summaryrefslogtreecommitdiffstats
path: root/connectivity/source
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
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')
-rw-r--r--connectivity/source/commontools/AutoRetrievingBase.cxx52
-rw-r--r--connectivity/source/commontools/BlobHelper.cxx71
-rw-r--r--connectivity/source/commontools/CommonTools.cxx235
-rw-r--r--connectivity/source/commontools/ConnectionWrapper.cxx238
-rw-r--r--connectivity/source/commontools/DateConversion.cxx526
-rw-r--r--connectivity/source/commontools/DriversConfig.cxx248
-rw-r--r--connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx851
-rw-r--r--connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx357
-rw-r--r--connectivity/source/commontools/FValue.cxx2473
-rw-r--r--connectivity/source/commontools/ParameterSubstitution.cxx105
-rw-r--r--connectivity/source/commontools/RowFunctionParser.cxx441
-rw-r--r--connectivity/source/commontools/TColumnsHelper.cxx208
-rw-r--r--connectivity/source/commontools/TConnection.cxx85
-rw-r--r--connectivity/source/commontools/TDatabaseMetaDataBase.cxx325
-rw-r--r--connectivity/source/commontools/TIndex.cxx100
-rw-r--r--connectivity/source/commontools/TIndexColumns.cxx114
-rw-r--r--connectivity/source/commontools/TIndexes.cxx247
-rw-r--r--connectivity/source/commontools/TKey.cxx107
-rw-r--r--connectivity/source/commontools/TKeyColumns.cxx132
-rw-r--r--connectivity/source/commontools/TKeys.cxx309
-rw-r--r--connectivity/source/commontools/TPrivilegesResultSet.cxx140
-rw-r--r--connectivity/source/commontools/TSkipDeletedSet.cxx255
-rw-r--r--connectivity/source/commontools/TSortIndex.cxx152
-rw-r--r--connectivity/source/commontools/TTableHelper.cxx610
-rw-r--r--connectivity/source/commontools/conncleanup.cxx230
-rw-r--r--connectivity/source/commontools/dbcharset.cxx190
-rw-r--r--connectivity/source/commontools/dbconversion.cxx463
-rw-r--r--connectivity/source/commontools/dbexception.cxx495
-rw-r--r--connectivity/source/commontools/dbmetadata.cxx443
-rw-r--r--connectivity/source/commontools/dbtools.cxx2073
-rw-r--r--connectivity/source/commontools/dbtools2.cxx1018
-rw-r--r--connectivity/source/commontools/filtermanager.cxx254
-rw-r--r--connectivity/source/commontools/formattedcolumnvalue.cxx289
-rw-r--r--connectivity/source/commontools/parameters.cxx1216
-rw-r--r--connectivity/source/commontools/paramwrapper.cxx354
-rw-r--r--connectivity/source/commontools/predicateinput.cxx421
-rw-r--r--connectivity/source/commontools/propertyids.cxx103
-rw-r--r--connectivity/source/commontools/sqlerror.cxx295
-rw-r--r--connectivity/source/commontools/statementcomposer.cxx301
-rw-r--r--connectivity/source/commontools/warningscontainer.cxx110
-rw-r--r--connectivity/source/cpool/ZConnectionPool.cxx301
-rw-r--r--connectivity/source/cpool/ZConnectionPool.hxx146
-rw-r--r--connectivity/source/cpool/ZConnectionWrapper.cxx241
-rw-r--r--connectivity/source/cpool/ZConnectionWrapper.hxx77
-rw-r--r--connectivity/source/cpool/ZDriverWrapper.cxx114
-rw-r--r--connectivity/source/cpool/ZDriverWrapper.hxx73
-rw-r--r--connectivity/source/cpool/ZPoolCollection.cxx468
-rw-r--r--connectivity/source/cpool/ZPoolCollection.hxx133
-rw-r--r--connectivity/source/cpool/ZPooledConnection.cxx72
-rw-r--r--connectivity/source/cpool/ZPooledConnection.hxx58
-rw-r--r--connectivity/source/cpool/dbpool2.component26
-rw-r--r--connectivity/source/dbtools/dbtools.component30
-rw-r--r--connectivity/source/drivers/ado/ACallableStatement.cxx253
-rw-r--r--connectivity/source/drivers/ado/ACatalog.cxx115
-rw-r--r--connectivity/source/drivers/ado/AColumn.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
-rw-r--r--connectivity/source/inc/AutoRetrievingBase.hxx50
-rw-r--r--connectivity/source/inc/FDatabaseMetaDataResultSet.hxx270
-rw-r--r--connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx96
-rw-r--r--connectivity/source/inc/OColumn.hxx118
-rw-r--r--connectivity/source/inc/OTypeInfo.hxx50
-rw-r--r--connectivity/source/inc/ParameterSubstitution.hxx63
-rw-r--r--connectivity/source/inc/RowFunctionParser.hxx109
-rw-r--r--connectivity/source/inc/TConnection.hxx81
-rw-r--r--connectivity/source/inc/TDatabaseMetaDataBase.hxx133
-rw-r--r--connectivity/source/inc/TKeyValue.hxx59
-rw-r--r--connectivity/source/inc/TPrivilegesResultSet.hxx46
-rw-r--r--connectivity/source/inc/TResultSetHelper.hxx51
-rw-r--r--connectivity/source/inc/TSkipDeletedSet.hxx80
-rw-r--r--connectivity/source/inc/TSortIndex.hxx110
-rw-r--r--connectivity/source/inc/ado/ACallableStatement.hxx76
-rw-r--r--connectivity/source/inc/ado/ACatalog.hxx49
-rw-r--r--connectivity/source/inc/ado/AColumn.hxx55
-rw-r--r--connectivity/source/inc/ado/AColumns.hxx56
-rw-r--r--connectivity/source/inc/ado/AConnection.hxx134
-rw-r--r--connectivity/source/inc/ado/ADatabaseMetaData.hxx221
-rw-r--r--connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx225
-rw-r--r--connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx102
-rw-r--r--connectivity/source/inc/ado/ADriver.hxx80
-rw-r--r--connectivity/source/inc/ado/AGroup.hxx62
-rw-r--r--connectivity/source/inc/ado/AGroups.hxx51
-rw-r--r--connectivity/source/inc/ado/AIndex.hxx49
-rw-r--r--connectivity/source/inc/ado/AIndexes.hxx53
-rw-r--r--connectivity/source/inc/ado/AKey.hxx59
-rw-r--r--connectivity/source/inc/ado/AKeys.hxx53
-rw-r--r--connectivity/source/inc/ado/APreparedStatement.hxx113
-rw-r--r--connectivity/source/inc/ado/AResultSet.hxx234
-rw-r--r--connectivity/source/inc/ado/AResultSetMetaData.hxx79
-rw-r--r--connectivity/source/inc/ado/AStatement.hxx217
-rw-r--r--connectivity/source/inc/ado/ATable.hxx72
-rw-r--r--connectivity/source/inc/ado/ATables.hxx52
-rw-r--r--connectivity/source/inc/ado/AUser.hxx86
-rw-r--r--connectivity/source/inc/ado/AUsers.hxx53
-rw-r--r--connectivity/source/inc/ado/AView.hxx51
-rw-r--r--connectivity/source/inc/ado/AViews.hxx51
-rw-r--r--connectivity/source/inc/ado/Aolevariant.hxx123
-rw-r--r--connectivity/source/inc/ado/Aolewrap.hxx174
-rw-r--r--connectivity/source/inc/ado/Awrapado.hxx372
-rw-r--r--connectivity/source/inc/ado/Awrapadox.hxx139
-rw-r--r--connectivity/source/inc/ado/WrapCatalog.hxx50
-rw-r--r--connectivity/source/inc/ado/WrapColumn.hxx62
-rw-r--r--connectivity/source/inc/ado/WrapIndex.hxx52
-rw-r--r--connectivity/source/inc/ado/WrapKey.hxx54
-rw-r--r--connectivity/source/inc/ado/WrapTable.hxx57
-rw-r--r--connectivity/source/inc/ado/WrapTypeDefs.hxx41
-rw-r--r--connectivity/source/inc/ado/adoimp.hxx103
-rw-r--r--connectivity/source/inc/calc/CCatalog.hxx38
-rw-r--r--connectivity/source/inc/calc/CConnection.hxx149
-rw-r--r--connectivity/source/inc/calc/CDatabaseMetaData.hxx42
-rw-r--r--connectivity/source/inc/calc/CDriver.hxx51
-rw-r--r--connectivity/source/inc/calc/CTable.hxx76
-rw-r--r--connectivity/source/inc/calc/CTables.hxx40
-rw-r--r--connectivity/source/inc/component/CColumns.hxx42
-rw-r--r--connectivity/source/inc/component/CDatabaseMetaData.hxx47
-rw-r--r--connectivity/source/inc/component/CPreparedStatement.hxx39
-rw-r--r--connectivity/source/inc/component/CResultSet.hxx79
-rw-r--r--connectivity/source/inc/component/CStatement.hxx39
-rw-r--r--connectivity/source/inc/component/CTable.hxx66
-rw-r--r--connectivity/source/inc/dbase/DCatalog.hxx38
-rw-r--r--connectivity/source/inc/dbase/DColumns.hxx43
-rw-r--r--connectivity/source/inc/dbase/DConnection.hxx46
-rw-r--r--connectivity/source/inc/dbase/DDatabaseMetaData.hxx57
-rw-r--r--connectivity/source/inc/dbase/DDriver.hxx46
-rw-r--r--connectivity/source/inc/dbase/DIndex.hxx139
-rw-r--r--connectivity/source/inc/dbase/DIndexColumns.hxx49
-rw-r--r--connectivity/source/inc/dbase/DIndexIter.hxx67
-rw-r--r--connectivity/source/inc/dbase/DIndexes.hxx50
-rw-r--r--connectivity/source/inc/dbase/DPreparedStatement.hxx38
-rw-r--r--connectivity/source/inc/dbase/DResultSet.hxx78
-rw-r--r--connectivity/source/inc/dbase/DStatement.hxx38
-rw-r--r--connectivity/source/inc/dbase/DTable.hxx194
-rw-r--r--connectivity/source/inc/dbase/DTables.hxx46
-rw-r--r--connectivity/source/inc/dbase/dindexnode.hxx307
-rw-r--r--connectivity/source/inc/file/FCatalog.hxx60
-rw-r--r--connectivity/source/inc/file/FColumns.hxx47
-rw-r--r--connectivity/source/inc/file/FConnection.hxx131
-rw-r--r--connectivity/source/inc/file/FDatabaseMetaData.hxx186
-rw-r--r--connectivity/source/inc/file/FDateFunctions.hxx228
-rw-r--r--connectivity/source/inc/file/FDriver.hxx72
-rw-r--r--connectivity/source/inc/file/FNumericFunctions.hxx362
-rw-r--r--connectivity/source/inc/file/FPreparedStatement.hxx121
-rw-r--r--connectivity/source/inc/file/FResultSet.hxx305
-rw-r--r--connectivity/source/inc/file/FResultSetMetaData.hxx77
-rw-r--r--connectivity/source/inc/file/FStatement.hxx196
-rw-r--r--connectivity/source/inc/file/FStringFunctions.hxx269
-rw-r--r--connectivity/source/inc/file/FTable.hxx103
-rw-r--r--connectivity/source/inc/file/FTables.hxx44
-rw-r--r--connectivity/source/inc/file/fanalyzer.hxx70
-rw-r--r--connectivity/source/inc/file/fcode.hxx330
-rw-r--r--connectivity/source/inc/file/fcomp.hxx110
-rw-r--r--connectivity/source/inc/file/filedllapi.hxx32
-rw-r--r--connectivity/source/inc/file/quotedstring.hxx46
-rw-r--r--connectivity/source/inc/flat/ECatalog.hxx38
-rw-r--r--connectivity/source/inc/flat/EColumns.hxx41
-rw-r--r--connectivity/source/inc/flat/EConnection.hxx62
-rw-r--r--connectivity/source/inc/flat/EDatabaseMetaData.hxx44
-rw-r--r--connectivity/source/inc/flat/EDriver.hxx45
-rw-r--r--connectivity/source/inc/flat/EPreparedStatement.hxx38
-rw-r--r--connectivity/source/inc/flat/EResultSet.hxx70
-rw-r--r--connectivity/source/inc/flat/EStatement.hxx38
-rw-r--r--connectivity/source/inc/flat/ETable.hxx104
-rw-r--r--connectivity/source/inc/flat/ETables.hxx40
-rw-r--r--connectivity/source/inc/hsqldb/HCatalog.hxx60
-rw-r--r--connectivity/source/inc/hsqldb/HColumns.hxx56
-rw-r--r--connectivity/source/inc/hsqldb/HConnection.hxx142
-rw-r--r--connectivity/source/inc/hsqldb/HDriver.hxx123
-rw-r--r--connectivity/source/inc/hsqldb/HStorageAccess.hxx43
-rw-r--r--connectivity/source/inc/hsqldb/HStorageMap.hxx97
-rw-r--r--connectivity/source/inc/hsqldb/HTable.hxx115
-rw-r--r--connectivity/source/inc/hsqldb/HTables.hxx52
-rw-r--r--connectivity/source/inc/hsqldb/HTools.hxx49
-rw-r--r--connectivity/source/inc/hsqldb/HUser.hxx73
-rw-r--r--connectivity/source/inc/hsqldb/HUsers.hxx52
-rw-r--r--connectivity/source/inc/hsqldb/HView.hxx88
-rw-r--r--connectivity/source/inc/hsqldb/HViews.hxx51
-rw-r--r--connectivity/source/inc/java/ContextClassLoader.hxx79
-rw-r--r--connectivity/source/inc/java/GlobalRef.hxx102
-rw-r--r--connectivity/source/inc/java/LocalRef.hxx95
-rw-r--r--connectivity/source/inc/java/io/InputStream.hxx51
-rw-r--r--connectivity/source/inc/java/io/Reader.hxx52
-rw-r--r--connectivity/source/inc/java/lang/Boolean.hxx43
-rw-r--r--connectivity/source/inc/java/lang/Class.hxx49
-rw-r--r--connectivity/source/inc/java/lang/Exception.hxx42
-rw-r--r--connectivity/source/inc/java/lang/Object.hxx147
-rw-r--r--connectivity/source/inc/java/lang/String.hxx43
-rw-r--r--connectivity/source/inc/java/lang/Throwable.hxx49
-rw-r--r--connectivity/source/inc/java/math/BigDecimal.hxx41
-rw-r--r--connectivity/source/inc/java/sql/Array.hxx54
-rw-r--r--connectivity/source/inc/java/sql/Blob.hxx54
-rw-r--r--connectivity/source/inc/java/sql/CallableStatement.hxx82
-rw-r--r--connectivity/source/inc/java/sql/Clob.hxx54
-rw-r--r--connectivity/source/inc/java/sql/Connection.hxx135
-rw-r--r--connectivity/source/inc/java/sql/ConnectionLog.hxx127
-rw-r--r--connectivity/source/inc/java/sql/DatabaseMetaData.hxx216
-rw-r--r--connectivity/source/inc/java/sql/Driver.hxx59
-rw-r--r--connectivity/source/inc/java/sql/DriverPropertyInfo.hxx42
-rw-r--r--connectivity/source/inc/java/sql/JStatement.hxx234
-rw-r--r--connectivity/source/inc/java/sql/PreparedStatement.hxx103
-rw-r--r--connectivity/source/inc/java/sql/Ref.hxx49
-rw-r--r--connectivity/source/inc/java/sql/ResultSet.hxx210
-rw-r--r--connectivity/source/inc/java/sql/ResultSetMetaData.hxx70
-rw-r--r--connectivity/source/inc/java/sql/SQLException.hxx56
-rw-r--r--connectivity/source/inc/java/sql/SQLWarning.hxx49
-rw-r--r--connectivity/source/inc/java/sql/Timestamp.hxx88
-rw-r--r--connectivity/source/inc/java/tools.hxx66
-rw-r--r--connectivity/source/inc/java/util/Date.hxx45
-rw-r--r--connectivity/source/inc/java/util/Property.hxx38
-rw-r--r--connectivity/source/inc/mysql/YCatalog.hxx60
-rw-r--r--connectivity/source/inc/mysql/YColumns.hxx56
-rw-r--r--connectivity/source/inc/mysql/YDriver.hxx106
-rw-r--r--connectivity/source/inc/mysql/YTable.hxx115
-rw-r--r--connectivity/source/inc/mysql/YTables.hxx62
-rw-r--r--connectivity/source/inc/mysql/YUser.hxx73
-rw-r--r--connectivity/source/inc/mysql/YUsers.hxx52
-rw-r--r--connectivity/source/inc/mysql/YViews.hxx51
-rw-r--r--connectivity/source/inc/odbc/OBoundParam.hxx128
-rw-r--r--connectivity/source/inc/odbc/OConnection.hxx126
-rw-r--r--connectivity/source/inc/odbc/ODatabaseMetaData.hxx203
-rw-r--r--connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx259
-rw-r--r--connectivity/source/inc/odbc/ODriver.hxx77
-rw-r--r--connectivity/source/inc/odbc/OFunctions.hxx600
-rw-r--r--connectivity/source/inc/odbc/OPreparedStatement.hxx149
-rw-r--r--connectivity/source/inc/odbc/OResultSet.hxx354
-rw-r--r--connectivity/source/inc/odbc/OResultSetMetaData.hxx116
-rw-r--r--connectivity/source/inc/odbc/OStatement.hxx244
-rw-r--r--connectivity/source/inc/odbc/OTools.hxx245
-rw-r--r--connectivity/source/inc/odbc/odbcbasedllapi.hxx32
-rw-r--r--connectivity/source/inc/propertyids.hxx109
-rw-r--r--connectivity/source/inc/resource/sharedresources.hxx149
-rw-r--r--connectivity/source/inc/writer/WCatalog.hxx37
-rw-r--r--connectivity/source/inc/writer/WConnection.hxx154
-rw-r--r--connectivity/source/inc/writer/WDatabaseMetaData.hxx43
-rw-r--r--connectivity/source/inc/writer/WDriver.hxx52
-rw-r--r--connectivity/source/inc/writer/WTable.hxx66
-rw-r--r--connectivity/source/inc/writer/WTables.hxx43
-rw-r--r--connectivity/source/manager/mdrivermanager.cxx665
-rw-r--r--connectivity/source/manager/mdrivermanager.hxx121
-rw-r--r--connectivity/source/manager/sdbc2.component26
-rw-r--r--connectivity/source/parse/PColumn.cxx271
-rw-r--r--connectivity/source/parse/internalnode.cxx64
-rw-r--r--connectivity/source/parse/sqlbison.y4835
-rw-r--r--connectivity/source/parse/sqlflex.l808
-rw-r--r--connectivity/source/parse/sqliterator.cxx2117
-rw-r--r--connectivity/source/parse/sqlnode.cxx2789
-rw-r--r--connectivity/source/resource/sharedresources.cxx191
-rw-r--r--connectivity/source/sdbcx/VCatalog.cxx211
-rw-r--r--connectivity/source/sdbcx/VCollection.cxx582
-rw-r--r--connectivity/source/sdbcx/VColumn.cxx219
-rw-r--r--connectivity/source/sdbcx/VDescriptor.cxx126
-rw-r--r--connectivity/source/sdbcx/VGroup.cxx166
-rw-r--r--connectivity/source/sdbcx/VIndex.cxx199
-rw-r--r--connectivity/source/sdbcx/VIndexColumn.cxx102
-rw-r--r--connectivity/source/sdbcx/VKey.cxx202
-rw-r--r--connectivity/source/sdbcx/VKeyColumn.cxx106
-rw-r--r--connectivity/source/sdbcx/VTable.cxx304
-rw-r--r--connectivity/source/sdbcx/VUser.cxx180
-rw-r--r--connectivity/source/sdbcx/VView.cxx132
652 files changed, 157563 insertions, 0 deletions
diff --git a/connectivity/source/commontools/AutoRetrievingBase.cxx b/connectivity/source/commontools/AutoRetrievingBase.cxx
new file mode 100644
index 000000000..99327f27e
--- /dev/null
+++ b/connectivity/source/commontools/AutoRetrievingBase.cxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AutoRetrievingBase.hxx>
+
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+namespace connectivity
+{
+ OUString OAutoRetrievingBase::getTransformedGeneratedStatement(const OUString& _sInsertStatement) const
+ {
+ OSL_ENSURE( m_bAutoRetrievingEnabled,"Illegal call here. isAutoRetrievingEnabled is false!");
+ OUString sStmt = _sInsertStatement.toAsciiUpperCase();
+ if ( sStmt.startsWith("INSERT") )
+ {
+ static const char sTable[] = "$table";
+ const sal_Int32 nColumnIndex {m_sGeneratedValueStatement.indexOf("$column")};
+ if ( nColumnIndex>=0 )
+ { // we need a column
+ }
+ const sal_Int32 nTableIndex {m_sGeneratedValueStatement.indexOf(sTable)};
+ if ( nTableIndex>=0 )
+ { // we need a table name
+ sal_Int32 nIntoIndex = sStmt.indexOf("INTO ") + 5;
+ while (nIntoIndex<sStmt.getLength() && sStmt[nIntoIndex]==' ') ++nIntoIndex;
+ const std::u16string_view sTableName = o3tl::getToken(sStmt, 0, ' ', nIntoIndex);
+ return m_sGeneratedValueStatement.replaceAt(nTableIndex, strlen(sTable), sTableName);
+ }
+ return m_sGeneratedValueStatement;
+ }
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/BlobHelper.cxx b/connectivity/source/commontools/BlobHelper.cxx
new file mode 100644
index 000000000..591fe961e
--- /dev/null
+++ b/connectivity/source/commontools/BlobHelper.cxx
@@ -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 .
+ */
+#include <connectivity/BlobHelper.hxx>
+#include <comphelper/seqstream.hxx>
+#include <connectivity/dbexception.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using namespace connectivity;
+using namespace dbtools;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+BlobHelper::BlobHelper(const css::uno::Sequence< sal_Int8 >& _val) : m_aValue(_val)
+{
+}
+
+::sal_Int64 SAL_CALL BlobHelper::length( )
+{
+ return m_aValue.getLength();
+}
+
+css::uno::Sequence< ::sal_Int8 > SAL_CALL BlobHelper::getBytes( ::sal_Int64 pos, ::sal_Int32 _length )
+{
+ if ( sal_Int32(pos + _length) > m_aValue.getLength() )
+ throw css::sdbc::SQLException();
+ return css::uno::Sequence< ::sal_Int8 >(m_aValue.getConstArray() + sal_Int32(pos),_length);
+}
+
+css::uno::Reference< css::io::XInputStream > SAL_CALL BlobHelper::getBinaryStream( )
+{
+ return new ::comphelper::SequenceInputStream(m_aValue);
+}
+
+
+// The "return" after a call to throwFeatureNotImplementedSQLException()
+// (which always throws) will be detected as unreachable when doing
+// global inlining.
+
+SAL_WNOUNREACHABLE_CODE_PUSH
+
+::sal_Int64 SAL_CALL BlobHelper::position( const css::uno::Sequence< ::sal_Int8 >& /*pattern*/, ::sal_Int64 /*start*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::position", *this );
+ return 0;
+}
+
+::sal_Int64 SAL_CALL BlobHelper::positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& /*pattern*/, ::sal_Int64 /*start*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::positionOfBlob", *this );
+ return 0;
+}
+
+SAL_WNOUNREACHABLE_CODE_POP
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/CommonTools.cxx b/connectivity/source/commontools/CommonTools.cxx
new file mode 100644
index 000000000..739fe6e66
--- /dev/null
+++ b/connectivity/source/commontools/CommonTools.cxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_java.h>
+
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/java/JavaVirtualMachine.hpp>
+#if HAVE_FEATURE_JAVA
+#include <jvmaccess/virtualmachine.hxx>
+#endif
+#include <osl/diagnose.h>
+#include <rtl/character.hxx>
+#include <rtl/process.h>
+#include <tools/diagnose_ex.h>
+
+using namespace ::comphelper;
+static sal_Unicode rtl_ascii_toUpperCase( sal_Unicode ch )
+{
+ return ch >= 0x0061 && ch <= 0x007a ? ch + 0x20 : ch;
+}
+
+namespace connectivity
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::java;
+ using namespace dbtools;
+
+ const sal_Unicode CHAR_PLACE = '_';
+ const sal_Unicode CHAR_WILD = '%';
+
+ bool match(const sal_Unicode* pWild, const sal_Unicode* pStr, const sal_Unicode cEscape)
+ {
+ int pos=0;
+ int flag=0;
+
+ while ( *pWild || flag )
+ {
+ switch (*pWild)
+ {
+ case CHAR_PLACE:
+ if ( *pStr == 0 )
+ return false;
+ break;
+ default:
+ if (*pWild && (*pWild == cEscape) && ((*(pWild+1)== CHAR_PLACE) || (*(pWild+1) == CHAR_WILD)) )
+ pWild++;
+ if ( rtl_ascii_toUpperCase(*pWild) != rtl_ascii_toUpperCase(*pStr) )
+ if ( !pos )
+ return false;
+ else
+ pWild += pos;
+ else
+ break;
+ // WARNING/TODO: in certain circumstances it will run into
+ // the next 'case'!
+ [[fallthrough]];
+ case CHAR_WILD:
+ while ( *pWild == CHAR_WILD )
+ pWild++;
+ if ( *pWild == 0 )
+ return true;
+ flag = 1;
+ pos = 0;
+ if ( *pStr == 0 )
+ return ( *pWild == 0 );
+ while ( *pStr && *pStr != *pWild )
+ {
+ if ( *pWild == CHAR_PLACE ) {
+ pWild++;
+ while ( *pWild == CHAR_WILD )
+ pWild++;
+ }
+ pStr++;
+ if ( *pStr == 0 )
+ return ( *pWild == 0 );
+ }
+ break;
+ }
+ if ( *pWild != 0 )
+ pWild++;
+ if ( *pStr != 0 )
+ pStr++;
+ else
+ flag = 0;
+ if ( flag )
+ pos--;
+ }
+ return ( *pStr == 0 ) && ( *pWild == 0 );
+ }
+
+#if HAVE_FEATURE_JAVA
+ ::rtl::Reference< jvmaccess::VirtualMachine > getJavaVM(const Reference<XComponentContext >& _rxContext)
+ {
+ ::rtl::Reference< jvmaccess::VirtualMachine > aRet;
+ OSL_ENSURE(_rxContext.is(),"No XMultiServiceFactory a.v.!");
+ if(!_rxContext.is())
+ return aRet;
+
+ try
+ {
+ Reference< XJavaVM > xVM = JavaVirtualMachine::create(_rxContext);
+
+ Sequence<sal_Int8> processID(17); // 16 + 1
+ auto pprocessID = processID.getArray();
+ rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(pprocessID) );
+ pprocessID[16] = 0; // RETURN_VIRTUALMACHINE
+
+ Any uaJVM = xVM->getJavaVM( processID );
+ sal_Int64 nTemp;
+ if (!(uaJVM >>= nTemp)) {
+ throw Exception("cannot get result for getJavaVM", nullptr); // -5
+ }
+ aRet = reinterpret_cast<jvmaccess::VirtualMachine *>(
+ static_cast<sal_IntPtr>(nTemp));
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.commontools", "getJavaVM failed:");
+ }
+
+ return aRet;
+ }
+
+ bool existsJavaClassByName( const ::rtl::Reference< jvmaccess::VirtualMachine >& _pJVM,std::u16string_view _sClassName )
+ {
+ bool bRet = false;
+ if ( _pJVM.is() )
+ {
+ jvmaccess::VirtualMachine::AttachGuard aGuard(_pJVM);
+ JNIEnv* pEnv = aGuard.getEnvironment();
+ if( pEnv )
+ {
+ OString sClassName = OUStringToOString(_sClassName, RTL_TEXTENCODING_ASCII_US);
+ sClassName = sClassName.replace('.','/');
+ jobject out = pEnv->FindClass(sClassName.getStr());
+ bRet = out != nullptr;
+ pEnv->DeleteLocalRef( out );
+ }
+ }
+ return bRet;
+ }
+#endif
+}
+
+namespace dbtools
+{
+
+static bool isCharOk(sal_Unicode c, std::u16string_view _rSpecials)
+{
+
+ return ( ((c >= 97) && (c <= 122)) || ((c >= 65) && (c <= 90)) || ((c >= 48) && (c <= 57)) ||
+ c == '_' || _rSpecials.find(c) != std::u16string_view::npos);
+}
+
+
+bool isValidSQLName(const OUString& rName, std::u16string_view _rSpecials)
+{
+ // Test for correct naming (in SQL sense)
+ // This is important for table names for example
+ const sal_Unicode* pStr = rName.getStr();
+ if (*pStr > 127 || rtl::isAsciiDigit(*pStr))
+ return false;
+
+ for (; *pStr; ++pStr )
+ if(!isCharOk(*pStr,_rSpecials))
+ return false;
+
+ if ( !rName.isEmpty()
+ && ( (rName.toChar() == '_')
+ || ( (rName.toChar() >= '0')
+ && (rName.toChar() <= '9')
+ )
+ )
+ )
+ return false;
+ // the SQL-Standard requires the first character to be an alphabetic character, which
+ // isn't easy to decide in UniCode...
+ // So we just prohibit the characters which already lead to problems...
+ // 11.04.00 - 74902 - FS
+
+ return true;
+}
+
+// Creates a new name if necessary
+OUString convertName2SQLName(const OUString& rName, std::u16string_view _rSpecials)
+{
+ if(isValidSQLName(rName,_rSpecials))
+ return rName;
+
+ const sal_Unicode* pStr = rName.getStr();
+ // if not valid
+ if (*pStr >= 128 || rtl::isAsciiDigit(*pStr))
+ return OUString();
+
+ OUStringBuffer aNewName(rName);
+ sal_Int32 nLength = rName.getLength();
+ for (sal_Int32 i=0; i < nLength; ++i)
+ if(!isCharOk(aNewName[i],_rSpecials))
+ aNewName[i] = '_';
+
+ return aNewName.makeStringAndClear();
+}
+
+OUString quoteName(const OUString& _rQuote, const OUString& _rName)
+{
+ OUString sName = _rName;
+ if( !_rQuote.isEmpty() && _rQuote.toChar() != ' ')
+ sName = _rQuote + _rName + _rQuote;
+ return sName;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/ConnectionWrapper.cxx b/connectivity/source/commontools/ConnectionWrapper.cxx
new file mode 100644
index 000000000..df5ef04ee
--- /dev/null
+++ b/connectivity/source/commontools/ConnectionWrapper.cxx
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/ConnectionWrapper.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/uno3.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/hash.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <algorithm>
+
+using namespace connectivity;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace ::com::sun::star::reflection;
+
+OConnectionWrapper::OConnectionWrapper()
+{
+
+}
+
+void OConnectionWrapper::setDelegation(Reference< XAggregation >& _rxProxyConnection,oslInterlockedCount& _rRefCount)
+{
+ OSL_ENSURE(_rxProxyConnection.is(),"OConnectionWrapper: Connection must be valid!");
+ osl_atomic_increment( &_rRefCount );
+ if (_rxProxyConnection.is())
+ {
+ // transfer the (one and only) real ref to the aggregate to our member
+ m_xProxyConnection = _rxProxyConnection;
+ _rxProxyConnection = nullptr;
+ ::comphelper::query_aggregation(m_xProxyConnection,m_xConnection);
+ m_xTypeProvider.set(m_xConnection,UNO_QUERY);
+ m_xUnoTunnel.set(m_xConnection,UNO_QUERY);
+ m_xServiceInfo.set(m_xConnection,UNO_QUERY);
+
+ // set ourself as delegator
+ Reference<XInterface> xIf = static_cast< XUnoTunnel* >( this );
+ m_xProxyConnection->setDelegator( xIf );
+
+ }
+ osl_atomic_decrement( &_rRefCount );
+}
+
+void OConnectionWrapper::setDelegation(const Reference< XConnection >& _xConnection
+ ,const Reference< XComponentContext>& _rxContext
+ ,oslInterlockedCount& _rRefCount)
+{
+ OSL_ENSURE(_xConnection.is(),"OConnectionWrapper: Connection must be valid!");
+ osl_atomic_increment( &_rRefCount );
+
+ m_xConnection = _xConnection;
+ m_xTypeProvider.set(m_xConnection,UNO_QUERY);
+ m_xUnoTunnel.set(m_xConnection,UNO_QUERY);
+ m_xServiceInfo.set(m_xConnection,UNO_QUERY);
+
+ Reference< XProxyFactory > xProxyFactory = ProxyFactory::create( _rxContext );
+ Reference< XAggregation > xConProxy = xProxyFactory->createProxy(_xConnection);
+ if (xConProxy.is())
+ {
+ // transfer the (one and only) real ref to the aggregate to our member
+ m_xProxyConnection = xConProxy;
+
+ // set ourself as delegator
+ Reference<XInterface> xIf = static_cast< XUnoTunnel* >( this );
+ m_xProxyConnection->setDelegator( xIf );
+
+ }
+ osl_atomic_decrement( &_rRefCount );
+}
+
+void OConnectionWrapper::disposing()
+{
+m_xConnection.clear();
+}
+
+OConnectionWrapper::~OConnectionWrapper()
+{
+ if (m_xProxyConnection.is())
+ m_xProxyConnection->setDelegator(nullptr);
+}
+
+// XServiceInfo
+
+OUString SAL_CALL OConnectionWrapper::getImplementationName( )
+{
+ return "com.sun.star.sdbc.drivers.OConnectionWrapper";
+}
+
+
+css::uno::Sequence< OUString > SAL_CALL OConnectionWrapper::getSupportedServiceNames( )
+{
+ // first collect the services which are supported by our aggregate
+ Sequence< OUString > aSupported;
+ if ( m_xServiceInfo.is() )
+ aSupported = m_xServiceInfo->getSupportedServiceNames();
+
+ // append our own service, if necessary
+ OUString sConnectionService( "com.sun.star.sdbc.Connection" );
+ if ( ::comphelper::findValue( aSupported, sConnectionService ) == -1 )
+ {
+ sal_Int32 nLen = aSupported.getLength();
+ aSupported.realloc( nLen + 1 );
+ aSupported.getArray()[ nLen ] = sConnectionService;
+ }
+
+ // outta here
+ return aSupported;
+}
+
+
+sal_Bool SAL_CALL OConnectionWrapper::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Any SAL_CALL OConnectionWrapper::queryInterface( const Type& _rType )
+{
+ Any aReturn = OConnection_BASE::queryInterface(_rType);
+ return aReturn.hasValue() ? aReturn : (m_xProxyConnection.is() ? m_xProxyConnection->queryAggregation(_rType) : aReturn);
+}
+
+Sequence< Type > SAL_CALL OConnectionWrapper::getTypes( )
+{
+ return ::comphelper::concatSequences(
+ OConnection_BASE::getTypes(),
+ m_xTypeProvider->getTypes()
+ );
+}
+
+// css::lang::XUnoTunnel
+sal_Int64 SAL_CALL OConnectionWrapper::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ if (comphelper::isUnoTunnelId<OConnectionWrapper>(rId))
+ return comphelper::getSomething_cast(this);
+
+ if(m_xUnoTunnel.is())
+ return m_xUnoTunnel->getSomething(rId);
+ return 0;
+}
+
+
+const Sequence< sal_Int8 > & OConnectionWrapper::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+namespace
+{
+ class TPropertyValueLessFunctor
+ {
+ public:
+ TPropertyValueLessFunctor()
+ {}
+ bool operator() (const css::beans::PropertyValue& lhs, const css::beans::PropertyValue& rhs) const
+ {
+ return lhs.Name.compareToIgnoreAsciiCase(rhs.Name) < 0;
+ }
+ };
+
+}
+
+
+// creates a unique id out of the url and sequence of properties
+void OConnectionWrapper::createUniqueId( const OUString& _rURL
+ ,Sequence< PropertyValue >& _rInfo
+ ,sal_uInt8* _pBuffer
+ ,const OUString& _rUserName
+ ,const OUString& _rPassword)
+{
+ // first we create the digest we want to have
+ ::comphelper::Hash sha1(::comphelper::HashType::SHA1);
+ sha1.update(reinterpret_cast<unsigned char const*>(_rURL.getStr()), _rURL.getLength() * sizeof(sal_Unicode));
+ if ( !_rUserName.isEmpty() )
+ sha1.update(reinterpret_cast<unsigned char const*>(_rUserName.getStr()), _rUserName.getLength() * sizeof(sal_Unicode));
+ if ( !_rPassword.isEmpty() )
+ sha1.update(reinterpret_cast<unsigned char const*>(_rPassword.getStr()), _rPassword.getLength() * sizeof(sal_Unicode));
+ // now we need to sort the properties
+ auto [begin, end] = asNonConstRange(_rInfo);
+ std::sort(begin,end,TPropertyValueLessFunctor());
+
+ for (PropertyValue const & prop : std::as_const(_rInfo))
+ {
+ // we only include strings an integer values
+ OUString sValue;
+ if ( prop.Value >>= sValue )
+ ;
+ else
+ {
+ sal_Int32 nValue = 0;
+ if ( prop.Value >>= nValue )
+ sValue = OUString::number(nValue);
+ else
+ {
+ Sequence< OUString> aSeq;
+ if ( prop.Value >>= aSeq )
+ {
+ for(OUString const & s : std::as_const(aSeq))
+ sha1.update(reinterpret_cast<unsigned char const*>(s.getStr()), s.getLength() * sizeof(sal_Unicode));
+ }
+ }
+ }
+ if ( !sValue.isEmpty() )
+ {
+ // we don't have to convert this into UTF8 because we don't store on a file system
+ sha1.update(reinterpret_cast<unsigned char const*>(sValue.getStr()), sValue.getLength() * sizeof(sal_Unicode));
+ }
+ }
+
+ std::vector<unsigned char> result(sha1.finalize());
+ std::copy(result.begin(), result.end(), _pBuffer);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/DateConversion.cxx b/connectivity/source/commontools/DateConversion.cxx
new file mode 100644
index 000000000..38f20af09
--- /dev/null
+++ b/connectivity/source/commontools/DateConversion.cxx
@@ -0,0 +1,526 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <comphelper/extract.hxx>
+#include <TConnection.hxx>
+#include <comphelper/numbers.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+
+using namespace ::connectivity;
+using namespace ::comphelper;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::dbtools;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::uno;
+
+OUString DBTypeConversion::toSQLString(sal_Int32 eType, const Any& _rVal,
+ const Reference< XTypeConverter >& _rxTypeConverter)
+{
+ OUStringBuffer aRet;
+ if (_rVal.hasValue())
+ {
+ try
+ {
+ switch (eType)
+ {
+ case DataType::INTEGER:
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_BOOLEAN)
+ {
+ if (::cppu::any2bool(_rVal))
+ aRet.append("1");
+ else
+ aRet.append("0");
+ }
+ else
+ {
+ OUString sTemp;
+ _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp;
+ aRet.append(sTemp);
+ }
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aRet.append("'");
+ {
+ OUString aTemp;
+ _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= aTemp;
+ sal_Int32 nIndex = sal_Int32(-2);
+ static const OUStringLiteral sQuot(u"\'");
+ do
+ {
+ nIndex += 2;
+ nIndex = aTemp.indexOf(sQuot,nIndex);
+ if(nIndex != -1)
+ aTemp = aTemp.replaceAt(nIndex,sQuot.getLength(), u"\'\'");
+ } while (nIndex != -1);
+
+ aRet.append(aTemp);
+ }
+ aRet.append("'");
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::BIGINT:
+ default:
+ {
+ OUString sTemp;
+ _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp;
+ aRet.append(sTemp);
+ }
+ break;
+ case DataType::TIMESTAMP:
+ {
+ DateTime aDateTime;
+ bool bOk = false;
+ if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE)
+ {
+ double nValue = 0.0;
+ _rVal >>= nValue;
+ aDateTime = DBTypeConversion::toDateTime(nValue);
+ bOk = true;
+ }
+ else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING)
+ {
+ OUString sValue;
+ _rVal >>= sValue;
+ aDateTime = DBTypeConversion::toDateTime(sValue);
+ bOk = true;
+ }
+ else
+ bOk = _rVal >>= aDateTime;
+
+ OSL_ENSURE( bOk, "DBTypeConversion::toSQLString: _rVal is not datetime!");
+ // check if this is really a timestamp or only a date
+ if ( bOk )
+ {
+ aRet.append("{ts '");
+ aRet.append(DBTypeConversion::toDateTimeString(aDateTime));
+ aRet.append("'}");
+ break;
+ }
+ break;
+ }
+ case DataType::DATE:
+ {
+ Date aDate;
+ bool bOk = false;
+ if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE)
+ {
+ double nValue = 0.0;
+ _rVal >>= nValue;
+ aDate = DBTypeConversion::toDate(nValue);
+ bOk = true;
+ }
+ else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING)
+ {
+ OUString sValue;
+ _rVal >>= sValue;
+ aDate = DBTypeConversion::toDate(sValue);
+ bOk = true;
+ }
+ else
+ bOk = _rVal >>= aDate;
+ OSL_ENSURE( bOk, "DBTypeConversion::toSQLString: _rVal is not date!");
+ aRet.append("{d '");
+ aRet.append(DBTypeConversion::toDateString(aDate));
+ aRet.append("'}");
+ } break;
+ case DataType::TIME:
+ {
+ css::util::Time aTime;
+ bool bOk = false;
+ if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE)
+ {
+ double nValue = 0.0;
+ _rVal >>= nValue;
+ aTime = DBTypeConversion::toTime(nValue);
+ bOk = true;
+ }
+ else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING)
+ {
+ OUString sValue;
+ _rVal >>= sValue;
+ aTime = DBTypeConversion::toTime(sValue);
+ bOk = true;
+ }
+ else
+ bOk = _rVal >>= aTime;
+ OSL_ENSURE( bOk,"DBTypeConversion::toSQLString: _rVal is not time!");
+ aRet.append("{t '");
+ aRet.append(DBTypeConversion::toTimeString(aTime));
+ aRet.append("'}");
+ } break;
+ }
+ }
+ catch ( const Exception& )
+ {
+ OSL_FAIL("TypeConversion Error");
+ }
+ }
+ else
+ aRet.append(" NULL ");
+ return aRet.makeStringAndClear();
+}
+
+Date DBTypeConversion::getNULLDate(const Reference< XNumberFormatsSupplier > &xSupplier)
+{
+ OSL_ENSURE(xSupplier.is(), "getNULLDate : the formatter doesn't implement a supplier !");
+ if (xSupplier.is())
+ {
+ try
+ {
+ // get the null date
+ Date aDate;
+ xSupplier->getNumberFormatSettings()->getPropertyValue("NullDate") >>= aDate;
+ return aDate;
+ }
+ catch ( const Exception& )
+ {
+ }
+ }
+
+ return getStandardDate();
+}
+
+void DBTypeConversion::setValue(const Reference<XColumnUpdate>& xVariant,
+ const Reference<XNumberFormatter>& xFormatter,
+ const Date& rNullDate,
+ const OUString& rString,
+ sal_Int32 nKey,
+ sal_Int16 nFieldType,
+ sal_Int16 nKeyType)
+{
+ if (!rString.isEmpty())
+ {
+ // Does the String need to be formatted?
+ sal_Int16 nTypeClass = nKeyType & ~NumberFormat::DEFINED;
+ bool bTextFormat = nTypeClass == NumberFormat::TEXT;
+ sal_Int32 nKeyToUse = bTextFormat ? 0 : nKey;
+ sal_Int16 nRealUsedTypeClass = nTypeClass;
+ // for a Text-Format the formatter needs some more freedom, otherwise
+ // convertStringToNumber will throw a NotNumericException
+ try
+ {
+ double fValue = xFormatter->convertStringToNumber(nKeyToUse, rString);
+ Reference< XNumberFormats > xFormats(xFormatter->getNumberFormatsSupplier()->getNumberFormats());
+ Reference< XNumberFormatTypes > xFormatTypes(xFormats, UNO_QUERY);
+ sal_Int32 nStandardKey(0);
+ if(xFormatTypes.is())
+ {
+ const Reference< XPropertySet > xFormatProps(xFormats->getByKey(nKeyToUse));
+ if (xFormatProps.is())
+ {
+ css::lang::Locale loc;
+ if (xFormatProps->getPropertyValue("Locale") >>= loc)
+ nStandardKey = xFormatTypes->getStandardIndex(loc);
+ else
+ {
+ assert(false);
+ }
+ }
+ else
+ {
+ SAL_WARN("connectivity.commontools", "no format by key " << nKeyToUse);
+ }
+ }
+ else
+ {
+ assert(false);
+ }
+ // Why use nStandardKey rather than nKeyToUse here? I'm not sure, but "it was always like that".
+ // Previously had hardcoded 0 instead of nStandardKey, which led to problems with dates
+ // because of differences M/D/Y vs D/M/Y. This at least fixes those problems, but possibly
+ // nKeyToUse is an even better choice than nStandardKey.
+ // OTOH, using nKeyToUse nullifies the special treatment for percent formats,
+ // leading to "5" (in a percent format) to be understood as "500%" instead of "5%".
+ sal_Int32 nRealUsedKey = xFormatter->detectNumberFormat(nStandardKey, rString);
+ if (nRealUsedKey != nKeyToUse)
+ nRealUsedTypeClass = getNumberFormatType(xFormatter, nRealUsedKey) & ~NumberFormat::DEFINED;
+
+ // and again a special treatment, this time for percent formats
+ if ((NumberFormat::NUMBER == nRealUsedTypeClass) && (NumberFormat::PERCENT == nTypeClass))
+ { // formatting should be "percent", but the String provides just a simple number -> adjust
+ OUString sExpanded = rString + "%";
+ fValue = xFormatter->convertStringToNumber(nKeyToUse, sExpanded);
+ }
+
+ switch (nRealUsedTypeClass)
+ {
+ case NumberFormat::DATE:
+ case NumberFormat::DATETIME:
+ case NumberFormat::TIME:
+ DBTypeConversion::setValue(xVariant,rNullDate,fValue,nRealUsedTypeClass);
+ break;
+ case NumberFormat::CURRENCY:
+ case NumberFormat::NUMBER:
+ case NumberFormat::SCIENTIFIC:
+ case NumberFormat::FRACTION:
+ case NumberFormat::PERCENT:
+ xVariant->updateDouble(fValue);
+ break;
+ default:
+ xVariant->updateString(rString);
+ }
+ }
+ catch(const Exception& )
+ {
+ xVariant->updateString(rString);
+ }
+ }
+ else
+ {
+ switch (nFieldType)
+ {
+ case css::sdbc::DataType::CHAR:
+ case css::sdbc::DataType::VARCHAR:
+ case css::sdbc::DataType::LONGVARCHAR:
+ xVariant->updateString(rString);
+ break;
+ default:
+ xVariant->updateNull();
+ }
+ }
+}
+
+
+void DBTypeConversion::setValue(const Reference<XColumnUpdate>& xVariant,
+ const Date& rNullDate,
+ const double& rValue,
+ sal_Int16 nKeyType)
+{
+ switch (nKeyType & ~NumberFormat::DEFINED)
+ {
+ case NumberFormat::DATE:
+ xVariant->updateDate(toDate( rValue, rNullDate));
+ break;
+ case NumberFormat::DATETIME:
+ xVariant->updateTimestamp(toDateTime(rValue,rNullDate));
+ break;
+ case NumberFormat::TIME:
+ xVariant->updateTime(toTime(rValue));
+ break;
+ default:
+ {
+ double nValue = rValue;
+// Reference<XPropertySet> xProp(xVariant,UNO_QUERY);
+// if ( xProp.is()
+// && xProp->getPropertySetInfo()->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSIGNED))
+// && !::comphelper::getBOOL(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSIGNED))) )
+// {
+// switch (::comphelper::getINT32(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))))
+// {
+// case DataType::TINYINT:
+// nValue = static_cast<sal_uInt8>(rValue);
+// break;
+// case DataType::SMALLINT:
+// nValue = static_cast<sal_uInt16>(rValue);
+// break;
+// case DataType::INTEGER:
+// nValue = static_cast<sal_uInt32>(rValue);
+// break;
+// case DataType::BIGINT:
+// nValue = static_cast<sal_uInt64>(rValue);
+// break;
+// }
+// }
+ xVariant->updateDouble(nValue);
+ }
+ }
+}
+
+
+double DBTypeConversion::getValue( const Reference< XColumn >& i_column, const Date& i_relativeToNullDate )
+{
+ try
+ {
+ const Reference< XPropertySet > xProp( i_column, UNO_QUERY_THROW );
+
+ const sal_Int32 nColumnType = ::comphelper::getINT32( xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE ) ) );
+ switch ( nColumnType )
+ {
+ case DataType::DATE:
+ return toDouble( i_column->getDate(), i_relativeToNullDate );
+
+ case DataType::TIME:
+ return toDouble( i_column->getTime() );
+
+ case DataType::TIMESTAMP:
+ return toDouble( i_column->getTimestamp(), i_relativeToNullDate );
+
+ default:
+ {
+ bool bIsSigned = true;
+ OSL_VERIFY( xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ISSIGNED ) ) >>= bIsSigned );
+ if ( !bIsSigned )
+ {
+ switch ( nColumnType)
+ {
+ case DataType::TINYINT:
+ return static_cast<double>(static_cast<sal_uInt8>(i_column->getByte()));
+ case DataType::SMALLINT:
+ return static_cast<double>(static_cast<sal_uInt16>(i_column->getShort()));
+ case DataType::INTEGER:
+ return static_cast<double>(static_cast<sal_uInt32>(i_column->getInt()));
+ case DataType::BIGINT:
+ return static_cast<double>(static_cast<sal_uInt64>(i_column->getLong()));
+ }
+ }
+ }
+ return i_column->getDouble();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ return 0.0;
+ }
+}
+
+OUString DBTypeConversion::getFormattedValue(const Reference< XPropertySet>& _xColumn,
+ const Reference<XNumberFormatter>& _xFormatter,
+ const css::lang::Locale& _rLocale,
+ const Date& _rNullDate)
+{
+ OSL_ENSURE(_xColumn.is() && _xFormatter.is(), "DBTypeConversion::getFormattedValue: invalid arg !");
+ if (!_xColumn.is() || !_xFormatter.is())
+ return OUString();
+
+ sal_Int32 nKey(0);
+ try
+ {
+ _xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) >>= nKey;
+ }
+ catch (const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "DBTypeConversion::getValue: caught an exception while asking for the format key!");
+ }
+
+ if (!nKey)
+ {
+ Reference<XNumberFormats> xFormats( _xFormatter->getNumberFormatsSupplier()->getNumberFormats() );
+
+ nKey = ::dbtools::getDefaultNumberFormat(_xColumn,
+ Reference< XNumberFormatTypes > (xFormats, UNO_QUERY),
+ _rLocale);
+
+ }
+
+ sal_Int16 nKeyType = getNumberFormatType(_xFormatter, nKey) & ~NumberFormat::DEFINED;
+
+ return DBTypeConversion::getFormattedValue(Reference< XColumn > (_xColumn, UNO_QUERY), _xFormatter, _rNullDate, nKey, nKeyType);
+}
+
+
+OUString DBTypeConversion::getFormattedValue(const Reference<XColumn>& xVariant,
+ const Reference<XNumberFormatter>& xFormatter,
+ const Date& rNullDate,
+ sal_Int32 nKey,
+ sal_Int16 nKeyType)
+{
+ OUString aString;
+ if (xVariant.is())
+ {
+ try
+ {
+ switch (nKeyType & ~NumberFormat::DEFINED)
+ {
+ case NumberFormat::DATE:
+ case NumberFormat::DATETIME:
+ {
+ // get a value which represents the given date, relative to the given null date
+ double fValue = getValue( xVariant, rNullDate );
+ if ( !xVariant->wasNull() )
+ {
+ // get the null date of the formatter
+ Date aFormatterNullDate( rNullDate );
+ try
+ {
+ Reference< XNumberFormatsSupplier > xSupplier( xFormatter->getNumberFormatsSupplier(), UNO_SET_THROW );
+ Reference< XPropertySet > xFormatterSettings( xSupplier->getNumberFormatSettings(), UNO_SET_THROW );
+ OSL_VERIFY( xFormatterSettings->getPropertyValue("NullDate") >>= aFormatterNullDate );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ // get a value which represents the given date, relative to the null date of the formatter
+ fValue -= toDays( rNullDate, aFormatterNullDate );
+ // format this value
+ aString = xFormatter->convertNumberToString( nKey, fValue );
+ }
+ }
+ break;
+ case NumberFormat::TIME:
+ case NumberFormat::NUMBER:
+ case NumberFormat::SCIENTIFIC:
+ case NumberFormat::FRACTION:
+ case NumberFormat::PERCENT:
+ {
+ double fValue = xVariant->getDouble();
+ if (!xVariant->wasNull())
+ aString = xFormatter->convertNumberToString(nKey, fValue);
+ } break;
+ case NumberFormat::CURRENCY:
+ {
+ double fValue = xVariant->getDouble();
+ if (!xVariant->wasNull())
+ aString = xFormatter->getInputString(nKey, fValue);
+ } break;
+ case NumberFormat::TEXT:
+ aString = xFormatter->formatString(nKey, xVariant->getString());
+ break;
+ default:
+ aString = xVariant->getString();
+ }
+ }
+ catch(const Exception& )
+ {
+ aString = xVariant->getString();
+ }
+ }
+ return aString;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/DriversConfig.cxx b/connectivity/source/commontools/DriversConfig.cxx
new file mode 100644
index 000000000..e1d492f9f
--- /dev/null
+++ b/connectivity/source/commontools/DriversConfig.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 <config_fuzzers.h>
+
+#include <connectivity/DriversConfig.hxx>
+#include <o3tl/string_view.hxx>
+#include <tools/wldcrd.hxx>
+#include <comphelper/sequence.hxx>
+
+using namespace connectivity;
+using namespace utl;
+using namespace ::com::sun::star;
+
+namespace
+{
+ void lcl_convert(const uno::Sequence< OUString >& _aSource,uno::Any& _rDest)
+ {
+ uno::Sequence<uno::Any> aRet(_aSource.getLength());
+ uno::Any* pAny = aRet.getArray();
+ const OUString* pIter = _aSource.getConstArray();
+ const OUString* pEnd = pIter + _aSource.getLength();
+ for (;pIter != pEnd ; ++pIter,++pAny)
+ {
+ *pAny <<= *pIter;
+ }
+ _rDest <<= aRet;
+ }
+ void lcl_fillValues(const ::utl::OConfigurationNode& _aURLPatternNode,const OUString& _sNode,::comphelper::NamedValueCollection& _rValues)
+ {
+ const ::utl::OConfigurationNode aPropertiesNode = _aURLPatternNode.openNode(_sNode);
+ if ( !aPropertiesNode.isValid() )
+ return;
+
+ uno::Sequence< OUString > aStringSeq;
+ const uno::Sequence< OUString > aProperties = aPropertiesNode.getNodeNames();
+ const OUString* pPropertiesIter = aProperties.getConstArray();
+ const OUString* pPropertiesEnd = pPropertiesIter + aProperties.getLength();
+ for (;pPropertiesIter != pPropertiesEnd ; ++pPropertiesIter)
+ {
+ uno::Any aValue = aPropertiesNode.getNodeValue(*pPropertiesIter + "/Value");
+ if ( aValue >>= aStringSeq )
+ {
+ lcl_convert(aStringSeq,aValue);
+ }
+ _rValues.put(*pPropertiesIter,aValue);
+ } // for (;pPropertiesIter != pPropertiesEnd ; ++pPropertiesIter,++pNamedIter)
+ }
+ void lcl_readURLPatternNode(const ::utl::OConfigurationTreeRoot& _aInstalled,const OUString& _sEntry,TInstalledDriver& _rInstalledDriver)
+ {
+ const ::utl::OConfigurationNode aURLPatternNode = _aInstalled.openNode(_sEntry);
+ if ( !aURLPatternNode.isValid() )
+ return;
+
+ OUString sParentURLPattern;
+ aURLPatternNode.getNodeValue("ParentURLPattern") >>= sParentURLPattern;
+ if ( !sParentURLPattern.isEmpty() )
+ lcl_readURLPatternNode(_aInstalled,sParentURLPattern,_rInstalledDriver);
+
+ OUString sDriverFactory;
+ aURLPatternNode.getNodeValue("Driver") >>= sDriverFactory;
+ if ( !sDriverFactory.isEmpty() )
+ _rInstalledDriver.sDriverFactory = sDriverFactory;
+
+ OUString sDriverTypeDisplayName;
+ aURLPatternNode.getNodeValue("DriverTypeDisplayName") >>= sDriverTypeDisplayName;
+ OSL_ENSURE(!sDriverTypeDisplayName.isEmpty(),"No valid DriverTypeDisplayName property!");
+ if ( !sDriverTypeDisplayName.isEmpty() )
+ _rInstalledDriver.sDriverTypeDisplayName = sDriverTypeDisplayName;
+
+ lcl_fillValues(aURLPatternNode,"Properties",_rInstalledDriver.aProperties);
+ lcl_fillValues(aURLPatternNode,"Features",_rInstalledDriver.aFeatures);
+ lcl_fillValues(aURLPatternNode,"MetaData",_rInstalledDriver.aMetaData);
+ }
+}
+
+DriversConfigImpl::DriversConfigImpl()
+{
+}
+
+const TInstalledDrivers& DriversConfigImpl::getInstalledDrivers(const uno::Reference< uno::XComponentContext >& _rxORB) const
+{
+ if ( m_aDrivers.empty() )
+ {
+ if ( !m_aInstalled.isValid() )
+ {
+ m_aInstalled = ::utl::OConfigurationTreeRoot::createWithComponentContext(_rxORB,
+ "org.openoffice.Office.DataAccess.Drivers/Installed", -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
+ }
+
+ if ( m_aInstalled.isValid() )
+ {
+ const uno::Sequence< OUString > aURLPatterns = m_aInstalled.getNodeNames();
+ const OUString* pPatternIter = aURLPatterns.getConstArray();
+ const OUString* pPatternEnd = pPatternIter + aURLPatterns.getLength();
+ for (;pPatternIter != pPatternEnd ; ++pPatternIter)
+ {
+ TInstalledDriver aInstalledDriver;
+ lcl_readURLPatternNode(m_aInstalled,*pPatternIter,aInstalledDriver);
+ if ( !aInstalledDriver.sDriverFactory.isEmpty() )
+ m_aDrivers.emplace(*pPatternIter,aInstalledDriver);
+ }
+ } // if ( m_aInstalled.isValid() )
+ }
+ return m_aDrivers;
+}
+
+DriversConfig::DriversConfig(const uno::Reference< uno::XComponentContext >& _rxORB)
+:m_xORB(_rxORB)
+{
+}
+
+
+DriversConfig::~DriversConfig()
+{
+}
+
+
+DriversConfig::DriversConfig( const DriversConfig& _rhs )
+{
+ *this = _rhs;
+}
+
+
+DriversConfig& DriversConfig::operator=( const DriversConfig& _rhs )
+{
+ if ( this != &_rhs )
+ {
+ m_aNode = _rhs.m_aNode;
+ }
+ return *this;
+}
+
+
+OUString DriversConfig::getDriverFactoryName(std::u16string_view _sURL) const
+{
+#if ENABLE_FUZZERS
+ if (o3tl::starts_with(_sURL, u"sdbc:dbase:"))
+ return "com.sun.star.comp.sdbc.dbase.ODriver";
+#endif
+
+ const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB);
+ OUString sRet;
+ OUString sOldPattern;
+ for(const auto& [rPattern, rDriver] : rDrivers)
+ {
+ WildCard aWildCard(rPattern);
+ if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) )
+ {
+ sRet = rDriver.sDriverFactory;
+ sOldPattern = rPattern;
+ }
+ }
+
+ return sRet;
+}
+
+OUString DriversConfig::getDriverTypeDisplayName(std::u16string_view _sURL) const
+{
+ const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB);
+ OUString sRet;
+ OUString sOldPattern;
+ for(const auto& [rPattern, rDriver] : rDrivers)
+ {
+ WildCard aWildCard(rPattern);
+ if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) )
+ {
+ sRet = rDriver.sDriverTypeDisplayName;
+ sOldPattern = rPattern;
+ }
+ }
+
+ return sRet;
+}
+
+const ::comphelper::NamedValueCollection& DriversConfig::getProperties(std::u16string_view _sURL)
+ const
+{
+ return impl_get(_sURL,1);
+}
+
+const ::comphelper::NamedValueCollection& DriversConfig::getFeatures(std::u16string_view _sURL)
+ const
+{
+ return impl_get(_sURL,0);
+}
+
+const ::comphelper::NamedValueCollection& DriversConfig::getMetaData(std::u16string_view _sURL)
+ const
+{
+ return impl_get(_sURL,2);
+}
+
+const ::comphelper::NamedValueCollection& DriversConfig::impl_get(std::u16string_view _sURL,sal_Int32 _nProps) const
+{
+ const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB);
+ const ::comphelper::NamedValueCollection* pRet = nullptr;
+ OUString sOldPattern;
+ for(const auto& [rPattern, rDriver] : rDrivers)
+ {
+ WildCard aWildCard(rPattern);
+ if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) )
+ {
+ switch(_nProps)
+ {
+ case 0:
+ pRet = &rDriver.aFeatures;
+ break;
+ case 1:
+ pRet = &rDriver.aProperties;
+ break;
+ case 2:
+ pRet = &rDriver.aMetaData;
+ break;
+ }
+ sOldPattern = rPattern;
+ }
+ } // for(;aIter != aEnd;++aIter)
+ if ( pRet == nullptr )
+ {
+ static const ::comphelper::NamedValueCollection s_sEmpty;
+ pRet = &s_sEmpty;
+ }
+ return *pRet;
+}
+
+uno::Sequence< OUString > DriversConfig::getURLs() const
+{
+ const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB);
+ return comphelper::mapKeysToSequence(rDrivers);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx
new file mode 100644
index 000000000..3c755f206
--- /dev/null
+++ b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx
@@ -0,0 +1,851 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <ParameterSubstitution.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <FDatabaseMetaDataResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/unreachable.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace dbtools;
+using namespace cppu;
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet()
+ :ODatabaseMetaDataResultSet_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer(ODatabaseMetaDataResultSet_BASE::rBHelper)
+ ,m_nColPos(0)
+ ,m_bBOF(true)
+ ,m_bEOF(true)
+{
+ construct();
+}
+
+
+ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet( MetaDataResultSetType _eType )
+ :ODatabaseMetaDataResultSet_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer(ODatabaseMetaDataResultSet_BASE::rBHelper)
+ ,m_nColPos(0)
+ ,m_bBOF(true)
+ ,m_bEOF(true)
+{
+ construct();
+
+ setType(_eType);
+}
+
+
+ODatabaseMetaDataResultSet::~ODatabaseMetaDataResultSet()
+{
+}
+
+void ODatabaseMetaDataResultSet::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, 0,&m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY,&m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, 0, &m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::READONLY,&m_nResultSetConcurrency, ::cppu::UnoType<sal_Int32>::get());
+}
+
+void ODatabaseMetaDataResultSet::setType(MetaDataResultSetType _eType)
+{
+ switch( _eType )
+ {
+ case eCatalogs: setCatalogsMap(); break;
+ case eSchemas: setSchemasMap(); break;
+ case eColumnPrivileges: setColumnPrivilegesMap(); break;
+ case eColumns: setColumnsMap(); break;
+ case eTables: setTablesMap(); break;
+ case eTableTypes: setTableTypes(); break;
+ case eProcedureColumns: setProcedureColumnsMap(); break;
+ case eProcedures: setProceduresMap(); break;
+ case eExportedKeys: setExportedKeysMap(); break;
+ case eImportedKeys: setImportedKeysMap(); break;
+ case ePrimaryKeys: setPrimaryKeysMap(); break;
+ case eIndexInfo: setIndexInfoMap(); break;
+ case eTablePrivileges: setTablePrivilegesMap(); break;
+ case eCrossReference: setCrossReferenceMap(); break;
+ case eTypeInfo: setTypeInfoMap(); break;
+ case eBestRowIdentifier: setBestRowIdentifierMap(); break;
+ case eVersionColumns: setVersionColumnsMap(); break;
+ case eUDTs: setUDTsMap(); break;
+ default:
+ OSL_FAIL("Wrong type!");
+ }
+}
+
+void ODatabaseMetaDataResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_aStatement.clear();
+ m_xMetaData.clear();
+ m_aRowsIter = m_aRows.end();
+ m_aRows.clear();
+ m_aRowsIter = m_aRows.end();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::acquire() noexcept
+{
+ ODatabaseMetaDataResultSet_BASE::acquire();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::release() noexcept
+{
+ ODatabaseMetaDataResultSet_BASE::release();
+}
+
+Any SAL_CALL ODatabaseMetaDataResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ODatabaseMetaDataResultSet_BASE::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL ODatabaseMetaDataResultSet::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),ODatabaseMetaDataResultSet_BASE::getTypes());
+}
+
+void ODatabaseMetaDataResultSet::setRows(ORows&& _rRows)
+{
+ m_aRows = std::move(_rRows);
+ m_bBOF = true;
+ m_bEOF = m_aRows.empty();
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::findColumn( const OUString& columnName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i))
+ )
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ O3TL_UNREACHABLE;
+}
+
+void ODatabaseMetaDataResultSet::checkIndex(sal_Int32 columnIndex )
+{
+ if(columnIndex < 1 || o3tl::make_unsigned(columnIndex) >= (*m_aRowsIter).size())
+ ::dbtools::throwInvalidIndexException(*this);
+}
+
+Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getBool();
+}
+
+
+sal_Int8 SAL_CALL ODatabaseMetaDataResultSet::getByte( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt8();
+}
+
+
+Sequence< sal_Int8 > SAL_CALL ODatabaseMetaDataResultSet::getBytes( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getSequence();
+}
+
+
+css::util::Date SAL_CALL ODatabaseMetaDataResultSet::getDate( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDate();
+}
+
+
+double SAL_CALL ODatabaseMetaDataResultSet::getDouble( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDouble();
+}
+
+
+float SAL_CALL ODatabaseMetaDataResultSet::getFloat( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getFloat();
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getInt( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt32();
+}
+
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getRow( )
+{
+ return 0;
+}
+
+
+sal_Int64 SAL_CALL ODatabaseMetaDataResultSet::getLong( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getLong();
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL ODatabaseMetaDataResultSet::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new ODatabaseMetaDataResultSetMetaData();
+
+ return m_xMetaData;
+}
+
+Reference< XArray > SAL_CALL ODatabaseMetaDataResultSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Reference< XClob > SAL_CALL ODatabaseMetaDataResultSet::getClob( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL ODatabaseMetaDataResultSet::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL ODatabaseMetaDataResultSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Any SAL_CALL ODatabaseMetaDataResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ return getValue(columnIndex).makeAny();
+}
+
+
+sal_Int16 SAL_CALL ODatabaseMetaDataResultSet::getShort( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt16();
+}
+
+
+OUString SAL_CALL ODatabaseMetaDataResultSet::getString( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getString();
+}
+
+
+css::util::Time SAL_CALL ODatabaseMetaDataResultSet::getTime( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getTime();
+}
+
+
+css::util::DateTime SAL_CALL ODatabaseMetaDataResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDateTime();
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isAfterLast( )
+{
+ return m_bEOF;
+}
+
+
+SAL_WNOUNREACHABLE_CODE_PUSH
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+SAL_WNOUNREACHABLE_CODE_POP
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::beforeFirst( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::afterLast( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+ }
+ dispose();
+}
+
+
+SAL_WNOUNREACHABLE_CODE_PUSH
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::first( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 /*row*/ )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 /*row*/ )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+SAL_WNOUNREACHABLE_CODE_POP
+
+
+Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( )
+{
+ return m_aStatement.get();
+}
+
+
+SAL_WNOUNREACHABLE_CODE_PUSH
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( )
+{
+ ::dbtools::throwFunctionSequenceException(*this);
+ return false;
+}
+
+SAL_WNOUNREACHABLE_CODE_POP
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isBeforeFirst( )
+{
+ return m_bBOF;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+ if ( m_bBOF )
+ {
+ m_aRowsIter = m_aRows.begin();
+ m_bBOF = false;
+ }
+ else
+ {
+ if ( m_bEOF )
+ throwFunctionSequenceException( *this );
+ else
+ if ( m_aRowsIter != m_aRows.end() )
+ ++m_aRowsIter;
+ }
+
+ bool bSuccess = m_aRowsIter != m_aRows.end();
+ if ( !bSuccess )
+ {
+ m_bEOF = true;
+ m_bBOF = m_aRows.empty();
+ }
+ return bSuccess;
+}
+
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+
+ if(m_aRowsIter == m_aRows.end() || !(*m_aRowsIter)[m_nColPos].is())
+ return true;
+
+ return (*m_aRowsIter)[m_nColPos]->getValue().isNull();
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::refreshRow( )
+{
+}
+
+
+void SAL_CALL ODatabaseMetaDataResultSet::cancel( )
+{
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::clearWarnings( )
+{
+}
+
+Any SAL_CALL ODatabaseMetaDataResultSet::getWarnings( )
+{
+ return Any();
+}
+
+::cppu::IPropertyArrayHelper* ODatabaseMetaDataResultSet::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+::cppu::IPropertyArrayHelper & ODatabaseMetaDataResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+void ODatabaseMetaDataResultSet::setProceduresMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setProceduresMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setCatalogsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setCatalogsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setSchemasMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setSchemasMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setColumnPrivilegesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setColumnPrivilegesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTablesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTablesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setProcedureColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setProcedureColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setPrimaryKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setPrimaryKeysMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setIndexInfoMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setIndexInfoMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTablePrivilegesMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTablePrivilegesMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setCrossReferenceMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setCrossReferenceMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setVersionColumnsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setVersionColumnsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setBestRowIdentifierMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setBestRowIdentifierMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTypeInfoMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTypeInfoMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setUDTsMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setUDTsMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setTableTypes()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setTableTypes();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setExportedKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setExportedKeysMap();
+ m_xMetaData = pMetaData;
+}
+
+void ODatabaseMetaDataResultSet::setImportedKeysMap()
+{
+ rtl::Reference<ODatabaseMetaDataResultSetMetaData> pMetaData = new ODatabaseMetaDataResultSetMetaData();
+ pMetaData->setImportedKeysMap();
+ m_xMetaData = pMetaData;
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL ODatabaseMetaDataResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+ORowSetValueDecorator& ORowSetValueDecorator::operator=(const ORowSetValue& _aValue)
+{
+ m_aValue = _aValue;
+ return *this;
+}
+
+const ORowSetValue& ODatabaseMetaDataResultSet::getValue(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+ if ( isBeforeFirst() || isAfterLast() )
+ ::dbtools::throwFunctionSequenceException( *this );
+
+ checkIndex(columnIndex );
+ m_nColPos = columnIndex;
+
+ if(m_aRowsIter != m_aRows.end() && (*m_aRowsIter)[columnIndex].is())
+ return *(*m_aRowsIter)[columnIndex];
+ return m_aEmptyValue;
+}
+
+/// return an empty ORowSetValueDecorator
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getEmptyValue()
+{
+ static ORowSetValueDecoratorRef aEmptyValueRef = new ORowSetValueDecorator();
+ return aEmptyValueRef;
+}
+
+/// return an ORowSetValueDecorator with 0 as value
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::get0Value()
+{
+ static ORowSetValueDecoratorRef a0ValueRef = new ORowSetValueDecorator(sal_Int32(0));
+ return a0ValueRef;
+}
+
+/// return an ORowSetValueDecorator with 1 as value
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::get1Value()
+{
+ static ORowSetValueDecoratorRef a1ValueRef = new ORowSetValueDecorator(sal_Int32(1));
+ return a1ValueRef;
+}
+
+/// return an ORowSetValueDecorator with ColumnSearch::BASIC as value
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getBasicValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(ColumnSearch::BASIC);
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getSelectValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("SELECT"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getInsertValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("INSERT"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getDeleteValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("DELETE"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getUpdateValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("UPDATE"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getCreateValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("CREATE"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getReadValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("READ"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getAlterValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("ALTER"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getDropValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("DROP"));
+ return aValueRef;
+}
+
+ORowSetValueDecoratorRef const & ODatabaseMetaDataResultSet::getQuoteValue()
+{
+ static ORowSetValueDecoratorRef aValueRef = new ORowSetValueDecorator(OUString("'"));
+ return aValueRef;
+}
+
+void SAL_CALL ODatabaseMetaDataResultSet::initialize( const Sequence< Any >& _aArguments )
+{
+ if ( _aArguments.getLength() != 2 )
+ return;
+
+ sal_Int32 nResultSetType = 0;
+ if ( !(_aArguments[0] >>= nResultSetType))
+ return;
+
+ setType(static_cast<MetaDataResultSetType>(nResultSetType));
+ Sequence< Sequence<Any> > aRows;
+ if ( !(_aArguments[1] >>= aRows) )
+ return;
+
+ ORows aRowsToSet;
+ const Sequence<Any>* pRowsIter = aRows.getConstArray();
+ const Sequence<Any>* pRowsEnd = pRowsIter + aRows.getLength();
+ for (; pRowsIter != pRowsEnd;++pRowsIter)
+ {
+ ORow aRowToSet;
+ const Any* pRowIter = pRowsIter->getConstArray();
+ const Any* pRowEnd = pRowIter + pRowsIter->getLength();
+ for (; pRowIter != pRowEnd;++pRowIter)
+ {
+ ORowSetValueDecoratorRef aValue;
+ switch( pRowIter->getValueTypeClass() )
+ {
+ case TypeClass_BOOLEAN:
+ {
+ bool bValue = false;
+ *pRowIter >>= bValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(bValue));
+ }
+ break;
+ case TypeClass_BYTE:
+ {
+ sal_Int8 nValue(0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_SHORT:
+ case TypeClass_UNSIGNED_SHORT:
+ {
+ sal_Int16 nValue(0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_LONG:
+ case TypeClass_UNSIGNED_LONG:
+ {
+ sal_Int32 nValue(0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_HYPER:
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ sal_Int64 nValue(0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_FLOAT:
+ {
+ float nValue(0.0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_DOUBLE:
+ {
+ double nValue(0.0);
+ *pRowIter >>= nValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(nValue));
+ }
+ break;
+ case TypeClass_STRING:
+ {
+ OUString sValue;
+ *pRowIter >>= sValue;
+ aValue = new ORowSetValueDecorator(ORowSetValue(sValue));
+ }
+ break;
+ default:
+ break;
+ }
+ aRowToSet.push_back(aValue);
+ }
+ aRowsToSet.push_back(aRowToSet);
+ } // for (; pRowsIter != pRowsEnd;++pRowsIter
+ setRows(std::move(aRowsToSet));
+}
+// XServiceInfo
+
+
+ OUString SAL_CALL ODatabaseMetaDataResultSet::getImplementationName( )
+ {
+ return "org.openoffice.comp.helper.DatabaseMetaDataResultSet";
+ }
+
+ sal_Bool SAL_CALL ODatabaseMetaDataResultSet::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL ODatabaseMetaDataResultSet::getSupportedServiceNames( )
+ {
+ return Sequence<OUString>{ "com.sun.star.sdbc.ResultSet" };
+ }
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_dbtools_ODatabaseMetaDataResultSet_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ODatabaseMetaDataResultSet());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx b/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx
new file mode 100644
index 000000000..561953a07
--- /dev/null
+++ b/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx
@@ -0,0 +1,357 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <FDatabaseMetaDataResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+
+ODatabaseMetaDataResultSetMetaData::~ODatabaseMetaDataResultSetMetaData()
+{
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnDisplaySize();
+
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnType();
+ return 1;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnCount( )
+{
+ return m_mColumns.size();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCaseSensitive( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isCaseSensitive();
+ return true;
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getSchemaName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnName();
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getTableName( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getTableName();
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getCatalogName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnTypeName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getColumnLabel();
+ return getColumnName(column);
+}
+
+OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isCurrency();
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isAutoIncrement( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isAutoIncrement();
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSigned( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isSigned();
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getPrecision();
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getScale( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.getScale();
+
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::isNullable( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isNullable();
+
+ return sal_Int32(false);
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSearchable( sal_Int32 column )
+{
+ if((m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
+ return (*m_mColumnsIter).second.isSearchable();
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isReadOnly( sal_Int32 /*column*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isDefinitelyWritable( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isWritable( sal_Int32 column )
+{
+ return isDefinitelyWritable(column);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setColumnPrivilegesMap()
+{
+ setColumnMap();
+ m_mColumns[5] = OColumn(OUString(),"GRANTOR", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"GRANTEE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"PRIVILEGE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[8] = OColumn(OUString(),"IS_GRANTABLE", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTableNameMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TABLE_CAT", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"TABLE_SCHEM", ColumnValue::NULLABLE, 3,3,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"TABLE_NAME", ColumnValue::NO_NULLS, 3,3,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setColumnMap()
+{
+ setTableNameMap();
+ m_mColumns[4] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 3,3,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setColumnsMap()
+{
+ setColumnMap();
+
+ m_mColumns[5] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"COLUMN_SIZE", ColumnValue::NO_NULLS, 3,3,0, DataType::INTEGER);
+ m_mColumns[8] = OColumn(OUString(),"BUFFER_LENGTH", ColumnValue::NULLABLE, 3,3,0, DataType::INTEGER);
+ m_mColumns[9] = OColumn(OUString(),"DECIMAL_DIGITS", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[10] = OColumn(OUString(),"NUM_PREC_RADIX", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[11] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[13] = OColumn(OUString(),"COLUMN_DEF", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[14] = OColumn(OUString(),"SQL_DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[15] = OColumn(OUString(),"SQL_DATETIME_SUB", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[16] = OColumn(OUString(),"CHAR_OCTET_LENGTH", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[17] = OColumn(OUString(),"ORDINAL_POSITION", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[18] = OColumn(OUString(),"IS_NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTablesMap()
+{
+ setTableNameMap();
+ m_mColumns[4] = OColumn(OUString(),"TABLE_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setProcedureNameMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"PROCEDURE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"PROCEDURE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"PROCEDURE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setProcedureColumnsMap()
+{
+ setProcedureNameMap();
+ m_mColumns[4] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"COLUMN_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[7] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[8] = OColumn(OUString(),"PRECISION", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[9] = OColumn(OUString(),"LENGTH", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[10] = OColumn(OUString(),"SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[11] = OColumn(OUString(),"RADIX", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[13] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setPrimaryKeysMap()
+{
+ setColumnMap();
+ m_mColumns[5] = OColumn(OUString(),"KEY_SEQ", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"PK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setIndexInfoMap()
+{
+ setTableNameMap();
+ m_mColumns[4] = OColumn(OUString(),"NON_UNIQUE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[5] = OColumn(OUString(),"INDEX_QUALIFIER", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"INDEX_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[8] = OColumn(OUString(),"ORDINAL_POSITION", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[9] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[10] = OColumn(OUString(),"ASC_OR_DESC", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[11] = OColumn(OUString(),"CARDINALITY", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"PAGES", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[13] = OColumn(OUString(),"FILTER_CONDITION", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTablePrivilegesMap()
+{
+ setTableNameMap();
+ m_mColumns[4] = OColumn(OUString(),"GRANTOR", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"GRANTEE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"PRIVILEGE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"IS_GRANTABLE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setCrossReferenceMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"PKTABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"PKTABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"PKTABLE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[4] = OColumn(OUString(),"PKCOLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"FKTABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"FKTABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"FKTABLE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[8] = OColumn(OUString(),"FKCOLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+
+ m_mColumns[9] = OColumn(OUString(),"KEY_SEQ", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[10] = OColumn(OUString(),"UPDATE_RULE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[11] = OColumn(OUString(),"DELETE_RULE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[12] = OColumn(OUString(),"FK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[13] = OColumn(OUString(),"PK_NAME", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[14] = OColumn(OUString(),"DEFERRABILITY", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTypeInfoMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[3] = OColumn(OUString(),"PRECISION", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[4] = OColumn(OUString(),"LITERAL_PREFIX", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"LITERAL_SUFFIX", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"CREATE_PARAMS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"NULLABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[8] = OColumn(OUString(),"CASE_SENSITIVE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[9] = OColumn(OUString(),"SEARCHABLE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[10] = OColumn(OUString(),"UNSIGNED_ATTRIBUTE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[11] = OColumn(OUString(),"FIXED_PREC_SCALE", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[12] = OColumn(OUString(),"AUTO_INCREMENT", ColumnValue::NO_NULLS, 1,1,0, DataType::BIT);
+ m_mColumns[13] = OColumn(OUString(),"LOCAL_TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[14] = OColumn(OUString(),"MINIMUM_SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[15] = OColumn(OUString(),"MAXIMUM_SCALE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[16] = OColumn(OUString(),"SQL_DATA_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[17] = OColumn(OUString(),"SQL_DATETIME_SUB", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+ m_mColumns[18] = OColumn(OUString(),"NUM_PREC_RADIX", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setProceduresMap()
+{
+ setProcedureNameMap();
+ m_mColumns[4] = OColumn(OUString(),"RESERVED1", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"RESERVED2", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"RESERVED3", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[7] = OColumn(OUString(),"REMARKS", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[8] = OColumn(OUString(),"PROCEDURE_TYPE", ColumnValue::NO_NULLS, 1,1,0, DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setTableTypes()
+{
+ m_mColumns[1] = OColumn(OUString(),"TABLE_TYPE", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setCatalogsMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TABLE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setSchemasMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TABLE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setVersionColumnsMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"SCOPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[2] = OColumn(OUString(),"COLUMN_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[4] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"COLUMN_SIZE", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[6] = OColumn(OUString(),"BUFFER_LENGTH", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+ m_mColumns[7] = OColumn(OUString(),"DECIMAL_DIGITS", ColumnValue::NULLABLE, 0,0,0, DataType::INTEGER);
+ m_mColumns[8] = OColumn(OUString(),"PSEUDO_COLUMN", ColumnValue::NO_NULLS, 0,0,0, DataType::INTEGER);
+}
+
+void ODatabaseMetaDataResultSetMetaData::setUDTsMap()
+{
+ m_mColumns[1] = OColumn(OUString(),"TYPE_CAT", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[2] = OColumn(OUString(),"TYPE_SCHEM", ColumnValue::NULLABLE, 0,0,0, DataType::VARCHAR);
+ m_mColumns[3] = OColumn(OUString(),"TYPE_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[4] = OColumn(OUString(),"CLASS_NAME", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[5] = OColumn(OUString(),"DATA_TYPE", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+ m_mColumns[6] = OColumn(OUString(),"REMARKS", ColumnValue::NO_NULLS, 0,0,0, DataType::VARCHAR);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/FValue.cxx b/connectivity/source/commontools/FValue.cxx
new file mode 100644
index 000000000..4ac0235ac
--- /dev/null
+++ b/connectivity/source/commontools/FValue.cxx
@@ -0,0 +1,2473 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <string.h>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <comphelper/extract.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/XClob.hpp>
+#include <com/sun/star/sdbc/XBlob.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::dbtools;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+
+namespace connectivity
+{
+
+namespace {
+ bool isStorageCompatible(sal_Int32 _eType1, sal_Int32 _eType2)
+ {
+ bool bIsCompatible = true;
+
+ if (_eType1 != _eType2)
+ {
+ SAL_INFO( "connectivity.commontools", "ORowSetValue::isStorageCompatible _eType1 != _eType2" );
+ switch (_eType1)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ bIsCompatible = (DataType::CHAR == _eType2)
+ || (DataType::VARCHAR == _eType2)
+ || (DataType::DECIMAL == _eType2)
+ || (DataType::NUMERIC == _eType2)
+ || (DataType::LONGVARCHAR == _eType2);
+ break;
+
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ bIsCompatible = (DataType::DOUBLE == _eType2)
+ || (DataType::REAL == _eType2);
+ break;
+
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ bIsCompatible = (DataType::BINARY == _eType2)
+ || (DataType::VARBINARY == _eType2)
+ || (DataType::LONGVARBINARY == _eType2);
+ break;
+
+ case DataType::INTEGER:
+ bIsCompatible = (DataType::SMALLINT == _eType2)
+ || (DataType::TINYINT == _eType2)
+ || (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+ case DataType::SMALLINT:
+ bIsCompatible = (DataType::TINYINT == _eType2)
+ || (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+ case DataType::TINYINT:
+ bIsCompatible = (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ bIsCompatible = (DataType::BLOB == _eType2)
+ || (DataType::CLOB == _eType2)
+ || (DataType::OBJECT == _eType2);
+ break;
+
+ default:
+ bIsCompatible = false;
+ }
+ }
+ return bIsCompatible;
+ }
+
+ bool isStorageComparable(sal_Int32 _eType1, sal_Int32 _eType2)
+ {
+ bool bIsComparable = true;
+
+ if (_eType1 != _eType2)
+ {
+ SAL_INFO( "connectivity.commontools", "ORowSetValue::isStorageCompatible _eType1 != _eType2" );
+ switch (_eType1)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ bIsComparable = (DataType::CHAR == _eType2)
+ || (DataType::VARCHAR == _eType2)
+ || (DataType::LONGVARCHAR == _eType2);
+ break;
+
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ bIsComparable = (DataType::DECIMAL == _eType2)
+ || (DataType::NUMERIC == _eType2);
+ break;
+
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ bIsComparable = (DataType::DOUBLE == _eType2)
+ || (DataType::REAL == _eType2);
+ break;
+
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ bIsComparable = (DataType::BINARY == _eType2)
+ || (DataType::VARBINARY == _eType2)
+ || (DataType::LONGVARBINARY == _eType2);
+ break;
+
+ case DataType::INTEGER:
+ bIsComparable = (DataType::SMALLINT == _eType2)
+ || (DataType::TINYINT == _eType2)
+ || (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+ case DataType::SMALLINT:
+ bIsComparable = (DataType::TINYINT == _eType2)
+ || (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+ case DataType::TINYINT:
+ bIsComparable = (DataType::BIT == _eType2)
+ || (DataType::BOOLEAN == _eType2);
+ break;
+
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ bIsComparable = (DataType::BLOB == _eType2)
+ || (DataType::CLOB == _eType2)
+ || (DataType::OBJECT == _eType2);
+ break;
+
+ default:
+ bIsComparable = false;
+ }
+ }
+ return bIsComparable;
+ }
+}
+
+void ORowSetValue::setTypeKind(sal_Int32 _eType)
+{
+ if ( !m_bNull && !isStorageCompatible(_eType, m_eTypeKind) )
+ {
+ switch(_eType)
+ {
+ case DataType::VARCHAR:
+ case DataType::CHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ (*this) = getString();
+ break;
+ case DataType::BIGINT:
+ {
+ sal_Int64 nVal(getLong());
+ sal_uInt64 nuVal(getULong());
+ if (nVal == 0 && nuVal != 0)
+ (*this) = nuVal;
+ else
+ (*this) = nVal;
+ break;
+ }
+
+ case DataType::FLOAT:
+ (*this) = getFloat();
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ (*this) = getDouble();
+ break;
+ case DataType::TINYINT:
+ (*this) = getInt8();
+ break;
+ case DataType::SMALLINT:
+ (*this) = getInt16();
+ break;
+ case DataType::INTEGER:
+ {
+ sal_Int32 nVal(getInt32());
+ sal_uInt32 nuVal(getUInt32());
+ if (nVal == 0 && nuVal != 0)
+ (*this) = nuVal;
+ else
+ (*this) = nVal;
+ break;
+ }
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ (*this) = getBool();
+ break;
+ case DataType::DATE:
+ (*this) = getDate();
+ break;
+ case DataType::TIME:
+ (*this) = getTime();
+ break;
+ case DataType::TIMESTAMP:
+ (*this) = getDateTime();
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ (*this) = getSequence();
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ case DataType::OTHER:
+ (*this) = makeAny();
+ break;
+ default:
+ (*this) = makeAny();
+ SAL_WARN( "connectivity.commontools","ORowSetValue::setTypeKind(): UNSUPPORTED TYPE!");
+ }
+ }
+
+ m_eTypeKind = _eType;
+}
+
+
+void ORowSetValue::free() noexcept
+{
+ if(m_bNull)
+ return;
+
+ switch(m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ OSL_ENSURE(m_aValue.m_pString,"String pointer is null!");
+ rtl_uString_release(m_aValue.m_pString);
+ m_aValue.m_pString = nullptr;
+ break;
+ case DataType::DATE:
+ delete static_cast<css::util::Date*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::TIME:
+ delete static_cast<css::util::Time*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::TIMESTAMP:
+ delete static_cast<css::util::DateTime*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ delete static_cast<Sequence<sal_Int8>*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ delete static_cast<Any*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ break;
+ case DataType::BIT:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::BOOLEAN:
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ break;
+ default:
+ if ( m_aValue.m_pValue )
+ {
+ delete static_cast<Any*>(m_aValue.m_pValue);
+ m_aValue.m_pValue = nullptr;
+ }
+ break;
+
+ }
+ m_bNull = true;
+}
+
+ORowSetValue& ORowSetValue::operator=(const ORowSetValue& _rRH)
+{
+ if(&_rRH == this)
+ return *this;
+
+ if ( m_eTypeKind != _rRH.m_eTypeKind || (_rRH.m_bNull && !m_bNull) || m_bSigned != _rRH.m_bSigned)
+ free();
+
+ m_bBound = _rRH.m_bBound;
+ m_eTypeKind = _rRH.m_eTypeKind;
+ m_bSigned = _rRH.m_bSigned;
+
+ if(m_bNull && !_rRH.m_bNull)
+ {
+ switch(_rRH.m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ rtl_uString_acquire(_rRH.m_aValue.m_pString);
+ m_aValue.m_pString = _rRH.m_aValue.m_pString;
+ break;
+ case DataType::DATE:
+ m_aValue.m_pValue = new Date(*static_cast<Date*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ m_aValue.m_pValue = new Time(*static_cast<Time*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::TIMESTAMP:
+ m_aValue.m_pValue = new DateTime(*static_cast<DateTime*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ m_aValue.m_pValue = new Sequence<sal_Int8>(*static_cast<Sequence<sal_Int8>*>(_rRH.m_aValue.m_pValue));
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ m_aValue.m_bBool = _rRH.m_aValue.m_bBool;
+ break;
+ case DataType::TINYINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt8 = _rRH.m_aValue.m_nInt8;
+ else
+ m_aValue.m_uInt8 = _rRH.m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt16 = _rRH.m_aValue.m_nInt16;
+ else
+ m_aValue.m_uInt16 = _rRH.m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt32 = _rRH.m_aValue.m_nInt32;
+ else
+ m_aValue.m_uInt32 = _rRH.m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt64 = _rRH.m_aValue.m_nInt64;
+ else
+ m_aValue.m_uInt64 = _rRH.m_aValue.m_uInt64;
+ break;
+ case DataType::FLOAT:
+ m_aValue.m_nFloat = _rRH.m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ m_aValue.m_nDouble = _rRH.m_aValue.m_nDouble;
+ break;
+ default:
+ m_aValue.m_pValue = new Any(*static_cast<Any*>(_rRH.m_aValue.m_pValue));
+ }
+ }
+ else if(!_rRH.m_bNull)
+ {
+ switch(_rRH.m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ (*this) = OUString(_rRH.m_aValue.m_pString);
+ break;
+ case DataType::DATE:
+ (*this) = *static_cast<Date*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ (*this) = *static_cast<Time*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ (*this) = *static_cast<DateTime*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ (*this) = *static_cast<Sequence<sal_Int8>*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ m_aValue.m_bBool = _rRH.m_aValue.m_bBool;
+ break;
+ case DataType::TINYINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt8 = _rRH.m_aValue.m_nInt8;
+ else
+ m_aValue.m_uInt8 = _rRH.m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt16 = _rRH.m_aValue.m_nInt16;
+ else
+ m_aValue.m_uInt16 = _rRH.m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt32 = _rRH.m_aValue.m_nInt32;
+ else
+ m_aValue.m_uInt32 = _rRH.m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( _rRH.m_bSigned )
+ m_aValue.m_nInt64 = _rRH.m_aValue.m_nInt64;
+ else
+ m_aValue.m_uInt64 = _rRH.m_aValue.m_uInt64;
+ break;
+ case DataType::FLOAT:
+ m_aValue.m_nFloat = _rRH.m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ m_aValue.m_nDouble = _rRH.m_aValue.m_nDouble;
+ break;
+ default:
+ *static_cast<Any*>(m_aValue.m_pValue) = *static_cast<Any*>(_rRH.m_aValue.m_pValue);
+ }
+ }
+
+ m_bNull = _rRH.m_bNull;
+ // OJ: BUGID: 96277
+ m_eTypeKind = _rRH.m_eTypeKind;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(ORowSetValue&& _rRH) noexcept
+{
+ if ( m_eTypeKind != _rRH.m_eTypeKind || !m_bNull)
+ free();
+ if(!_rRH.m_bNull)
+ {
+ m_aValue = _rRH.m_aValue;
+ memset(&_rRH.m_aValue, 0, sizeof(_rRH.m_aValue));
+ }
+ m_bBound = _rRH.m_bBound;
+ m_eTypeKind = _rRH.m_eTypeKind;
+ m_bSigned = _rRH.m_bSigned;
+ m_bNull = _rRH.m_bNull;
+ _rRH.m_bNull = true;
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(const Date& _rRH)
+{
+ if(m_eTypeKind != DataType::DATE)
+ free();
+
+ if(m_bNull)
+ {
+ m_aValue.m_pValue = new Date(_rRH);
+ m_eTypeKind = DataType::DATE;
+ m_bNull = false;
+ }
+ else
+ *static_cast<Date*>(m_aValue.m_pValue) = _rRH;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(const css::util::Time& _rRH)
+{
+ if(m_eTypeKind != DataType::TIME)
+ free();
+
+ if(m_bNull)
+ {
+ m_aValue.m_pValue = new Time(_rRH);
+ m_eTypeKind = DataType::TIME;
+ m_bNull = false;
+ }
+ else
+ *static_cast<Time*>(m_aValue.m_pValue) = _rRH;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(const DateTime& _rRH)
+{
+ if(m_eTypeKind != DataType::TIMESTAMP)
+ free();
+ if(m_bNull)
+ {
+ m_aValue.m_pValue = new DateTime(_rRH);
+ m_eTypeKind = DataType::TIMESTAMP;
+ m_bNull = false;
+ }
+ else
+ *static_cast<DateTime*>(m_aValue.m_pValue) = _rRH;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(const OUString& _rRH)
+{
+ if(m_eTypeKind != DataType::VARCHAR || m_aValue.m_pString != _rRH.pData)
+ {
+ free();
+ m_bNull = false;
+
+ m_aValue.m_pString = _rRH.pData;
+ rtl_uString_acquire(m_aValue.m_pString);
+ m_eTypeKind = DataType::VARCHAR;
+ }
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(double _rRH)
+{
+ if(m_eTypeKind != DataType::DOUBLE)
+ free();
+
+ m_aValue.m_nDouble = _rRH;
+ m_eTypeKind = DataType::DOUBLE;
+ m_bNull = false;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(float _rRH)
+{
+ if(m_eTypeKind != DataType::FLOAT)
+ free();
+
+ m_aValue.m_nFloat = _rRH;
+ m_eTypeKind = DataType::FLOAT;
+ m_bNull = false;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(sal_Int8 _rRH)
+{
+ if(m_eTypeKind != DataType::TINYINT )
+ free();
+
+ m_aValue.m_nInt8 = _rRH;
+ m_eTypeKind = DataType::TINYINT;
+ m_bNull = false;
+ m_bSigned = true;
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(sal_Int16 _rRH)
+{
+ if(m_eTypeKind != DataType::SMALLINT )
+ free();
+
+ m_aValue.m_nInt16 = _rRH;
+ m_eTypeKind = DataType::SMALLINT;
+ m_bNull = false;
+ m_bSigned = true;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(sal_uInt16 _rRH)
+{
+ if(m_eTypeKind != DataType::SMALLINT )
+ free();
+
+ m_aValue.m_uInt16 = _rRH;
+ m_eTypeKind = DataType::SMALLINT;
+ m_bNull = false;
+ m_bSigned = false;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(sal_Int32 _rRH)
+{
+ if(m_eTypeKind != DataType::INTEGER )
+ free();
+
+ m_aValue.m_nInt32 = _rRH;
+
+ m_eTypeKind = DataType::INTEGER;
+ m_bNull = false;
+ m_bSigned = true;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(sal_uInt32 _rRH)
+{
+ if(m_eTypeKind != DataType::INTEGER )
+ free();
+
+ m_aValue.m_uInt32 = _rRH;
+
+ m_eTypeKind = DataType::INTEGER;
+ m_bNull = false;
+ m_bSigned = false;
+
+ return *this;
+}
+
+
+ORowSetValue& ORowSetValue::operator=(const bool _rRH)
+{
+ if(m_eTypeKind != DataType::BIT && DataType::BOOLEAN != m_eTypeKind )
+ free();
+
+ m_aValue.m_bBool = _rRH;
+ m_eTypeKind = DataType::BOOLEAN;
+ m_bNull = false;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(sal_Int64 _rRH)
+{
+ if ( DataType::BIGINT != m_eTypeKind)
+ free();
+
+ m_aValue.m_nInt64 = _rRH;
+ m_eTypeKind = DataType::BIGINT;
+ m_bNull = false;
+ m_bSigned = true;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(sal_uInt64 _rRH)
+{
+ if ( DataType::BIGINT != m_eTypeKind)
+ free();
+
+ m_aValue.m_uInt64 = _rRH;
+ m_eTypeKind = DataType::BIGINT;
+ m_bNull = false;
+ m_bSigned = false;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(const Sequence<sal_Int8>& _rRH)
+{
+ if (!isStorageCompatible(DataType::LONGVARBINARY,m_eTypeKind))
+ free();
+
+ if (m_bNull)
+ {
+ m_aValue.m_pValue = new Sequence<sal_Int8>(_rRH);
+ }
+ else
+ *static_cast< Sequence< sal_Int8 >* >(m_aValue.m_pValue) = _rRH;
+
+ m_eTypeKind = DataType::LONGVARBINARY;
+ m_bNull = false;
+
+ return *this;
+}
+
+ORowSetValue& ORowSetValue::operator=(const Any& _rAny)
+{
+ if (!isStorageCompatible(DataType::OBJECT,m_eTypeKind))
+ free();
+
+ if ( m_bNull )
+ {
+ m_aValue.m_pValue = new Any(_rAny);
+ }
+ else
+ *static_cast<Any*>(m_aValue.m_pValue) = _rAny;
+
+ m_eTypeKind = DataType::OBJECT;
+ m_bNull = false;
+
+ return *this;
+}
+
+
+bool ORowSetValue::operator==(const ORowSetValue& _rRH) const
+{
+ if ( m_bNull != _rRH.isNull() )
+ return false;
+
+ if(m_bNull && _rRH.isNull())
+ return true;
+
+ if ( !isStorageComparable(m_eTypeKind, _rRH.m_eTypeKind ))
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ return getDouble() == _rRH.getDouble();
+ default:
+ switch(_rRH.m_eTypeKind)
+ {
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ return getDouble() == _rRH.getDouble();
+ default:
+ break;
+ }
+ break;
+ }
+ return false;
+ }
+
+ bool bRet = false;
+ OSL_ENSURE(!m_bNull,"Should not be null!");
+ switch(m_eTypeKind)
+ {
+ case DataType::VARCHAR:
+ case DataType::CHAR:
+ case DataType::LONGVARCHAR:
+ {
+ OUString aVal1(m_aValue.m_pString);
+ OUString aVal2(_rRH.m_aValue.m_pString);
+ return aVal1 == aVal2;
+ }
+ default:
+ if ( m_bSigned != _rRH.m_bSigned )
+ return false;
+ break;
+ }
+
+ switch(m_eTypeKind)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ {
+ OUString aVal1(m_aValue.m_pString);
+ OUString aVal2(_rRH.m_aValue.m_pString);
+ bRet = aVal1 == aVal2;
+ }
+ break;
+ case DataType::FLOAT:
+ bRet = m_aValue.m_nFloat == _rRH.m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ bRet = m_aValue.m_nDouble == _rRH.m_aValue.m_nDouble;
+ break;
+ case DataType::TINYINT:
+ bRet = m_bSigned ? ( m_aValue.m_nInt8 == _rRH.m_aValue.m_nInt8 ) : (m_aValue.m_uInt8 == _rRH.m_aValue.m_uInt8);
+ break;
+ case DataType::SMALLINT:
+ bRet = m_bSigned ? ( m_aValue.m_nInt16 == _rRH.m_aValue.m_nInt16 ) : (m_aValue.m_uInt16 == _rRH.m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ bRet = m_bSigned ? ( m_aValue.m_nInt32 == _rRH.m_aValue.m_nInt32 ) : (m_aValue.m_uInt32 == _rRH.m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ bRet = m_bSigned ? ( m_aValue.m_nInt64 == _rRH.m_aValue.m_nInt64 ) : (m_aValue.m_uInt64 == _rRH.m_aValue.m_uInt64);
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ bRet = m_aValue.m_bBool == _rRH.m_aValue.m_bBool;
+ break;
+ case DataType::DATE:
+ bRet = *static_cast<Date*>(m_aValue.m_pValue) == *static_cast<Date*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ bRet = *static_cast<Time*>(m_aValue.m_pValue) == *static_cast<Time*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ bRet = *static_cast<DateTime*>(m_aValue.m_pValue) == *static_cast<DateTime*>(_rRH.m_aValue.m_pValue);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ bRet = false;
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ case DataType::OTHER:
+ bRet = false;
+ break;
+ default:
+ bRet = false;
+ SAL_WARN( "connectivity.commontools","ORowSetValue::operator==(): UNSUPPORTED TYPE!");
+ break;
+ }
+ return bRet;
+}
+
+Any ORowSetValue::makeAny() const
+{
+ Any rValue;
+ if(isBound() && !isNull())
+ {
+ switch(getTypeKind())
+ {
+ case DataType::SQLNULL:
+ assert(rValue == Any());
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ OSL_ENSURE(m_aValue.m_pString,"Value is null!");
+ rValue <<= OUString(m_aValue.m_pString);
+ break;
+ case DataType::FLOAT:
+ rValue <<= m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ rValue <<= m_aValue.m_nDouble;
+ break;
+ case DataType::DATE:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<Date*>(m_aValue.m_pValue);
+ break;
+ case DataType::TIME:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<Time*>(m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<DateTime*>(m_aValue.m_pValue);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ OSL_ENSURE(m_aValue.m_pValue,"Value is null!");
+ rValue <<= *static_cast<Sequence<sal_Int8>*>(m_aValue.m_pValue);
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ case DataType::OTHER:
+ rValue = getAny();
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ rValue <<= m_aValue.m_bBool;
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ // TypeClass_BYTE
+ rValue <<= m_aValue.m_nInt8;
+ else
+ // There is no TypeClass_UNSIGNED_BYTE,
+ // so silently promote it to a 16-bit integer,
+ // that is TypeClass_UNSIGNED_SHORT
+ rValue <<= static_cast<sal_uInt16>(m_aValue.m_uInt8);
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ // TypeClass_SHORT
+ rValue <<= m_aValue.m_nInt16;
+ else
+ // TypeClass_UNSIGNED_SHORT
+ rValue <<= m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ // TypeClass_LONG
+ rValue <<= m_aValue.m_nInt32;
+ else
+ // TypeClass_UNSIGNED_LONG
+ rValue <<= m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ // TypeClass_HYPER
+ rValue <<= m_aValue.m_nInt64;
+ else
+ // TypeClass_UNSIGNED_HYPER
+ rValue <<= m_aValue.m_uInt64;
+ break;
+ default:
+ SAL_WARN( "connectivity.commontools","ORowSetValue::makeAny(): UNSUPPORTED TYPE!");
+ rValue = getAny();
+ break;
+ }
+ }
+ return rValue;
+}
+
+OUString ORowSetValue::getString( ) const
+{
+ OUString aRet;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ aRet = m_aValue.m_pString;
+ break;
+ case DataType::FLOAT:
+ aRet = OUString::number(getFloat());
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aRet = OUString::number(getDouble());
+ break;
+ case DataType::DATE:
+ aRet = DBTypeConversion::toDateString(getDate());
+ break;
+ case DataType::TIME:
+ aRet = DBTypeConversion::toTimeString(getTime());
+ break;
+ case DataType::TIMESTAMP:
+ aRet = DBTypeConversion::toDateTimeString(getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ {
+ OUStringBuffer sVal("0x");
+ Sequence<sal_Int8> aSeq(getSequence());
+ const sal_Int8* pBegin = aSeq.getConstArray();
+ const sal_Int8* pEnd = pBegin + aSeq.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ sVal.append(static_cast<sal_Int32>(*pBegin),16);
+ aRet = sVal.makeStringAndClear();
+ }
+ break;
+ case DataType::BIT:
+ aRet = OUString::number(int(getBool()));
+ break;
+ case DataType::BOOLEAN:
+ aRet = OUString::boolean(getBool());
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ aRet = OUString::number(getInt32());
+ else
+ aRet = OUString::number(getUInt32());
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ aRet = OUString::number(getLong());
+ else
+ aRet = OUString::number(getULong());
+ break;
+ case DataType::CLOB:
+ {
+ Any aValue( getAny() );
+ Reference< XClob > xClob;
+ if ( (aValue >>= xClob) && xClob.is() )
+ {
+ aRet = xClob->getSubString(1,static_cast<sal_Int32>(xClob->length()) );
+ }
+ }
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= aRet;
+ break;
+ }
+ }
+ }
+ return aRet;
+}
+
+bool ORowSetValue::getBool() const
+{
+ bool bRet = false;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ {
+ const OUString sValue(m_aValue.m_pString);
+ if ( sValue.equalsIgnoreAsciiCase("true") || (sValue == "1") )
+ {
+ bRet = true;
+ break;
+ }
+ else if ( sValue.equalsIgnoreAsciiCase("false") || (sValue == "0") )
+ {
+ bRet = false;
+ break;
+ }
+ }
+ [[fallthrough]];
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+
+ bRet = OUString::unacquired(&m_aValue.m_pString).toInt32() != 0;
+ break;
+ case DataType::FLOAT:
+ bRet = m_aValue.m_nFloat != 0.0;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ bRet = m_aValue.m_nDouble != 0.0;
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ OSL_FAIL("getBool() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ bRet = m_aValue.m_bBool;
+ break;
+ case DataType::TINYINT:
+ bRet = m_bSigned ? (m_aValue.m_nInt8 != 0) : (m_aValue.m_uInt8 != 0);
+ break;
+ case DataType::SMALLINT:
+ bRet = m_bSigned ? (m_aValue.m_nInt16 != 0) : (m_aValue.m_uInt16 != 0);
+ break;
+ case DataType::INTEGER:
+ bRet = m_bSigned ? (m_aValue.m_nInt32 != 0) : (m_aValue.m_uInt32 != 0);
+ break;
+ case DataType::BIGINT:
+ bRet = m_bSigned ? (m_aValue.m_nInt64 != 0) : (m_aValue.m_uInt64 != 0);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= bRet;
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+
+sal_Int8 ORowSetValue::getInt8() const
+{
+ sal_Int8 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = sal_Int8(OUString::unacquired(&m_aValue.m_pString).toInt32());
+ break;
+ case DataType::FLOAT:
+ nRet = sal_Int8(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_Int8(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getInt8() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_Int8(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt8);
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt16);
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int8>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int8>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_uInt8 ORowSetValue::getUInt8() const
+{
+ sal_uInt8 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = sal_uInt8(OUString::unacquired(&m_aValue.m_pString).toInt32());
+ break;
+ case DataType::FLOAT:
+ nRet = sal_uInt8(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_uInt8(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getuInt8() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = int(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt8>(m_aValue.m_nInt16);
+ else
+ nRet = static_cast<sal_uInt8>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt8>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_uInt8>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt8>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt8>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ // Cf. "There is no TypeClass_UNSIGNED_BYTE" in makeAny:
+ sal_uInt16 n;
+ if (aValue >>= n) {
+ nRet = static_cast<sal_uInt8>(n);
+ }
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_Int16 ORowSetValue::getInt16() const
+{
+ sal_Int16 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = sal_Int16(OUString::unacquired(&m_aValue.m_pString).toInt32());
+ break;
+ case DataType::FLOAT:
+ nRet = sal_Int16(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_Int16(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getInt16() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_Int16(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = static_cast<sal_Int16>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int16>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_Int16>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int16>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int16>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_uInt16 ORowSetValue::getUInt16() const
+{
+ sal_uInt16 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = sal_uInt16(OUString::unacquired(&m_aValue.m_pString).toInt32());
+ break;
+ case DataType::FLOAT:
+ nRet = sal_uInt16(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_uInt16(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getuInt16() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_uInt16(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt16>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<sal_uInt16>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt16>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt16>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_Int32 ORowSetValue::getInt32() const
+{
+ sal_Int32 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toInt32();
+ break;
+ case DataType::FLOAT:
+ nRet = sal_Int32(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_Int32(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDays(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getInt32() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_Int32(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = static_cast<sal_Int32>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_Int32>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_Int32>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_uInt32 ORowSetValue::getUInt32() const
+{
+ sal_uInt32 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toUInt32();
+ break;
+ case DataType::FLOAT:
+ nRet = sal_uInt32(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_uInt32(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDays(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getuInt32() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_uInt32(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<sal_uInt32>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<sal_uInt32>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_Int64 ORowSetValue::getLong() const
+{
+ sal_Int64 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toInt64();
+ break;
+ case DataType::FLOAT:
+ nRet = sal_Int64(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_Int64(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDays(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getLong() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_Int64(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt64;
+ else
+ nRet = static_cast<sal_Int64>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+sal_uInt64 ORowSetValue::getULong() const
+{
+ sal_uInt64 nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toUInt64();
+ break;
+ case DataType::FLOAT:
+ nRet = sal_uInt64(m_aValue.m_nFloat);
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = sal_uInt64(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDays(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getULong() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = sal_uInt64(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt64;
+ else
+ nRet = m_aValue.m_uInt64;
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+
+float ORowSetValue::getFloat() const
+{
+ float nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toFloat();
+ break;
+ case DataType::FLOAT:
+ nRet = m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = static_cast<float>(m_aValue.m_nDouble);
+ break;
+ case DataType::DATE:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Date*>(m_aValue.m_pValue)));
+ break;
+ case DataType::TIME:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Time*>(m_aValue.m_pValue)));
+ break;
+ case DataType::TIMESTAMP:
+ nRet = static_cast<float>(dbtools::DBTypeConversion::toDouble(*static_cast<css::util::DateTime*>(m_aValue.m_pValue)));
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getDouble() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = float(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = static_cast<float>(m_aValue.m_uInt16);
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = static_cast<float>(m_aValue.m_nInt32);
+ else
+ nRet = static_cast<float>(m_aValue.m_uInt32);
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = static_cast<float>(m_aValue.m_nInt64);
+ else
+ nRet = static_cast<float>(m_aValue.m_uInt64);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+double ORowSetValue::getDouble() const
+{
+ double nRet = 0;
+ if(!m_bNull)
+ {
+ switch(getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ nRet = OUString::unacquired(&m_aValue.m_pString).toDouble();
+ break;
+ case DataType::FLOAT:
+ nRet = m_aValue.m_nFloat;
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ nRet = m_aValue.m_nDouble;
+ break;
+ case DataType::DATE:
+ nRet = dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Date*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIME:
+ nRet = dbtools::DBTypeConversion::toDouble(*static_cast<css::util::Time*>(m_aValue.m_pValue));
+ break;
+ case DataType::TIMESTAMP:
+ nRet = dbtools::DBTypeConversion::toDouble(*static_cast<css::util::DateTime*>(m_aValue.m_pValue));
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ case DataType::CLOB:
+ OSL_FAIL("getDouble() for this type is not allowed!");
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nRet = double(m_aValue.m_bBool);
+ break;
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt8;
+ else
+ nRet = m_aValue.m_uInt8;
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt16;
+ else
+ nRet = m_aValue.m_uInt16;
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt32;
+ else
+ nRet = m_aValue.m_uInt32;
+ break;
+ case DataType::BIGINT:
+ if ( m_bSigned )
+ nRet = m_aValue.m_nInt64;
+ else
+ nRet = m_aValue.m_uInt64;
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= nRet;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+Sequence<sal_Int8> ORowSetValue::getSequence() const
+{
+ Sequence<sal_Int8> aSeq;
+ if (!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::OBJECT:
+ case DataType::CLOB:
+ case DataType::BLOB:
+ {
+ Reference<XInputStream> xStream;
+ const Any aValue = makeAny();
+ if(aValue.hasValue())
+ {
+ Reference<XBlob> xBlob(aValue,UNO_QUERY);
+ if ( xBlob.is() )
+ xStream = xBlob->getBinaryStream();
+ else
+ {
+ Reference<XClob> xClob(aValue,UNO_QUERY);
+ if ( xClob.is() )
+ xStream = xClob->getCharacterStream();
+ }
+ if(xStream.is())
+ {
+ const sal_uInt32 nBytesToRead = 65535;
+ sal_uInt32 nRead;
+
+ do
+ {
+ css::uno::Sequence< sal_Int8 > aReadSeq;
+
+ nRead = xStream->readSomeBytes( aReadSeq, nBytesToRead );
+
+ if( nRead )
+ {
+ const sal_uInt32 nOldLength = aSeq.getLength();
+ aSeq.realloc( nOldLength + nRead );
+ memcpy( aSeq.getArray() + nOldLength, aReadSeq.getConstArray(), aReadSeq.getLength() );
+ }
+ }
+ while( nBytesToRead == nRead );
+ xStream->closeInput();
+ }
+ }
+ }
+ break;
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ {
+ aSeq = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(m_aValue.m_pString->buffer),
+ sizeof(sal_Unicode) * m_aValue.m_pString->length);
+ }
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ aSeq = *static_cast< Sequence<sal_Int8>*>(m_aValue.m_pValue);
+ break;
+ default:
+ {
+ Any aValue = makeAny();
+ aValue >>= aSeq;
+ break;
+ }
+ }
+ }
+ return aSeq;
+
+}
+
+css::util::Date ORowSetValue::getDate() const
+{
+ css::util::Date aValue;
+ if(!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aValue = DBTypeConversion::toDate(getString());
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aValue = DBTypeConversion::toDate(getDouble());
+ break;
+
+ case DataType::DATE:
+ aValue = *static_cast< css::util::Date*>(m_aValue.m_pValue);
+ break;
+ case DataType::TIMESTAMP:
+ {
+ css::util::DateTime* pDateTime = static_cast< css::util::DateTime*>(m_aValue.m_pValue);
+ aValue.Day = pDateTime->Day;
+ aValue.Month = pDateTime->Month;
+ aValue.Year = pDateTime->Year;
+ }
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ aValue = DBTypeConversion::toDate( double( getLong() ) );
+ break;
+
+ case DataType::BLOB:
+ case DataType::CLOB:
+ case DataType::OBJECT:
+ default:
+ OSL_ENSURE( false, "ORowSetValue::getDate: cannot retrieve the data!" );
+ [[fallthrough]];
+
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::TIME:
+ aValue = DBTypeConversion::toDate( double(0) );
+ break;
+ }
+ }
+ return aValue;
+}
+
+css::util::Time ORowSetValue::getTime() const
+{
+ css::util::Time aValue;
+ if(!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aValue = DBTypeConversion::toTime(getString());
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ aValue = DBTypeConversion::toTime(getDouble());
+ break;
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aValue = DBTypeConversion::toTime(getDouble());
+ break;
+ case DataType::TIMESTAMP:
+ {
+ css::util::DateTime* pDateTime = static_cast< css::util::DateTime*>(m_aValue.m_pValue);
+ aValue.NanoSeconds = pDateTime->NanoSeconds;
+ aValue.Seconds = pDateTime->Seconds;
+ aValue.Minutes = pDateTime->Minutes;
+ aValue.Hours = pDateTime->Hours;
+ }
+ break;
+ case DataType::TIME:
+ aValue = *static_cast< css::util::Time*>(m_aValue.m_pValue);
+ break;
+ default:
+ {
+ Any aAnyValue = makeAny();
+ aAnyValue >>= aValue;
+ break;
+ }
+ }
+ }
+ return aValue;
+}
+
+css::util::DateTime ORowSetValue::getDateTime() const
+{
+ css::util::DateTime aValue;
+ if(!m_bNull)
+ {
+ switch(m_eTypeKind)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ aValue = DBTypeConversion::toDateTime(getString());
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ aValue = DBTypeConversion::toDateTime(getDouble());
+ break;
+ case DataType::FLOAT:
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ aValue = DBTypeConversion::toDateTime(getDouble());
+ break;
+ case DataType::DATE:
+ {
+ css::util::Date* pDate = static_cast< css::util::Date*>(m_aValue.m_pValue);
+ aValue.Day = pDate->Day;
+ aValue.Month = pDate->Month;
+ aValue.Year = pDate->Year;
+ }
+ break;
+ case DataType::TIME:
+ {
+ css::util::Time* pTime = static_cast< css::util::Time*>(m_aValue.m_pValue);
+ aValue.NanoSeconds = pTime->NanoSeconds;
+ aValue.Seconds = pTime->Seconds;
+ aValue.Minutes = pTime->Minutes;
+ aValue.Hours = pTime->Hours;
+ }
+ break;
+ case DataType::TIMESTAMP:
+ aValue = *static_cast< css::util::DateTime*>(m_aValue.m_pValue);
+ break;
+ default:
+ {
+ Any aAnyValue = makeAny();
+ aAnyValue >>= aValue;
+ break;
+ }
+ }
+ }
+ return aValue;
+}
+
+void ORowSetValue::setSigned(bool _bMod)
+{
+ if ( m_bSigned == _bMod )
+ return;
+
+ m_bSigned = _bMod;
+ if ( m_bNull )
+ return;
+
+ sal_Int32 nType = m_eTypeKind;
+ switch(m_eTypeKind)
+ {
+ case DataType::TINYINT:
+ if ( m_bSigned )
+ (*this) = getInt8();
+ else
+ {
+ m_bSigned = !m_bSigned;
+ (*this) = getInt16();
+ m_bSigned = !m_bSigned;
+ }
+ break;
+ case DataType::SMALLINT:
+ if ( m_bSigned )
+ (*this) = getInt16();
+ else
+ {
+ m_bSigned = !m_bSigned;
+ (*this) = getInt32();
+ m_bSigned = !m_bSigned;
+ }
+ break;
+ case DataType::INTEGER:
+ if ( m_bSigned )
+ (*this) = getInt32();
+ else
+ {
+ m_bSigned = !m_bSigned;
+ (*this) = getLong();
+ m_bSigned = !m_bSigned;
+ }
+ break;
+ case DataType::BIGINT:
+ {
+ if ( m_bSigned )
+ {
+ auto nTmp = static_cast<sal_Int64>(m_aValue.m_uInt64);
+ m_aValue.m_nInt64 = nTmp;
+ }
+ else
+ {
+ auto nTmp = static_cast<sal_uInt64>(m_aValue.m_nInt64);
+ m_aValue.m_uInt64 = nTmp;
+ }
+ break;
+ }
+ }
+ m_eTypeKind = nType;
+}
+
+
+namespace detail
+{
+ class SAL_NO_VTABLE IValueSource
+ {
+ public:
+ virtual OUString getString() const = 0;
+ virtual bool getBoolean() const = 0;
+ virtual sal_Int8 getByte() const = 0;
+ virtual sal_Int16 getShort() const = 0;
+ virtual sal_Int32 getInt() const = 0;
+ virtual sal_Int64 getLong() const = 0;
+ virtual float getFloat() const = 0;
+ virtual double getDouble() const = 0;
+ virtual Date getDate() const = 0;
+ virtual css::util::Time getTime() const = 0;
+ virtual DateTime getTimestamp() const = 0;
+ virtual Sequence< sal_Int8 > getBytes() const = 0;
+ virtual Reference< XBlob > getBlob() const = 0;
+ virtual Reference< XClob > getClob() const = 0;
+ virtual Any getObject() const = 0;
+ virtual bool wasNull() const = 0;
+
+ virtual ~IValueSource() { }
+ };
+
+ namespace {
+
+ class RowValue : public IValueSource
+ {
+ public:
+ RowValue( const Reference< XRow >& _xRow, const sal_Int32 _nPos )
+ :m_xRow( _xRow )
+ ,m_nPos( _nPos )
+ {
+ }
+
+ // IValueSource
+ virtual OUString getString() const override { return m_xRow->getString( m_nPos ); };
+ virtual bool getBoolean() const override { return m_xRow->getBoolean( m_nPos ); };
+ virtual sal_Int8 getByte() const override { return m_xRow->getByte( m_nPos ); };
+ virtual sal_Int16 getShort() const override { return m_xRow->getShort( m_nPos ); }
+ virtual sal_Int32 getInt() const override { return m_xRow->getInt( m_nPos ); }
+ virtual sal_Int64 getLong() const override { return m_xRow->getLong( m_nPos ); }
+ virtual float getFloat() const override { return m_xRow->getFloat( m_nPos ); };
+ virtual double getDouble() const override { return m_xRow->getDouble( m_nPos ); };
+ virtual Date getDate() const override { return m_xRow->getDate( m_nPos ); };
+ virtual css::util::Time getTime() const override { return m_xRow->getTime( m_nPos ); };
+ virtual DateTime getTimestamp() const override { return m_xRow->getTimestamp( m_nPos ); };
+ virtual Sequence< sal_Int8 > getBytes() const override { return m_xRow->getBytes( m_nPos ); };
+ virtual Reference< XBlob > getBlob() const override { return m_xRow->getBlob( m_nPos ); };
+ virtual Reference< XClob > getClob() const override { return m_xRow->getClob( m_nPos ); };
+ virtual Any getObject() const override { return m_xRow->getObject( m_nPos ,nullptr); };
+ virtual bool wasNull() const override { return m_xRow->wasNull( ); };
+
+ private:
+ const Reference< XRow > m_xRow;
+ const sal_Int32 m_nPos;
+ };
+
+ class ColumnValue : public IValueSource
+ {
+ public:
+ explicit ColumnValue( const Reference< XColumn >& _rxColumn )
+ :m_xColumn( _rxColumn )
+ {
+ }
+
+ // IValueSource
+ virtual OUString getString() const override { return m_xColumn->getString(); };
+ virtual bool getBoolean() const override { return m_xColumn->getBoolean(); };
+ virtual sal_Int8 getByte() const override { return m_xColumn->getByte(); };
+ virtual sal_Int16 getShort() const override { return m_xColumn->getShort(); }
+ virtual sal_Int32 getInt() const override { return m_xColumn->getInt(); }
+ virtual sal_Int64 getLong() const override { return m_xColumn->getLong(); }
+ virtual float getFloat() const override { return m_xColumn->getFloat(); };
+ virtual double getDouble() const override { return m_xColumn->getDouble(); };
+ virtual Date getDate() const override { return m_xColumn->getDate(); };
+ virtual css::util::Time getTime() const override { return m_xColumn->getTime(); };
+ virtual DateTime getTimestamp() const override { return m_xColumn->getTimestamp(); };
+ virtual Sequence< sal_Int8 > getBytes() const override { return m_xColumn->getBytes(); };
+ virtual Reference< XBlob > getBlob() const override { return m_xColumn->getBlob(); };
+ virtual Reference< XClob > getClob() const override { return m_xColumn->getClob(); };
+ virtual Any getObject() const override { return m_xColumn->getObject( nullptr ); };
+ virtual bool wasNull() const override { return m_xColumn->wasNull( ); };
+
+ private:
+ const Reference< XColumn > m_xColumn;
+ };
+
+ }
+}
+
+
+void ORowSetValue::fill( const sal_Int32 _nType, const Reference< XColumn >& _rxColumn )
+{
+ detail::ColumnValue aColumnValue( _rxColumn );
+ impl_fill( _nType, true, aColumnValue );
+}
+
+
+void ORowSetValue::fill( sal_Int32 _nPos, sal_Int32 _nType, bool _bNullable, const Reference< XRow>& _xRow )
+{
+ detail::RowValue aRowValue( _xRow, _nPos );
+ impl_fill( _nType, _bNullable, aRowValue );
+}
+
+
+void ORowSetValue::fill(sal_Int32 _nPos,
+ sal_Int32 _nType,
+ const css::uno::Reference< css::sdbc::XRow>& _xRow)
+{
+ fill(_nPos,_nType,true,_xRow);
+}
+
+
+void ORowSetValue::impl_fill( const sal_Int32 _nType, bool _bNullable, const detail::IValueSource& _rValueSource )
+{
+ switch(_nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::LONGVARCHAR:
+ (*this) = _rValueSource.getString();
+ break;
+ case DataType::BIGINT:
+ if ( isSigned() )
+ (*this) = _rValueSource.getLong();
+ else
+ // TODO: this is rather horrible performance-wise
+ // but fixing it needs extending the css::sdbc::XRow API
+ // to have a getULong(), and needs updating all drivers :-|
+ // When doing that, add getUByte, getUShort, getUInt for symmetry/completeness
+ (*this) = _rValueSource.getString().toUInt64();
+ break;
+ case DataType::FLOAT:
+ (*this) = _rValueSource.getFloat();
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ (*this) = _rValueSource.getDouble();
+ break;
+ case DataType::DATE:
+ (*this) = _rValueSource.getDate();
+ break;
+ case DataType::TIME:
+ (*this) = _rValueSource.getTime();
+ break;
+ case DataType::TIMESTAMP:
+ (*this) = _rValueSource.getTimestamp();
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ (*this) = _rValueSource.getBytes();
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ (*this) = _rValueSource.getBoolean();
+ break;
+ case DataType::TINYINT:
+ if ( isSigned() )
+ (*this) = _rValueSource.getByte();
+ else
+ (*this) = _rValueSource.getShort();
+ break;
+ case DataType::SMALLINT:
+ if ( isSigned() )
+ (*this) = _rValueSource.getShort();
+ else
+ (*this) = _rValueSource.getInt();
+ break;
+ case DataType::INTEGER:
+ if ( isSigned() )
+ (*this) = _rValueSource.getInt();
+ else
+ (*this) = _rValueSource.getLong();
+ break;
+ case DataType::CLOB:
+ (*this) = css::uno::Any(_rValueSource.getClob());
+ setTypeKind(DataType::CLOB);
+ break;
+ case DataType::BLOB:
+ (*this) = css::uno::Any(_rValueSource.getBlob());
+ setTypeKind(DataType::BLOB);
+ break;
+ case DataType::OTHER:
+ (*this) = _rValueSource.getObject();
+ setTypeKind(DataType::OTHER);
+ break;
+ default:
+ SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported type!" );
+ (*this) = _rValueSource.getObject();
+ break;
+ }
+ if ( _bNullable && _rValueSource.wasNull() )
+ setNull();
+ setTypeKind(_nType);
+}
+
+void ORowSetValue::fill(const Any& _rValue)
+{
+ switch (_rValue.getValueType().getTypeClass())
+ {
+ case TypeClass_VOID:
+ setNull(); break;
+ case TypeClass_BOOLEAN:
+ {
+ bool bValue( false );
+ _rValue >>= bValue;
+ (*this) = bValue;
+ break;
+ }
+ case TypeClass_CHAR:
+ {
+ sal_Unicode aDummy(0);
+ _rValue >>= aDummy;
+ (*this) = OUString(aDummy);
+ break;
+ }
+ case TypeClass_STRING:
+ {
+ OUString sDummy;
+ _rValue >>= sDummy;
+ (*this) = sDummy;
+ break;
+ }
+ case TypeClass_FLOAT:
+ {
+ float aDummy(0.0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_DOUBLE:
+ {
+ double aDummy(0.0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_BYTE:
+ {
+ sal_Int8 aDummy(0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_SHORT:
+ {
+ sal_Int16 aDummy(0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_UNSIGNED_SHORT:
+ {
+ sal_uInt16 nValue(0);
+ _rValue >>= nValue;
+ (*this) = nValue;
+ break;
+ }
+ case TypeClass_LONG:
+ {
+ sal_Int32 aDummy(0);
+ _rValue >>= aDummy;
+ (*this) = aDummy;
+ break;
+ }
+ case TypeClass_UNSIGNED_LONG:
+ {
+ sal_uInt32 nValue(0);
+ _rValue >>= nValue;
+ (*this) = static_cast<sal_Int64>(nValue);
+ setSigned(false);
+ break;
+ }
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue(0);
+ _rValue >>= nValue;
+ (*this) = nValue;
+ break;
+ }
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ sal_uInt64 nValue(0);
+ _rValue >>= nValue;
+ (*this) = nValue;
+ setSigned(false);
+ break;
+ }
+ case TypeClass_ENUM:
+ {
+ sal_Int32 enumValue( 0 );
+ ::cppu::enum2int( enumValue, _rValue );
+ (*this) = enumValue;
+ }
+ break;
+
+ case TypeClass_SEQUENCE:
+ {
+ Sequence<sal_Int8> aDummy;
+ if ( _rValue >>= aDummy )
+ (*this) = aDummy;
+ else
+ SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported sequence type!" );
+ break;
+ }
+
+ case TypeClass_STRUCT:
+ {
+ css::util::Date aDate;
+ css::util::Time aTime;
+ css::util::DateTime aDateTime;
+ if ( _rValue >>= aDate )
+ {
+ (*this) = aDate;
+ }
+ else if ( _rValue >>= aTime )
+ {
+ (*this) = aTime;
+ }
+ else if ( _rValue >>= aDateTime )
+ {
+ (*this) = aDateTime;
+ }
+ else
+ SAL_WARN( "connectivity.commontools", "ORowSetValue::fill: unsupported structure!" );
+
+ break;
+ }
+ case TypeClass_INTERFACE:
+ {
+ Reference< XClob > xClob;
+ if ( _rValue >>= xClob )
+ {
+ (*this) = _rValue;
+ setTypeKind(DataType::CLOB);
+ }
+ else
+ {
+ Reference< XBlob > xBlob;
+ if ( _rValue >>= xBlob )
+ {
+ (*this) = _rValue;
+ setTypeKind(DataType::BLOB);
+ }
+ else
+ {
+ (*this) = _rValue;
+ }
+ }
+ }
+ break;
+
+ default:
+ SAL_WARN( "connectivity.commontools","Unknown type");
+ break;
+ }
+}
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/ParameterSubstitution.cxx b/connectivity/source/commontools/ParameterSubstitution.cxx
new file mode 100644
index 000000000..ca96cf331
--- /dev/null
+++ b/connectivity/source/commontools/ParameterSubstitution.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <ParameterSubstitution.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+namespace connectivity
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star;
+
+ ParameterSubstitution::ParameterSubstitution(const css::uno::Reference< css::uno::XComponentContext >& _rxContext ) : m_xContext(_rxContext)
+ {
+ }
+ void SAL_CALL ParameterSubstitution::initialize( const uno::Sequence< uno::Any >& _aArguments )
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ comphelper::SequenceAsHashMap aArgs(_aArguments);
+ uno::Reference< sdbc::XConnection > xConnection;
+ xConnection = aArgs.getUnpackedValueOrDefault("ActiveConnection",xConnection);
+ m_xConnection = xConnection;
+ }
+
+ OUString SAL_CALL ParameterSubstitution::getImplementationName( )
+ {
+ return "org.openoffice.comp.helper.ParameterSubstitution";
+ }
+
+ sal_Bool SAL_CALL ParameterSubstitution::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL ParameterSubstitution::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.sdb.ParameterSubstitution" };
+ }
+
+
+ OUString SAL_CALL ParameterSubstitution::substituteVariables( const OUString& _sText, sal_Bool /*bSubstRequired*/ )
+ {
+ OUString sRet = _sText;
+ uno::Reference< sdbc::XConnection > xConnection = m_xConnection;
+ if ( xConnection.is() )
+ {
+ try
+ {
+ OSQLParser aParser( m_xContext );
+ OUString sErrorMessage;
+ std::unique_ptr<OSQLParseNode> pNode = aParser.parseTree(sErrorMessage,_sText);
+ if(pNode)
+ { // special handling for parameters
+ OSQLParseNode::substituteParameterNames(pNode.get());
+ OUString sNewSql;
+ pNode->parseNodeToStr( sNewSql, xConnection );
+ sRet = sNewSql;
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ return sRet;
+ }
+
+ OUString SAL_CALL ParameterSubstitution::reSubstituteVariables( const OUString& _sText )
+ {
+ return _sText;
+ }
+
+ OUString SAL_CALL ParameterSubstitution::getSubstituteVariableValue( const OUString& /*variable*/ )
+ {
+ throw container::NoSuchElementException();
+ }
+
+
+} // connectivity
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_dbtools_ParameterSubstitution_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new connectivity::ParameterSubstitution(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/RowFunctionParser.cxx b/connectivity/source/commontools/RowFunctionParser.cxx
new file mode 100644
index 000000000..21f5e638a
--- /dev/null
+++ b/connectivity/source/commontools/RowFunctionParser.cxx
@@ -0,0 +1,441 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+// Makes parser a static resource,
+// we're synchronized externally.
+// But watch out, the parser might have
+// state not visible to this code!
+#define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
+
+#if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
+#include <typeinfo>
+#define BOOST_SPIRIT_DEBUG
+#endif
+#include <boost/spirit/include/classic_core.hpp>
+#include <RowFunctionParser.hxx>
+#include <rtl/ustring.hxx>
+
+
+#if (OSL_DEBUG_LEVEL > 0)
+#include <iostream>
+#endif
+#include <algorithm>
+#include <stack>
+
+namespace connectivity
+{
+using namespace com::sun::star;
+
+namespace
+{
+
+
+// EXPRESSION NODES
+
+
+class ConstantValueExpression : public ExpressionNode
+{
+ ORowSetValueDecoratorRef maValue;
+
+public:
+
+ explicit ConstantValueExpression( ORowSetValueDecoratorRef const & rValue ) :
+ maValue( rValue )
+ {
+ }
+ virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
+ {
+ return maValue;
+ }
+ virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
+ {
+ }
+};
+
+
+/** ExpressionNode implementation for unary
+ function over two ExpressionNodes
+ */
+class BinaryFunctionExpression : public ExpressionNode
+{
+ const ExpressionFunct meFunct;
+ std::shared_ptr<ExpressionNode> mpFirstArg;
+ std::shared_ptr<ExpressionNode> mpSecondArg;
+
+public:
+
+ BinaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rFirstArg, const std::shared_ptr<ExpressionNode>& rSecondArg ) :
+ meFunct( eFunct ),
+ mpFirstArg( rFirstArg ),
+ mpSecondArg( rSecondArg )
+ {
+ }
+ virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
+ {
+ ORowSetValueDecoratorRef aRet;
+ switch(meFunct)
+ {
+ case ExpressionFunct::Equation:
+ aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue() );
+ break;
+ case ExpressionFunct::And:
+ aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool() );
+ break;
+ case ExpressionFunct::Or:
+ aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool() );
+ break;
+ default:
+ break;
+ }
+ return aRet;
+ }
+ virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
+ {
+ switch(meFunct)
+ {
+ case ExpressionFunct::Equation:
+ (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+
+// FUNCTION PARSER
+
+
+typedef const char* StringIteratorT;
+
+struct ParserContext
+{
+ typedef std::stack< std::shared_ptr<ExpressionNode> > OperandStack;
+
+ // stores a stack of not-yet-evaluated operands. This is used
+ // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
+ // arguments from. If all arguments to an operator are constant,
+ // the operator pushes a precalculated result on the stack, and
+ // a composite ExpressionNode otherwise.
+ OperandStack maOperandStack;
+};
+
+typedef std::shared_ptr< ParserContext > ParserContextSharedPtr;
+
+/** Generate apriori constant value
+ */
+
+class ConstantFunctor
+{
+ ParserContextSharedPtr mpContext;
+
+public:
+
+ explicit ConstantFunctor( const ParserContextSharedPtr& rContext ) :
+ mpContext( rContext )
+ {
+ }
+ void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
+ {
+ OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
+ mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( sVal ) ) );
+ }
+};
+
+/** Generate parse-dependent-but-then-constant value
+ */
+class IntConstantFunctor
+{
+ ParserContextSharedPtr mpContext;
+
+public:
+ explicit IntConstantFunctor( const ParserContextSharedPtr& rContext ) :
+ mpContext( rContext )
+ {
+ }
+ void operator()( sal_Int32 n ) const
+ {
+ mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( n ) ) );
+ }
+};
+
+/** Implements a binary function over two ExpressionNodes
+
+ @tpl Generator
+ Generator functor, to generate an ExpressionNode of
+ appropriate type
+
+ */
+class BinaryFunctionFunctor
+{
+ const ExpressionFunct meFunct;
+ ParserContextSharedPtr mpContext;
+
+public:
+
+ BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
+ meFunct( eFunct ),
+ mpContext( rContext )
+ {
+ }
+
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+ ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
+
+ if( rNodeStack.size() < 2 )
+ throw ParseError( "Not enough arguments for binary operator" );
+
+ // retrieve arguments
+ std::shared_ptr<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+ std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ // create combined ExpressionNode
+ auto pNode = std::make_shared<BinaryFunctionExpression>( meFunct, pFirstArg, pSecondArg );
+ // check for constness
+ rNodeStack.push( pNode );
+ }
+};
+/** ExpressionNode implementation for unary
+ function over one ExpressionNode
+ */
+class UnaryFunctionExpression : public ExpressionNode
+{
+ std::shared_ptr<ExpressionNode> mpArg;
+
+public:
+ explicit UnaryFunctionExpression( const std::shared_ptr<ExpressionNode>& rArg ) :
+ mpArg( rArg )
+ {
+ }
+ virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override
+ {
+ return _aRow[mpArg->evaluate(_aRow )->getValue().getUInt32()];
+ }
+ virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override
+ {
+ }
+};
+
+class UnaryFunctionFunctor
+{
+ ParserContextSharedPtr mpContext;
+
+public:
+
+ explicit UnaryFunctionFunctor(const ParserContextSharedPtr& rContext)
+ : mpContext(rContext)
+ {
+ }
+ void operator()( StringIteratorT, StringIteratorT ) const
+ {
+
+ ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
+
+ if( rNodeStack.empty() )
+ throw ParseError( "Not enough arguments for unary operator" );
+
+ // retrieve arguments
+ std::shared_ptr<ExpressionNode> pArg( std::move(rNodeStack.top()) );
+ rNodeStack.pop();
+
+ rNodeStack.push( std::make_shared<UnaryFunctionExpression>( pArg ) );
+ }
+};
+
+/* This class implements the following grammar (more or
+ less literally written down below, only slightly
+ obfuscated by the parser actions):
+
+ basic_expression =
+ number |
+ '(' additive_expression ')'
+
+ unary_expression =
+ basic_expression
+
+ multiplicative_expression =
+ unary_expression ( ( '*' unary_expression )* |
+ ( '/' unary_expression )* )
+
+ additive_expression =
+ multiplicative_expression ( ( '+' multiplicative_expression )* |
+ ( '-' multiplicative_expression )* )
+
+ */
+class ExpressionGrammar : public ::boost::spirit::classic::grammar< ExpressionGrammar >
+{
+public:
+ /** Create an arithmetic expression grammar
+
+ @param rParserContext
+ Contains context info for the parser
+ */
+ explicit ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
+ mpParserContext( rParserContext )
+ {
+ }
+
+ template< typename ScannerT > class definition
+ {
+ public:
+ // grammar definition
+ explicit definition( const ExpressionGrammar& self )
+ {
+ using ::boost::spirit::classic::space_p;
+ using ::boost::spirit::classic::range_p;
+ using ::boost::spirit::classic::lexeme_d;
+ using ::boost::spirit::classic::ch_p;
+ using ::boost::spirit::classic::int_p;
+ using ::boost::spirit::classic::as_lower_d;
+ using ::boost::spirit::classic::strlit;
+ using ::boost::spirit::classic::inhibit_case;
+
+
+ typedef inhibit_case<strlit<> > token_t;
+ token_t COLUMN = as_lower_d[ "column" ];
+ token_t OR_ = as_lower_d[ "or" ];
+ token_t AND_ = as_lower_d[ "and" ];
+
+ integer =
+ int_p
+ [IntConstantFunctor(self.getContext())];
+
+ argument =
+ integer
+ | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
+ [ ConstantFunctor(self.getContext()) ]
+ ;
+
+ unaryFunction =
+ (COLUMN >> '(' >> integer >> ')' )
+ [ UnaryFunctionFunctor( self.getContext()) ]
+ ;
+
+ assignment =
+ unaryFunction >> ch_p('=') >> argument
+ [ BinaryFunctionFunctor( ExpressionFunct::Equation, self.getContext()) ]
+ ;
+
+ andExpression =
+ assignment
+ | ( '(' >> orExpression >> ')' )
+ | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ExpressionFunct::And, self.getContext()) ]
+ ;
+
+ orExpression =
+ andExpression
+ | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ExpressionFunct::Or, self.getContext()) ]
+ ;
+
+ basicExpression =
+ orExpression
+ ;
+
+ BOOST_SPIRIT_DEBUG_RULE(basicExpression);
+ BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
+ BOOST_SPIRIT_DEBUG_RULE(assignment);
+ BOOST_SPIRIT_DEBUG_RULE(argument);
+ BOOST_SPIRIT_DEBUG_RULE(integer);
+ BOOST_SPIRIT_DEBUG_RULE(orExpression);
+ BOOST_SPIRIT_DEBUG_RULE(andExpression);
+ }
+
+ const ::boost::spirit::classic::rule< ScannerT >& start() const
+ {
+ return basicExpression;
+ }
+
+ private:
+ // the constituents of the Spirit arithmetic expression grammar.
+ // For the sake of readability, without 'ma' prefix.
+ ::boost::spirit::classic::rule< ScannerT > basicExpression;
+ ::boost::spirit::classic::rule< ScannerT > unaryFunction;
+ ::boost::spirit::classic::rule< ScannerT > assignment;
+ ::boost::spirit::classic::rule< ScannerT > integer,argument;
+ ::boost::spirit::classic::rule< ScannerT > orExpression,andExpression;
+ };
+
+ const ParserContextSharedPtr& getContext() const
+ {
+ return mpParserContext;
+ }
+
+private:
+ ParserContextSharedPtr mpParserContext; // might get modified during parsing
+};
+
+const ParserContextSharedPtr& getParserContext()
+{
+ static ParserContextSharedPtr lcl_parserContext = std::make_shared<ParserContext>();
+
+ // clear node stack (since we reuse the static object, that's
+ // the whole point here)
+ while( !lcl_parserContext->maOperandStack.empty() )
+ lcl_parserContext->maOperandStack.pop();
+
+ return lcl_parserContext;
+}
+
+}
+
+std::shared_ptr<ExpressionNode> const & FunctionParser::parseFunction( const OUString& _sFunction)
+{
+ // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
+ // gives better conversion robustness here (we might want to map space
+ // etc. to ASCII space here)
+ const OString& rAsciiFunction(
+ OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
+
+ StringIteratorT aStart( rAsciiFunction.getStr() );
+ StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
+
+ // static parser context, because the actual
+ // Spirit parser is also a static object
+ ParserContextSharedPtr pContext = getParserContext();
+
+ ExpressionGrammar aExpressionGrammer( pContext );
+
+ const ::boost::spirit::classic::parse_info<StringIteratorT> aParseInfo(
+ ::boost::spirit::classic::parse( aStart,
+ aEnd,
+ aExpressionGrammer,
+ ::boost::spirit::classic::space_p ) );
+
+#if (OSL_DEBUG_LEVEL > 0)
+ std::cout.flush(); // needed to keep stdout and cout in sync
+#endif
+
+ // input fully congested by the parser?
+ if( !aParseInfo.full )
+ throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
+
+ // parser's state stack now must contain exactly _one_ ExpressionNode,
+ // which represents our formula.
+ if( pContext->maOperandStack.size() != 1 )
+ throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
+
+ return pContext->maOperandStack.top();
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TColumnsHelper.cxx b/connectivity/source/commontools/TColumnsHelper.cxx
new file mode 100644
index 000000000..f81eca9f0
--- /dev/null
+++ b/connectivity/source/commontools/TColumnsHelper.cxx
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+using namespace ::comphelper;
+
+
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace connectivity
+{
+ class OColumnsHelperImpl
+ {
+ public:
+ explicit OColumnsHelperImpl(bool _bCase)
+ : m_aColumnInfo(_bCase)
+ {
+ }
+ ColumnInformationMap m_aColumnInfo;
+ };
+}
+
+OColumnsHelper::OColumnsHelper( ::cppu::OWeakObject& _rParent
+ ,bool _bCase
+ ,::osl::Mutex& _rMutex
+ ,const ::std::vector< OUString> &_rVector
+ ,bool _bUseHardRef
+ ) : OCollection(_rParent,_bCase,_rMutex,_rVector,false,_bUseHardRef)
+ ,m_pTable(nullptr)
+{
+}
+
+OColumnsHelper::~OColumnsHelper()
+{
+}
+
+
+sdbcx::ObjectType OColumnsHelper::createObject(const OUString& _rName)
+{
+ OSL_ENSURE(m_pTable,"NO Table set. Error!");
+ Reference<XConnection> xConnection = m_pTable->getConnection();
+
+ if ( !m_pImpl )
+ m_pImpl.reset(new OColumnsHelperImpl(isCaseSensitive()));
+
+ bool bQueryInfo = true;
+ bool bAutoIncrement = false;
+ bool bIsCurrency = false;
+ sal_Int32 nDataType = DataType::OTHER;
+
+ ColumnInformationMap::const_iterator aFind = m_pImpl->m_aColumnInfo.find(_rName);
+ if ( aFind == m_pImpl->m_aColumnInfo.end() ) // we have to fill it
+ {
+ OUString sComposedName = ::dbtools::composeTableNameForSelect( xConnection, m_pTable );
+ collectColumnInformation(xConnection,sComposedName,u"*" ,m_pImpl->m_aColumnInfo);
+ aFind = m_pImpl->m_aColumnInfo.find(_rName);
+ }
+ if ( aFind != m_pImpl->m_aColumnInfo.end() )
+ {
+ bQueryInfo = false;
+ bAutoIncrement = aFind->second.first.first;
+ bIsCurrency = aFind->second.first.second;
+ nDataType = aFind->second.second;
+ } // if ( aFind != m_pImpl->m_aColumnInfo.end() )
+
+ sdbcx::ObjectType xRet;
+ const ColumnDesc* pColDesc = m_pTable->getColumnDescription(_rName);
+ if ( pColDesc )
+ {
+ Reference<XPropertySet> xPr = m_pTable;
+ const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xPr);
+ sal_Int32 nField11 = pColDesc->nField11;
+ if ( nField11 != ColumnValue::NO_NULLS && xPrimaryKeyColumns.is() && xPrimaryKeyColumns->hasByName(_rName) )
+ {
+ nField11 = ColumnValue::NO_NULLS;
+ } // if ( xKeys.is() )
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aCatalog, aSchema, aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= aCatalog;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+ rtl::Reference<connectivity::sdbcx::OColumn> pRet = new connectivity::sdbcx::OColumn(_rName,
+ pColDesc->aField6,
+ pColDesc->sField13,
+ pColDesc->sField12,
+ nField11,
+ pColDesc->nField7,
+ pColDesc->nField9,
+ pColDesc->nField5,
+ bAutoIncrement,
+ false,
+ bIsCurrency,
+ isCaseSensitive(),
+ aCatalog,
+ aSchema,
+ aTable);
+
+ xRet = pRet;
+ }
+ else
+ {
+
+ xRet = ::dbtools::createSDBCXColumn( m_pTable,
+ xConnection,
+ _rName,
+ isCaseSensitive(),
+ bQueryInfo,
+ bAutoIncrement,
+ bIsCurrency,
+ nDataType);
+ }
+ return xRet;
+}
+
+
+void OColumnsHelper::impl_refresh()
+{
+ if ( m_pTable )
+ {
+ m_pImpl->m_aColumnInfo.clear();
+ m_pTable->refreshColumns();
+ }
+}
+
+Reference< XPropertySet > OColumnsHelper::createDescriptor()
+{
+ return new OColumn(true);
+}
+
+// XAppend
+sdbcx::ObjectType OColumnsHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_pTable,"OColumnsHelper::appendByDescriptor: Table is null!");
+ if ( !m_pTable || m_pTable->isNew() )
+ return cloneDescriptor( descriptor );
+
+ Reference<XDatabaseMetaData> xMetaData = m_pTable->getConnection()->getMetaData();
+ OUString aSql = "ALTER TABLE " +
+ ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true ) +
+ " ADD " +
+ ::dbtools::createStandardColumnPart(descriptor,m_pTable->getConnection(),nullptr,m_pTable->getTypeCreatePattern());
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ return createObject( _rForName );
+}
+
+// XDrop
+void OColumnsHelper::dropObject(sal_Int32 /*_nPos*/, const OUString& _sElementName)
+{
+ OSL_ENSURE(m_pTable,"OColumnsHelper::dropByName: Table is null!");
+ if ( !m_pTable || m_pTable->isNew() )
+ return;
+
+ Reference<XDatabaseMetaData> xMetaData = m_pTable->getConnection()->getMetaData();
+ OUString aQuote = xMetaData->getIdentifierQuoteString( );
+ OUString aSql = "ALTER TABLE " +
+ ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true ) +
+ " DROP " +
+ ::dbtools::quoteName( aQuote,_sElementName);
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TConnection.cxx b/connectivity/source/commontools/TConnection.cxx
new file mode 100644
index 000000000..f35e8ca19
--- /dev/null
+++ b/connectivity/source/commontools/TConnection.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TConnection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+
+using namespace connectivity;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::beans;
+using namespace ::osl;
+
+
+OMetaConnection::OMetaConnection()
+ : OMetaConnection_BASE(m_aMutex)
+ , m_nTextEncoding(RTL_TEXTENCODING_MS_1252)
+{
+}
+
+void OMetaConnection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_xMetaData = WeakReference< XDatabaseMetaData>();
+ for (auto const& statement : m_aStatements)
+ {
+ try
+ {
+ Reference< XInterface > xStatement( statement.get() );
+ ::comphelper::disposeComponent( xStatement );
+ }
+ catch (const DisposedException&)
+ {
+ }
+ }
+ m_aStatements.clear();
+}
+//XUnoTunnel
+sal_Int64 SAL_CALL OMetaConnection::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence< sal_Int8 > & OMetaConnection::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+::dbtools::OPropertyMap& OMetaConnection::getPropMap()
+{
+ static ::dbtools::OPropertyMap s_aPropertyNameMap;
+ return s_aPropertyNameMap;
+}
+
+void OMetaConnection::throwGenericSQLException(TranslateId pErrorResourceId, const Reference< XInterface>& _xContext )
+{
+ OUString sErrorMessage;
+ if (pErrorResourceId)
+ sErrorMessage = m_aResources.getResourceString(pErrorResourceId);
+ Reference< XInterface> xContext = _xContext;
+ if ( !xContext.is() )
+ xContext = *this;
+ ::dbtools::throwGenericSQLException( sErrorMessage, xContext);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TDatabaseMetaDataBase.cxx b/connectivity/source/commontools/TDatabaseMetaDataBase.cxx
new file mode 100644
index 000000000..0e81e71cf
--- /dev/null
+++ b/connectivity/source/commontools/TDatabaseMetaDataBase.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 <TDatabaseMetaDataBase.hxx>
+#include <RowFunctionParser.hxx>
+
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/evtlistenerhlp.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <connectivity/dbexception.hxx>
+#include <sal/macros.h>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::beans;
+using namespace comphelper;
+using namespace connectivity;
+
+
+ODatabaseMetaDataBase::ODatabaseMetaDataBase(const Reference< XConnection >& _rxConnection,const Sequence< PropertyValue >& _rInfo)
+ : m_aConnectionInfo(_rInfo)
+ ,m_isCatalogAtStart(false,false)
+ ,m_sCatalogSeparator(false,OUString())
+ ,m_sIdentifierQuoteString(false,OUString())
+ ,m_supportsCatalogsInTableDefinitions(false,false)
+ ,m_supportsSchemasInTableDefinitions(false,false)
+ ,m_supportsCatalogsInDataManipulation(false,false)
+ ,m_supportsSchemasInDataManipulation(false,false)
+ ,m_supportsMixedCaseQuotedIdentifiers(false,false)
+ ,m_supportsAlterTableWithAddColumn(false,false)
+ ,m_supportsAlterTableWithDropColumn(false,false)
+ ,m_MaxStatements(false,0)
+ ,m_MaxTablesInSelect(false,0)
+ ,m_storesMixedCaseQuotedIdentifiers(false,false)
+ , m_xConnection(_rxConnection)
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ m_xListenerHelper = new OEventListenerHelper(this);
+ Reference<XComponent> xCom(m_xConnection,UNO_QUERY);
+ if(xCom.is())
+ xCom->addEventListener(m_xListenerHelper);
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+ODatabaseMetaDataBase::~ODatabaseMetaDataBase()
+{
+}
+
+
+Sequence< PropertyValue > SAL_CALL ODatabaseMetaDataBase::getConnectionInfo( )
+{
+ return m_aConnectionInfo;
+}
+
+
+void SAL_CALL ODatabaseMetaDataBase::disposing( const EventObject& /*Source*/ )
+{
+ // cut off all references to the connection
+m_xConnection.clear();
+m_xListenerHelper.clear();
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getTypeInfo( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_aTypeInfoRows.empty() )
+ {
+ Reference< XResultSet > xRet = impl_getTypeInfo_throw();
+ Reference< XRow > xRow(xRet,UNO_QUERY);
+ ::comphelper::SequenceAsHashMap aMap(m_aConnectionInfo);
+ Sequence< Any > aTypeInfoSettings;
+ aTypeInfoSettings = aMap.getUnpackedValueOrDefault("TypeInfoSettings",aTypeInfoSettings);
+
+ if ( xRow.is() )
+ {
+ static const sal_Int32 pTypes[] = {
+ DataType::VARCHAR
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ ,DataType::VARCHAR
+ ,DataType::VARCHAR
+ ,DataType::VARCHAR
+ ,DataType::INTEGER
+ ,DataType::BOOLEAN
+ ,DataType::INTEGER
+ ,DataType::BOOLEAN
+ ,DataType::BOOLEAN
+ ,DataType::BOOLEAN
+ ,DataType::VARCHAR
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ ,DataType::INTEGER
+ };
+ std::vector<std::shared_ptr<ExpressionNode>> aConditions;
+ if ( aTypeInfoSettings.getLength() > 1 && ((aTypeInfoSettings.getLength() % 2) == 0) )
+ {
+ const Any* pIter = aTypeInfoSettings.getConstArray();
+ const Any* pEnd = pIter + aTypeInfoSettings.getLength();
+ try
+ {
+ for(;pIter != pEnd;++pIter)
+ aConditions.push_back(FunctionParser::parseFunction(::comphelper::getString(*pIter)));
+ }
+ catch(ParseError&)
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_FORMULA_WRONG));
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+ }
+
+ ::connectivity::ODatabaseMetaDataResultSet::ORows aTypeInfoRows;
+ while( xRet->next() )
+ {
+ ::connectivity::ODatabaseMetaDataResultSet::ORow aRow;
+ aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue());
+ const sal_Int32* pType = pTypes;
+ for (sal_Int32 i = 1; i <= sal_Int32(std::size(pTypes)); ++i,++pType)
+ {
+ ORowSetValue aValue;
+ aValue.fill(i,*pType,xRow);
+ aRow.push_back(new ORowSetValueDecorator(aValue));
+ }
+
+ std::vector<std::shared_ptr<ExpressionNode>>::iterator aIter = aConditions.begin();
+ std::vector<std::shared_ptr<ExpressionNode>>::const_iterator aEnd = aConditions.end();
+ for (; aIter != aEnd; ++aIter)
+ {
+ if ( (*aIter)->evaluate(aRow)->getValue().getBool() )
+ {
+ ++aIter;
+ (*aIter)->fill(aRow);
+ }
+ else
+ ++aIter;
+ }
+ aTypeInfoRows.push_back(aRow);
+ }
+ m_aTypeInfoRows = aTypeInfoRows;
+ }
+ }
+ rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo);
+ pResult->setRows(std::vector(m_aTypeInfoRows));
+ return pResult;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getExportedKeys(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eExportedKeys );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getImportedKeys(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eImportedKeys );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getPrimaryKeys(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::ePrimaryKeys );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getIndexInfo(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/,
+ sal_Bool /*unique*/, sal_Bool /*approximate*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eIndexInfo );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getBestRowIdentifier(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/, sal_Int32 /*scope*/,
+ sal_Bool /*nullable*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eBestRowIdentifier );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getCrossReference(
+ const Any& /*primaryCatalog*/, const OUString& /*primarySchema*/,
+ const OUString& /*primaryTable*/, const Any& /*foreignCatalog*/,
+ const OUString& /*foreignSchema*/, const OUString& /*foreignTable*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCrossReference );
+}
+
+Reference< XConnection > SAL_CALL ODatabaseMetaDataBase::getConnection( )
+{
+ return m_xConnection;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getProcedureColumns(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& /*procedureNamePattern*/, const OUString& /*columnNamePattern*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedureColumns );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getProcedures(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& /*procedureNamePattern*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedures );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getVersionColumns(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eVersionColumns );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getSchemas( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eSchemas );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getColumnPrivileges(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/,
+ const OUString& /*columnNamePattern*/ )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumnPrivileges );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getTablePrivileges(
+ const Any& /*catalog*/, const OUString& /*schema*/, const OUString& /*table*/)
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges );
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaDataBase::getCatalogs( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCatalogs );
+}
+
+OUString SAL_CALL ODatabaseMetaDataBase::getIdentifierQuoteString( )
+{
+ return callImplMethod(m_sIdentifierQuoteString,std::function<OUString(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getIdentifierQuoteString_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::isCatalogAtStart( )
+{
+ return callImplMethod(m_isCatalogAtStart,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_isCatalogAtStart_throw));
+}
+
+OUString SAL_CALL ODatabaseMetaDataBase::getCatalogSeparator( )
+{
+ return callImplMethod(m_sCatalogSeparator,std::function<OUString(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getCatalogSeparator_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsCatalogsInTableDefinitions( )
+{
+ return callImplMethod(m_supportsCatalogsInTableDefinitions,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsCatalogsInTableDefinitions_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsSchemasInTableDefinitions( )
+{
+ return callImplMethod(m_supportsSchemasInTableDefinitions,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsSchemasInTableDefinitions_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsCatalogsInDataManipulation( )
+{
+ return callImplMethod(m_supportsCatalogsInDataManipulation,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsCatalogsInDataManipulation_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsSchemasInDataManipulation( )
+{
+ return callImplMethod(m_supportsSchemasInDataManipulation,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsSchemasInDataManipulation_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsMixedCaseQuotedIdentifiers( )
+{
+ return callImplMethod(m_supportsMixedCaseQuotedIdentifiers,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsMixedCaseQuotedIdentifiers_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsAlterTableWithAddColumn( )
+{
+ return callImplMethod(m_supportsAlterTableWithAddColumn,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsAlterTableWithAddColumn_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::supportsAlterTableWithDropColumn( )
+{
+ return callImplMethod(m_supportsAlterTableWithDropColumn,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_supportsAlterTableWithDropColumn_throw));
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataBase::getMaxStatements( )
+{
+ return callImplMethod(m_MaxStatements,std::function<sal_Int32(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getMaxStatements_throw));
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaDataBase::getMaxTablesInSelect( )
+{
+ return callImplMethod(m_MaxTablesInSelect,std::function<sal_Int32(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_getMaxTablesInSelect_throw));
+}
+
+sal_Bool SAL_CALL ODatabaseMetaDataBase::storesMixedCaseQuotedIdentifiers( )
+{
+ return callImplMethod(m_storesMixedCaseQuotedIdentifiers,std::function<bool(ODatabaseMetaDataBase *)>(&ODatabaseMetaDataBase::impl_storesMixedCaseQuotedIdentifiers_throw));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TIndex.cxx b/connectivity/source/commontools/TIndex.cxx
new file mode 100644
index 000000000..f7f891308
--- /dev/null
+++ b/connectivity/source/commontools/TIndex.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TIndex.hxx>
+#include <TIndexColumns.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <connectivity/TTableHelper.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OIndexHelper::OIndexHelper( OTableHelper* _pTable) : connectivity::sdbcx::OIndex(true)
+ , m_pTable(_pTable)
+{
+ construct();
+ std::vector< OUString> aVector;
+ m_pColumns.reset(new OIndexColumns(this,m_aMutex,aVector));
+}
+
+OIndexHelper::OIndexHelper( OTableHelper* _pTable,
+ const OUString& Name,
+ const OUString& Catalog,
+ bool _isUnique,
+ bool _isPrimaryKeyIndex,
+ bool _isClustered
+ ) : connectivity::sdbcx::OIndex(Name,
+ Catalog,
+ _isUnique,
+ _isPrimaryKeyIndex,
+ _isClustered,true)
+ ,m_pTable(_pTable)
+{
+ construct();
+ refreshColumns();
+}
+
+
+void OIndexHelper::refreshColumns()
+{
+ if ( !m_pTable )
+ return;
+
+ std::vector< OUString> aVector;
+ if ( !isNew() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aSchema,aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Reference< XResultSet > xResult = m_pTable->getMetaData()->getIndexInfo(
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)),
+ aSchema,aTable,false,false);
+
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString aColName;
+ while( xResult->next() )
+ {
+ if ( xRow->getString(6) == m_Name )
+ {
+ aColName = xRow->getString(9);
+ if ( !xRow->wasNull() )
+ aVector.push_back(aColName);
+ }
+ }
+ }
+ }
+ if(m_pColumns)
+ m_pColumns->reFill(aVector);
+ else
+ m_pColumns.reset(new OIndexColumns(this,m_aMutex,aVector));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TIndexColumns.cxx b/connectivity/source/commontools/TIndexColumns.cxx
new file mode 100644
index 000000000..1db4426c1
--- /dev/null
+++ b/connectivity/source/commontools/TIndexColumns.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TIndexColumns.hxx>
+#include <sdbcx/VIndexColumn.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TIndex.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OIndexColumns::OIndexColumns( OIndexHelper* _pIndex,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector)
+ : connectivity::sdbcx::OCollection(*_pIndex,true,_rMutex,_rVector)
+ ,m_pIndex(_pIndex)
+{
+}
+
+sdbcx::ObjectType OIndexColumns::createObject(const OUString& _rName)
+{
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aCatalog, aSchema, aTable;
+ css::uno::Any Catalog(m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)));
+ Catalog >>= aCatalog;
+ m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pIndex->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Reference< XResultSet > xResult = m_pIndex->getTable()->getConnection()->getMetaData()->getIndexInfo(
+ Catalog, aSchema, aTable, false, false);
+
+ bool bAsc = true;
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ if(xRow->getString(9) == _rName)
+ bAsc = xRow->getString(10) != "D";
+ }
+ }
+
+ xResult = m_pIndex->getTable()->getConnection()->getMetaData()->getColumns(
+ Catalog, aSchema, aTable, _rName);
+
+ sdbcx::ObjectType xRet;
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ if ( xRow->getString(4) == _rName )
+ {
+ sal_Int32 nDataType = xRow->getInt(5);
+ OUString aTypeName(xRow->getString(6));
+ sal_Int32 nSize = xRow->getInt(7);
+ sal_Int32 nDec = xRow->getInt(9);
+ sal_Int32 nNull = xRow->getInt(11);
+ OUString aColumnDef(xRow->getString(13));
+
+ xRet = new OIndexColumn(bAsc,
+ _rName,
+ aTypeName,
+ aColumnDef,
+ nNull,
+ nSize,
+ nDec,
+ nDataType,
+ true,
+ aCatalog, aSchema, aTable);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+Reference< XPropertySet > OIndexColumns::createDescriptor()
+{
+ return new OIndexColumn(true);
+}
+
+void OIndexColumns::impl_refresh()
+{
+ m_pIndex->refreshColumns();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TIndexes.cxx b/connectivity/source/commontools/TIndexes.cxx
new file mode 100644
index 000000000..b0998b5b3
--- /dev/null
+++ b/connectivity/source/commontools/TIndexes.cxx
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/TIndexes.hxx>
+#include <TIndex.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XIndexAlteration.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/IndexType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ustrbuf.hxx>
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace cppu;
+
+
+OIndexesHelper::OIndexesHelper(OTableHelper* _pTable,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector
+ )
+ : OCollection(*_pTable,true,_rMutex,_rVector)
+ ,m_pTable(_pTable)
+{
+}
+
+
+sdbcx::ObjectType OIndexesHelper::createObject(const OUString& _rName)
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if ( !xConnection.is() )
+ return nullptr;
+
+ sdbcx::ObjectType xRet;
+ OUString aName,aQualifier;
+ sal_Int32 nLen = _rName.indexOf('.');
+ if ( nLen != -1 )
+ {
+ aQualifier = _rName.copy(0,nLen);
+ aName = _rName.copy(nLen+1);
+ }
+ else
+ aName = _rName;
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aSchema,aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Any aCatalog = m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME));
+ Reference< XResultSet > xResult = m_pTable->getMetaData()->getIndexInfo(aCatalog,aSchema,aTable,false,false);
+
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ bool bUnique = !xRow->getBoolean(4);
+ if((aQualifier.isEmpty() || xRow->getString(5) == aQualifier ) && xRow->getString(6) == aName)
+ {
+ sal_Int32 nClustered = xRow->getShort(7);
+ bool bPrimarKeyIndex = false;
+ xRow.clear();
+ xResult.clear();
+ try
+ {
+ xResult = m_pTable->getMetaData()->getPrimaryKeys(aCatalog,aSchema,aTable);
+ xRow.set(xResult,UNO_QUERY);
+
+ if ( xRow.is() && xResult->next() ) // there can be only one primary key
+ {
+ bPrimarKeyIndex = xRow->getString(6) == aName;
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ xRet = new OIndexHelper(m_pTable,aName,aQualifier,bUnique,
+ bPrimarKeyIndex,
+ nClustered == IndexType::CLUSTERED);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void OIndexesHelper::impl_refresh()
+{
+ m_pTable->refreshIndexes();
+}
+
+Reference< XPropertySet > OIndexesHelper::createDescriptor()
+{
+ return new OIndexHelper(m_pTable);
+}
+
+// XAppend
+sdbcx::ObjectType OIndexesHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if ( !xConnection.is() )
+ return nullptr;
+ if ( m_pTable->isNew() )
+ return cloneDescriptor( descriptor );
+
+ if ( m_pTable->getIndexService().is() )
+ {
+ m_pTable->getIndexService()->addIndex(m_pTable,descriptor);
+ }
+ else
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUStringBuffer aSql( "CREATE " );
+ OUString aQuote = m_pTable->getMetaData()->getIdentifierQuoteString( );
+
+ if(comphelper::getBOOL(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISUNIQUE))))
+ aSql.append("UNIQUE ");
+ aSql.append("INDEX ");
+
+
+ OUString aCatalog,aSchema,aTable;
+ dbtools::qualifiedNameComponents(m_pTable->getMetaData(),m_pTable->getName(),aCatalog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
+
+ OUString aComposedName = dbtools::composeTableName(m_pTable->getMetaData(),aCatalog,aSchema,aTable, true, ::dbtools::EComposeRule::InIndexDefinitions);
+ if (!_rForName.isEmpty() )
+ {
+ aSql.append( ::dbtools::quoteName( aQuote, _rForName ) );
+ aSql.append(" ON ");
+ aSql.append(aComposedName);
+ aSql.append(" ( ");
+
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xColProp;
+ bool bAddIndexAppendix = ::dbtools::getBooleanDataSourceSetting( m_pTable->getConnection(), "AddIndexAppendix" );
+ sal_Int32 nCount = xColumns->getCount();
+ for(sal_Int32 i = 0 ; i < nCount; ++i)
+ {
+ xColProp.set(xColumns->getByIndex(i),UNO_QUERY);
+ aSql.append(::dbtools::quoteName( aQuote,comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
+
+ if ( bAddIndexAppendix )
+ {
+
+ aSql.appendAscii(any2bool(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISASCENDING)))
+ ?
+ " ASC"
+ :
+ " DESC");
+ }
+ aSql.append(",");
+ }
+ aSql[aSql.getLength() - 1] = ')';
+ }
+ else
+ {
+ aSql.append(aComposedName);
+
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xColProp;
+ if(xColumns->getCount() != 1)
+ throw SQLException();
+
+ xColumns->getByIndex(0) >>= xColProp;
+
+ aSql.append(".");
+ aSql.append(::dbtools::quoteName( aQuote,comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
+ }
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ OUString sSql = aSql.makeStringAndClear();
+ xStmt->execute(sSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OIndexesHelper::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName)
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if( !xConnection.is() || m_pTable->isNew() )
+ return;
+
+ if ( m_pTable->getIndexService().is() )
+ {
+ m_pTable->getIndexService()->dropIndex(m_pTable,_sElementName);
+ }
+ else
+ {
+ OUString aName,aSchema;
+ sal_Int32 nLen = _sElementName.indexOf('.');
+ if(nLen != -1)
+ aSchema = _sElementName.copy(0,nLen);
+ aName = _sElementName.copy(nLen+1);
+
+ OUString aSql( "DROP INDEX " );
+
+ OUString aComposedName = dbtools::composeTableName( m_pTable->getMetaData(), m_pTable, ::dbtools::EComposeRule::InIndexDefinitions, true );
+ OUString sIndexName = dbtools::composeTableName( m_pTable->getMetaData(), OUString(), aSchema, aName, true, ::dbtools::EComposeRule::InIndexDefinitions );
+
+ aSql += sIndexName + " ON " + aComposedName;
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TKey.cxx b/connectivity/source/commontools/TKey.cxx
new file mode 100644
index 000000000..1341291ab
--- /dev/null
+++ b/connectivity/source/commontools/TKey.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TKey.hxx>
+#include <TKeyColumns.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OTableKeyHelper::OTableKeyHelper(OTableHelper* _pTable) : connectivity::sdbcx::OKey(true)
+ ,m_pTable(_pTable)
+{
+ construct();
+}
+
+OTableKeyHelper::OTableKeyHelper( OTableHelper* _pTable
+ ,const OUString& Name
+ ,const std::shared_ptr<sdbcx::KeyProperties>& _rProps
+ ) : connectivity::sdbcx::OKey(Name,_rProps,true)
+ ,m_pTable(_pTable)
+{
+ construct();
+ refreshColumns();
+}
+
+void OTableKeyHelper::refreshColumns()
+{
+ if ( !m_pTable )
+ return;
+
+ std::vector< OUString> aVector;
+ if ( !isNew() )
+ {
+ aVector = m_aProps->m_aKeyColumnNames;
+ if ( aVector.empty() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aSchema,aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ if ( !m_Name.isEmpty() ) // foreign key
+ {
+
+ Reference< XResultSet > xResult = m_pTable->getMetaData()->getImportedKeys(m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)),
+ aSchema,aTable);
+
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ OUString aForeignKeyColumn = xRow->getString(8);
+ if(xRow->getString(12) == m_Name)
+ aVector.push_back(aForeignKeyColumn);
+ }
+ }
+ }
+
+ if ( aVector.empty() )
+ {
+ const Reference< XResultSet > xResult = m_pTable->getMetaData()->getPrimaryKeys(m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)),
+ aSchema,aTable);
+
+ if ( xResult.is() )
+ {
+ const Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ aVector.push_back(xRow->getString(4));
+ } // if ( xResult.is() )
+ }
+ }
+ }
+
+
+ if ( m_pColumns )
+ m_pColumns->reFill(aVector);
+ else
+ m_pColumns.reset(new OKeyColumnsHelper(this,m_aMutex,aVector));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TKeyColumns.cxx b/connectivity/source/commontools/TKeyColumns.cxx
new file mode 100644
index 000000000..0a2c02bb2
--- /dev/null
+++ b/connectivity/source/commontools/TKeyColumns.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TKeyColumns.hxx>
+#include <TKey.hxx>
+#include <sdbcx/VKeyColumn.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <TConnection.hxx>
+#include <connectivity/TTableHelper.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OKeyColumnsHelper::OKeyColumnsHelper( OTableKeyHelper* _pKey,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector)
+ : connectivity::sdbcx::OCollection(*_pKey,true,_rMutex,_rVector)
+ ,m_pKey(_pKey)
+{
+}
+
+sdbcx::ObjectType OKeyColumnsHelper::createObject(const OUString& _rName)
+{
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ OUString aCatalog, aSchema, aTable;
+ css::uno::Any Catalog(m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)));
+ Catalog >>= aCatalog;
+ m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pKey->getTable()->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ // first get the related column to _rName
+ Reference< XResultSet > xResult = m_pKey->getTable()->getMetaData()->getImportedKeys(
+ Catalog, aSchema, aTable);
+
+ OUString aRefColumnName;
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString aTemp;
+ while(xResult->next())
+ {
+ aTemp = xRow->getString(4);
+ if(xRow->getString(8) == _rName && m_pKey->getName() == xRow->getString(12))
+ {
+ aRefColumnName = aTemp;
+ break;
+ }
+ }
+ }
+
+ sdbcx::ObjectType xRet;
+
+ // now describe the column _rName and set his related column
+ xResult = m_pKey->getTable()->getMetaData()->getColumns(Catalog, aSchema, aTable, _rName);
+
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ if ( xResult->next() )
+ {
+ if ( xRow->getString(4) == _rName )
+ {
+ sal_Int32 nDataType = xRow->getInt(5);
+ OUString aTypeName(xRow->getString(6));
+ sal_Int32 nSize = xRow->getInt(7);
+ sal_Int32 nDec = xRow->getInt(9);
+ sal_Int32 nNull = xRow->getInt(11);
+ OUString sColumnDef;
+ try
+ {
+ sColumnDef = xRow->getString(13);
+ }
+ catch(const SQLException&)
+ {
+ // sometimes we get an error when asking for this param
+ }
+
+ xRet = new OKeyColumn(aRefColumnName,
+ _rName,
+ aTypeName,
+ sColumnDef,
+ nNull,
+ nSize,
+ nDec,
+ nDataType,
+ isCaseSensitive(),
+ aCatalog,
+ aSchema,
+ aTable);
+ }
+ }
+ }
+
+ return xRet;
+}
+
+Reference< XPropertySet > OKeyColumnsHelper::createDescriptor()
+{
+ return new OKeyColumn(isCaseSensitive());
+}
+
+void OKeyColumnsHelper::impl_refresh()
+{
+ m_pKey->refreshColumns();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TKeys.cxx b/connectivity/source/commontools/TKeys.cxx
new file mode 100644
index 000000000..1a73a349b
--- /dev/null
+++ b/connectivity/source/commontools/TKeys.cxx
@@ -0,0 +1,309 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/TKeys.hxx>
+#include <TKey.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XKeyAlteration.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbtools.hxx>
+#include <comphelper/types.hxx>
+#include <TConnection.hxx>
+
+namespace connectivity
+{
+using namespace comphelper;
+using namespace connectivity::sdbcx;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OKeysHelper::OKeysHelper( OTableHelper* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString>& _rVector
+ ) : OKeys_BASE(*_pTable,true,_rMutex,_rVector,true)
+ ,m_pTable(_pTable)
+{
+}
+
+sdbcx::ObjectType OKeysHelper::createObject(const OUString& _rName)
+{
+ sdbcx::ObjectType xRet;
+
+ if(!_rName.isEmpty())
+ {
+ xRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName));
+ }
+
+ if(!xRet.is()) // we have a primary key with a system name
+ {
+ xRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName));
+ }
+
+ return xRet;
+}
+
+void OKeysHelper::impl_refresh()
+{
+ m_pTable->refreshKeys();
+}
+
+Reference< XPropertySet > OKeysHelper::createDescriptor()
+{
+ return new OTableKeyHelper(m_pTable);
+}
+
+/** returns the keyrule string for the primary key
+*/
+static OUString getKeyRuleString(bool _bUpdate,sal_Int32 _nKeyRule)
+{
+ const char* pKeyRule = nullptr;
+ switch ( _nKeyRule )
+ {
+ case KeyRule::CASCADE:
+ pKeyRule = _bUpdate ? " ON UPDATE CASCADE " : " ON DELETE CASCADE ";
+ break;
+ case KeyRule::RESTRICT:
+ pKeyRule = _bUpdate ? " ON UPDATE RESTRICT " : " ON DELETE RESTRICT ";
+ break;
+ case KeyRule::SET_NULL:
+ pKeyRule = _bUpdate ? " ON UPDATE SET NULL " : " ON DELETE SET NULL ";
+ break;
+ case KeyRule::SET_DEFAULT:
+ pKeyRule = _bUpdate ? " ON UPDATE SET DEFAULT " : " ON DELETE SET DEFAULT ";
+ break;
+ default:
+ ;
+ }
+ OUString sRet;
+ if ( pKeyRule )
+ sRet = OUString::createFromAscii(pKeyRule);
+ return sRet;
+}
+
+void OKeysHelper::cloneDescriptorColumns( const sdbcx::ObjectType& _rSourceDescriptor, const sdbcx::ObjectType& _rDestDescriptor )
+{
+ Reference< XColumnsSupplier > xColSupp( _rSourceDescriptor, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xSourceCols( xColSupp->getColumns(), UNO_QUERY_THROW );
+
+ xColSupp.set( _rDestDescriptor, UNO_QUERY_THROW );
+ Reference< XAppend > xDestAppend( xColSupp->getColumns(), UNO_QUERY_THROW );
+
+ sal_Int32 nCount = xSourceCols->getCount();
+ for ( sal_Int32 i=0; i< nCount; ++i )
+ {
+ Reference< XPropertySet > xColProp( xSourceCols->getByIndex(i), UNO_QUERY );
+ xDestAppend->appendByDescriptor( xColProp );
+ }
+}
+
+// XAppend
+sdbcx::ObjectType OKeysHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if ( !xConnection.is() )
+ return nullptr;
+ if ( m_pTable->isNew() )
+ {
+ Reference< XPropertySet > xNewDescriptor( cloneDescriptor( descriptor ) );
+ cloneDescriptorColumns( descriptor, xNewDescriptor );
+ return xNewDescriptor;
+ }
+
+ const ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ sal_Int32 nKeyType = getINT32(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)));
+ sal_Int32 nUpdateRule = 0, nDeleteRule = 0;
+ OUString sReferencedName;
+
+ if ( nKeyType == KeyType::FOREIGN )
+ {
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)) >>= sReferencedName;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_UPDATERULE)) >>= nUpdateRule;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)) >>= nDeleteRule;
+ }
+
+ if ( m_pTable->getKeyService().is() )
+ {
+ m_pTable->getKeyService()->addKey(m_pTable,descriptor);
+ }
+ else
+ {
+ // if we're here, we belong to a table which is not new, i.e. already exists in the database.
+ // In this case, really append the new index.
+ OUStringBuffer aSql;
+ aSql.append("ALTER TABLE ");
+ OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString( );
+
+ aSql.append(composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true ));
+ aSql.append(" ADD ");
+
+ if ( nKeyType == KeyType::PRIMARY )
+ {
+ aSql.append(" PRIMARY KEY (");
+ }
+ else if ( nKeyType == KeyType::FOREIGN )
+ {
+ aSql.append(" FOREIGN KEY (");
+ }
+ else
+ throw SQLException();
+
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xColProp;
+ for(sal_Int32 i = 0 ; i < xColumns->getCount() ; ++i)
+ {
+ if ( i > 0 )
+ aSql.append(",");
+ xColProp.set(xColumns->getByIndex(i), css::uno::UNO_QUERY);
+ aSql.append( ::dbtools::quoteName( aQuote,getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))) );
+
+ }
+ aSql.append(")");
+
+ if ( nKeyType == KeyType::FOREIGN )
+ {
+ aSql.append(" REFERENCES ");
+ aSql.append(::dbtools::quoteTableName(m_pTable->getConnection()->getMetaData(),sReferencedName,::dbtools::EComposeRule::InTableDefinitions));
+ aSql.append(" (");
+
+ for(sal_Int32 i=0;i<xColumns->getCount();++i)
+ {
+ if ( i > 0 )
+ aSql.append(",");
+ xColumns->getByIndex(i) >>= xColProp;
+ aSql.append(::dbtools::quoteName( aQuote,getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_RELATEDCOLUMN)))));
+
+ }
+ aSql.append(")");
+ aSql.append(getKeyRuleString(true ,nUpdateRule));
+ aSql.append(getKeyRuleString(false ,nDeleteRule));
+ }
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ xStmt->execute(aSql.makeStringAndClear());
+ }
+ // find the name which the database gave the new key
+ OUString sNewName( _rForName );
+ try
+ {
+ OUString aSchema,aTable;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+ Reference< XResultSet > xResult;
+ sal_Int32 nColumn = 12;
+ if ( nKeyType == KeyType::FOREIGN )
+ xResult = m_pTable->getMetaData()->getImportedKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
+ ,aSchema
+ ,aTable);
+ else
+ {
+ xResult = m_pTable->getMetaData()->getPrimaryKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
+ ,aSchema
+ ,aTable);
+ nColumn = 6;
+ }
+ if ( xResult.is() )
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ OUString sName = xRow->getString(nColumn);
+ if ( !m_pElements->exists(sName) ) // this name wasn't inserted yet so it must be the new one
+ {
+ descriptor->setPropertyValue( rPropMap.getNameByIndex( PROPERTY_ID_NAME ), Any( sName ) );
+ sNewName = sName;
+ break;
+ }
+ }
+ ::comphelper::disposeComponent(xResult);
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+
+ m_pTable->addKey(sNewName,std::make_shared<sdbcx::KeyProperties>(sReferencedName,nKeyType,nUpdateRule,nDeleteRule));
+
+ return createObject( sNewName );
+}
+
+OUString OKeysHelper::getDropForeignKey() const
+{
+ return " DROP CONSTRAINT ";
+}
+
+// XDrop
+void OKeysHelper::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ Reference< XConnection> xConnection = m_pTable->getConnection();
+ if ( !xConnection.is() || m_pTable->isNew() )
+ return;
+
+ Reference<XPropertySet> xKey(getObject(_nPos),UNO_QUERY);
+ if ( m_pTable->getKeyService().is() )
+ {
+ m_pTable->getKeyService()->dropKey(m_pTable,xKey);
+ }
+ else
+ {
+ OUStringBuffer aSql;
+ aSql.append("ALTER TABLE ");
+
+ aSql.append( composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable,::dbtools::EComposeRule::InTableDefinitions, true ));
+
+ sal_Int32 nKeyType = KeyType::PRIMARY;
+ if ( xKey.is() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ xKey->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nKeyType;
+ }
+ if ( KeyType::PRIMARY == nKeyType )
+ {
+ aSql.append(" DROP PRIMARY KEY");
+ }
+ else
+ {
+ aSql.append(getDropForeignKey());
+ const OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString();
+ aSql.append( ::dbtools::quoteName( aQuote,_sElementName) );
+ }
+
+ Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(aSql.makeStringAndClear());
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+}
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TPrivilegesResultSet.cxx b/connectivity/source/commontools/TPrivilegesResultSet.cxx
new file mode 100644
index 000000000..928e9c016
--- /dev/null
+++ b/connectivity/source/commontools/TPrivilegesResultSet.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TPrivilegesResultSet.hxx>
+
+using namespace connectivity;
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+OResultSetPrivileges::OResultSetPrivileges( const Reference< XDatabaseMetaData>& _rxMeta
+ , const Any& catalog
+ , const OUString& schemaPattern
+ , const OUString& tableNamePattern)
+ : ODatabaseMetaDataResultSet(eTablePrivileges)
+ , m_bResetValues(true)
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ OUString sUserWorkingFor;
+ // we want all catalogues, all schemas, all tables
+ Sequence< OUString > sTableTypes {"VIEW", "TABLE", "%"}; // this last one is just to be sure to include anything else...
+ try
+ {
+ m_xTables = _rxMeta->getTables(catalog,schemaPattern,tableNamePattern,sTableTypes);
+ m_xRow.set(m_xTables,UNO_QUERY);
+
+ sUserWorkingFor = _rxMeta->getUserName();
+ }
+ catch(Exception&)
+ {
+ }
+
+ ODatabaseMetaDataResultSet::ORows aRows;
+ ODatabaseMetaDataResultSet::ORow aRow(8);
+ aRow[5] = new ORowSetValueDecorator(sUserWorkingFor);
+ aRow[6] = ODatabaseMetaDataResultSet::getSelectValue();
+ aRow[7] = new ORowSetValueDecorator(OUString("YES"));
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getInsertValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getDeleteValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getUpdateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getCreateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getReadValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getAlterValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getDropValue();
+ aRows.push_back(aRow);
+ aRow[6] = new ORowSetValueDecorator(OUString("REFERENCE"));
+ aRows.push_back(aRow);
+
+ setRows(std::move(aRows));
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+const ORowSetValue& OResultSetPrivileges::getValue(sal_Int32 columnIndex)
+{
+ switch(columnIndex)
+ {
+ case 1:
+ case 2:
+ case 3:
+ if ( m_xRow.is() && m_bResetValues )
+ {
+ (*m_aRowsIter)[1] = new ORowSetValueDecorator(m_xRow->getString(1));
+ if ( m_xRow->wasNull() )
+ (*m_aRowsIter)[1]->setNull();
+ (*m_aRowsIter)[2] = new ORowSetValueDecorator(m_xRow->getString(2));
+ if ( m_xRow->wasNull() )
+ (*m_aRowsIter)[2]->setNull();
+ (*m_aRowsIter)[3] = new ORowSetValueDecorator(m_xRow->getString(3));
+ if ( m_xRow->wasNull() )
+ (*m_aRowsIter)[3]->setNull();
+
+ m_bResetValues = false;
+ }
+ }
+ return ODatabaseMetaDataResultSet::getValue(columnIndex);
+}
+
+void SAL_CALL OResultSetPrivileges::disposing()
+{
+ ODatabaseMetaDataResultSet::disposing();
+ m_xTables.clear();
+ m_xRow.clear();
+}
+
+sal_Bool SAL_CALL OResultSetPrivileges::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed );
+
+ bool bReturn = false;
+ if ( m_xTables.is() )
+ {
+ if ( m_bBOF )
+ {
+ m_bResetValues = true;
+ if ( !m_xTables->next() )
+ return false;
+ }
+
+ bReturn = ODatabaseMetaDataResultSet::next();
+ if ( !bReturn )
+ {
+ m_bBOF = false;
+ m_bResetValues = bReturn = m_xTables->next();
+ }
+ }
+ return bReturn;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TSkipDeletedSet.cxx b/connectivity/source/commontools/TSkipDeletedSet.cxx
new file mode 100644
index 000000000..701bd743f
--- /dev/null
+++ b/connectivity/source/commontools/TSkipDeletedSet.cxx
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TSkipDeletedSet.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <algorithm>
+
+using namespace connectivity;
+
+OSkipDeletedSet::OSkipDeletedSet(IResultSetHelper* _pHelper)
+ : m_pHelper(_pHelper)
+ ,m_bDeletedVisible(false)
+{
+ m_aBookmarksPositions.reserve(256);
+}
+
+OSkipDeletedSet::~OSkipDeletedSet()
+{
+ m_aBookmarksPositions.clear();
+ //m_aBookmarks.clear();
+}
+
+bool OSkipDeletedSet::skipDeleted(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData)
+{
+ OSL_ENSURE(_eCursorPosition != IResultSetHelper::BOOKMARK,"OSkipDeletedSet::SkipDeleted can't be called for BOOKMARK");
+
+ IResultSetHelper::Movement eDelPosition = _eCursorPosition;
+ sal_Int32 nDelOffset = abs(_nOffset);
+
+ switch (_eCursorPosition)
+ {
+ case IResultSetHelper::ABSOLUTE1:
+ return moveAbsolute(_nOffset,_bRetrieveData);
+ case IResultSetHelper::FIRST: // set the movement when positioning failed
+ eDelPosition = IResultSetHelper::NEXT;
+ nDelOffset = 1;
+ break;
+ case IResultSetHelper::LAST:
+ eDelPosition = IResultSetHelper::PRIOR; // last row is invalid so position before
+ nDelOffset = 1;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ eDelPosition = (_nOffset >= 0) ? IResultSetHelper::NEXT : IResultSetHelper::PRIOR;
+ break;
+ default:
+ break;
+ }
+
+ bool bDone = true;
+ bool bDataFound = false;
+
+ if (_eCursorPosition == IResultSetHelper::LAST)
+ {
+ SAL_INFO( "connectivity.commontools", "OSkipDeletedSet::skipDeleted: last" );
+ sal_Int32 nBookmark = 0;
+ // first position on the last known row
+ if ( m_aBookmarksPositions.empty() )
+ {
+ bDataFound = m_pHelper->move(IResultSetHelper::FIRST, 0, _bRetrieveData);
+ if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ }
+ else
+ {
+ // I already have a bookmark so we can positioned on that and look if it is the last one
+ nBookmark = (*m_aBookmarksPositions.rbegin())/*->first*/;
+
+ bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nBookmark, _bRetrieveData);
+ OSL_ENSURE((m_bDeletedVisible || !m_pHelper->isRowDeleted()),"A bookmark should not be deleted!");
+ }
+
+
+ // and then move forward until we are after the last row
+ while(bDataFound)
+ {
+ bDataFound = m_pHelper->move(IResultSetHelper::NEXT, 1, false); // we don't need the data here
+ if( bDataFound && ( m_bDeletedVisible || !m_pHelper->isRowDeleted()) )
+ { // we weren't on the last row we remember it and move on
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ }
+ else if(!bDataFound && !m_aBookmarksPositions.empty() )
+ {
+ // i already know the last bookmark :-)
+ // now we only have to repositioning us to the last row
+ nBookmark = (*m_aBookmarksPositions.rbegin())/*->first*/;
+ bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nBookmark, _bRetrieveData);
+ break;
+ }
+ }
+ return bDataFound;
+ }
+ else if (_eCursorPosition != IResultSetHelper::RELATIVE1)
+ {
+ bDataFound = m_pHelper->move(_eCursorPosition, _nOffset, _bRetrieveData);
+ bDone = bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted());
+ }
+ else
+ {
+ bDataFound = m_pHelper->move(eDelPosition, 1, _bRetrieveData);
+ if (bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ {
+ bDone = (--nDelOffset) == 0;
+ if ( !bDone )
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ }
+ else
+ bDone = false;
+ }
+
+ while (bDataFound && !bDone) // Iterate until we are at the valid set
+ {
+ bDataFound = m_pHelper->move(eDelPosition, 1, _bRetrieveData);
+ if (_eCursorPosition != IResultSetHelper::RELATIVE1)
+ bDone = bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted());
+ else if (bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ {
+ bDone = (--nDelOffset) == 0;
+ if ( !bDone )
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ }
+ else
+ bDone = false;
+ }
+
+ if(bDataFound && bDone)
+ {
+ const sal_Int32 nDriverPos = m_pHelper->getDriverPos();
+ if ( m_bDeletedVisible )
+ {
+ if ( nDriverPos > static_cast<sal_Int32>(m_aBookmarksPositions.size()) )
+ m_aBookmarksPositions.push_back(nDriverPos);
+ }
+ else if ( std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),nDriverPos) == m_aBookmarksPositions.end() )
+ m_aBookmarksPositions.push_back(nDriverPos);
+ /*sal_Int32 nDriverPos = m_pHelper->getDriverPos();
+ if(m_aBookmarks.find(nDriverPos) == m_aBookmarks.end())
+ m_aBookmarksPositions.push_back(m_aBookmarks.emplace( nDriverPos,m_aBookmarksPositions.size()+1)).first);*/
+ }
+
+ return bDataFound;
+}
+
+bool OSkipDeletedSet::moveAbsolute(sal_Int32 _nPos,bool _bRetrieveData)
+{
+ bool bDataFound = false;
+ sal_Int32 nNewPos = _nPos;
+ if(nNewPos > 0)
+ {
+ if(static_cast<sal_Int32>(m_aBookmarksPositions.size()) < nNewPos)
+ {
+ // bookmark isn't known yet
+ // start at the last known position
+ sal_Int32 nCurPos = 0;
+ if ( m_aBookmarksPositions.empty() )
+ {
+ bDataFound = m_pHelper->move(IResultSetHelper::FIRST, 0, _bRetrieveData );
+ if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ {
+ ++nCurPos;
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ --nNewPos;
+ }
+ } // if ( m_aBookmarksPositions.empty() )
+ else
+ {
+ sal_Int32 nLastBookmark = *m_aBookmarksPositions.rbegin()/*->first*/;
+ nCurPos = /*(**/m_aBookmarksPositions.size()/*->second*/;
+ nNewPos = nNewPos - nCurPos;
+ bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK, nLastBookmark, _bRetrieveData);
+ }
+
+ // now move to that row we need and don't count deleted rows
+ while (bDataFound && nNewPos)
+ {
+ bDataFound = m_pHelper->move(IResultSetHelper::NEXT, 1, _bRetrieveData);
+ if(bDataFound && (m_bDeletedVisible || !m_pHelper->isRowDeleted()))
+ {
+ ++nCurPos;
+ m_aBookmarksPositions.push_back(m_pHelper->getDriverPos());
+ //m_aBookmarksPositions.push_back(m_aBookmarks.emplace( m_pHelper->getDriverPos(),m_aBookmarksPositions.size()+1)).first);
+ --nNewPos;
+ }
+ }
+ }
+ else
+ {
+ const sal_Int32 nBookmark = m_aBookmarksPositions[nNewPos-1]/*->first*/;
+ bDataFound = m_pHelper->move(IResultSetHelper::BOOKMARK,nBookmark, _bRetrieveData);
+ OSL_ENSURE((m_bDeletedVisible || !m_pHelper->isRowDeleted()),"moveAbsolute: row can't be deleted!");
+ }
+ }
+ else
+ {
+ ++nNewPos;
+ bDataFound = skipDeleted(IResultSetHelper::LAST,0,nNewPos == 0);
+
+ for(sal_Int32 i=nNewPos+1;bDataFound && i <= 0;++i)
+ bDataFound = skipDeleted(IResultSetHelper::PRIOR,1,i == 0);
+
+ }
+ return bDataFound;
+}
+
+void OSkipDeletedSet::clear()
+{
+ std::vector<sal_Int32>().swap(m_aBookmarksPositions);
+}
+
+sal_Int32 OSkipDeletedSet::getMappedPosition(sal_Int32 _nPos) const
+{
+ std::vector<sal_Int32>::const_iterator aFind = std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),_nPos);
+ if ( aFind != m_aBookmarksPositions.end() )
+ return (aFind - m_aBookmarksPositions.begin()) + 1;
+ OSL_FAIL("Why!");
+ return -1;
+}
+
+void OSkipDeletedSet::insertNewPosition(sal_Int32 _nPos)
+{
+ m_aBookmarksPositions.push_back(_nPos);
+}
+
+void OSkipDeletedSet::deletePosition(sal_Int32 _nBookmark)
+{
+ std::vector<sal_Int32>::iterator aFind = std::find(m_aBookmarksPositions.begin(),m_aBookmarksPositions.end(),_nBookmark);
+ if ( aFind != m_aBookmarksPositions.end() )
+ {
+ m_aBookmarksPositions.erase(aFind);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TSortIndex.cxx b/connectivity/source/commontools/TSortIndex.cxx
new file mode 100644
index 000000000..44a883dc8
--- /dev/null
+++ b/connectivity/source/commontools/TSortIndex.cxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <TSortIndex.hxx>
+#include <algorithm>
+#include <iterator>
+#include <o3tl/functional.hxx>
+
+using namespace connectivity;
+
+namespace {
+
+/// Functor object for class OSortIndex::TIntValuePairVector::value_type returntype is bool
+struct TKeyValueFunc
+{
+ OSortIndex* pIndex;
+
+ explicit TKeyValueFunc(OSortIndex* _pIndex) : pIndex(_pIndex)
+ {
+ }
+ // return false if compared values are equal otherwise true
+ bool operator()(const OSortIndex::TIntValuePairVector::value_type& lhs,const OSortIndex::TIntValuePairVector::value_type& rhs) const
+ {
+ const std::vector<OKeyType>& aKeyType = pIndex->getKeyType();
+ size_t i = 0;
+ for (auto const& elem : aKeyType)
+ {
+ const bool bGreater = pIndex->getAscending(i) != TAscendingOrder::ASC;
+ const bool bLess = !bGreater;
+
+ // compare depending for type
+ switch (elem)
+ {
+ case OKeyType::String:
+ {
+ sal_Int32 nRes = lhs.second->getKeyString(i).compareTo(rhs.second->getKeyString(i));
+ if (nRes < 0)
+ return bLess;
+ else if (nRes > 0)
+ return bGreater;
+ }
+ break;
+ case OKeyType::Double:
+ {
+ double d1 = lhs.second->getKeyDouble(i);
+ double d2 = rhs.second->getKeyDouble(i);
+
+ if (d1 < d2)
+ return bLess;
+ else if (d1 > d2)
+ return bGreater;
+ }
+ break;
+ case OKeyType::NONE:
+ break;
+ }
+ ++i;
+ }
+
+ // know we know that the values are equal
+ return false;
+ }
+};
+
+}
+
+::rtl::Reference<OKeySet> OSortIndex::CreateKeySet()
+{
+ Freeze();
+
+ ::rtl::Reference<OKeySet> pKeySet = new OKeySet();
+ pKeySet->reserve(m_aKeyValues.size());
+ std::transform(m_aKeyValues.begin()
+ ,m_aKeyValues.end()
+ ,std::back_inserter(*pKeySet)
+ ,::o3tl::select1st<TIntValuePairVector::value_type>());
+ pKeySet->setFrozen();
+ return pKeySet;
+}
+
+OSortIndex::OSortIndex( std::vector<OKeyType>&& _aKeyType,
+ std::vector<TAscendingOrder>&& _aAscending)
+ :m_aKeyType(std::move(_aKeyType))
+ ,m_aAscending(std::move(_aAscending))
+ ,m_bFrozen(false)
+{
+}
+
+OSortIndex::~OSortIndex()
+{
+}
+
+void OSortIndex::AddKeyValue(std::unique_ptr<OKeyValue> pKeyValue)
+{
+ assert(pKeyValue && "Can not be null here!");
+ if(m_bFrozen)
+ {
+ m_aKeyValues.push_back({pKeyValue->getValue(),nullptr});
+ }
+ else
+ m_aKeyValues.push_back({pKeyValue->getValue(),std::move(pKeyValue)});
+}
+
+void OSortIndex::Freeze()
+{
+ OSL_ENSURE(! m_bFrozen,"OSortIndex::Freeze: already frozen!");
+ // sorting:
+ if (m_aKeyType[0] != OKeyType::NONE)
+ // we will sort ourself when the first keyType say so
+ std::sort(m_aKeyValues.begin(),m_aKeyValues.end(),TKeyValueFunc(this));
+
+ for (auto & keyValue : m_aKeyValues)
+ {
+ keyValue.second.reset();
+ }
+
+ m_bFrozen = true;
+}
+
+
+OKeyValue::OKeyValue(sal_Int32 nVal)
+: m_nValue(nVal)
+{
+}
+
+OKeyValue::~OKeyValue()
+{
+}
+
+std::unique_ptr<OKeyValue> OKeyValue::createKeyValue(sal_Int32 _nVal)
+{
+ return std::unique_ptr<OKeyValue>(new OKeyValue(_nVal));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/TTableHelper.cxx b/connectivity/source/commontools/TTableHelper.cxx
new file mode 100644
index 000000000..31e240469
--- /dev/null
+++ b/connectivity/source/commontools/TTableHelper.cxx
@@ -0,0 +1,610 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <connectivity/TTableHelper.hxx>
+#include <com/sun/star/sdb/tools/XTableRename.hpp>
+#include <com/sun/star/sdb/tools/XTableAlteration.hpp>
+#include <com/sun/star/sdb/tools/XKeyAlteration.hpp>
+#include <com/sun/star/sdb/tools/XIndexAlteration.hpp>
+#include <sdbcx/VKey.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <TConnection.hxx>
+
+#include <o3tl/functional.hxx>
+
+#include <iterator>
+#include <set>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+namespace
+{
+ /// helper class for column property change events which holds the OComponentDefinition weak
+class OTableContainerListener:
+ public ::cppu::WeakImplHelper< XContainerListener >
+{
+ OTableHelper* m_pComponent;
+ std::map< OUString,bool> m_aRefNames;
+
+protected:
+ virtual ~OTableContainerListener() override {}
+public:
+ explicit OTableContainerListener(OTableHelper* _pComponent) : m_pComponent(_pComponent){}
+ // noncopyable
+ OTableContainerListener(const OTableContainerListener&) = delete;
+ const OTableContainerListener& operator=(const OTableContainerListener&) = delete;
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& /*Event*/ ) override
+ {
+ }
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override
+ {
+ // tdf#137745, perhaps connectivity::OTableHelper::disposing() has been called
+ // which called OTableContainerListener::clear(), so m_pComponent may be null
+ if (m_pComponent == nullptr)
+ return;
+
+ OUString sName;
+ Event.Accessor >>= sName;
+ if ( m_aRefNames.find(sName) != m_aRefNames.end() )
+ m_pComponent->refreshKeys();
+ }
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override
+ {
+ OUString sOldComposedName,sNewComposedName;
+ Event.ReplacedElement >>= sOldComposedName;
+ Event.Accessor >>= sNewComposedName;
+ if ( sOldComposedName != sNewComposedName && m_aRefNames.find(sOldComposedName) != m_aRefNames.end() )
+ m_pComponent->refreshKeys();
+ }
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& /*_rSource*/ ) override
+ {
+ }
+ void clear() { m_pComponent = nullptr; }
+ void add(const OUString& _sRefName) { m_aRefNames.emplace(_sRefName,true); }
+};
+}
+namespace connectivity
+{
+ static OUString lcl_getServiceNameForSetting(const Reference< css::sdbc::XConnection >& _xConnection,const OUString& i_sSetting)
+ {
+ OUString sSupportService;
+ Any aValue;
+ if ( ::dbtools::getDataSourceSetting(_xConnection,i_sSetting,aValue) )
+ {
+ aValue >>= sSupportService;
+ }
+ return sSupportService;
+ }
+ struct OTableHelperImpl
+ {
+ TKeyMap m_aKeys;
+ // helper services which can be provided by extensions
+ Reference< css::sdb::tools::XTableRename> m_xRename;
+ Reference< css::sdb::tools::XTableAlteration> m_xAlter;
+ Reference< css::sdb::tools::XKeyAlteration> m_xKeyAlter;
+ Reference< css::sdb::tools::XIndexAlteration> m_xIndexAlter;
+
+ Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ Reference< css::sdbc::XConnection > m_xConnection;
+ rtl::Reference<OTableContainerListener> m_xTablePropertyListener;
+ std::vector< ColumnDesc > m_aColumnDesc;
+ explicit OTableHelperImpl(const Reference< css::sdbc::XConnection >& _xConnection)
+ : m_xConnection(_xConnection)
+ {
+ try
+ {
+ m_xMetaData = m_xConnection->getMetaData();
+ Reference<XMultiServiceFactory> xFac(_xConnection,UNO_QUERY);
+ if ( xFac.is() )
+ {
+ m_xRename.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"TableRenameServiceName")),UNO_QUERY);
+ m_xAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"TableAlterationServiceName")),UNO_QUERY);
+ m_xKeyAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"KeyAlterationServiceName")),UNO_QUERY);
+ m_xIndexAlter.set(xFac->createInstance(lcl_getServiceNameForSetting(m_xConnection,"IndexAlterationServiceName")),UNO_QUERY);
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ };
+}
+
+OTableHelper::OTableHelper( sdbcx::OCollection* _pTables,
+ const Reference< XConnection >& _xConnection,
+ bool _bCase)
+ :OTable_TYPEDEF(_pTables,_bCase)
+ ,m_pImpl(new OTableHelperImpl(_xConnection))
+{
+}
+
+OTableHelper::OTableHelper( sdbcx::OCollection* _pTables,
+ const Reference< XConnection >& _xConnection,
+ bool _bCase,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ ) : OTable_TYPEDEF(_pTables,
+ _bCase,
+ Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+ ,m_pImpl(new OTableHelperImpl(_xConnection))
+{
+}
+
+OTableHelper::~OTableHelper()
+{
+}
+
+void SAL_CALL OTableHelper::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( m_pImpl->m_xTablePropertyListener.is() )
+ {
+ m_pTables->removeContainerListener(m_pImpl->m_xTablePropertyListener);
+ m_pImpl->m_xTablePropertyListener->clear();
+ m_pImpl->m_xTablePropertyListener.clear();
+ }
+ OTable_TYPEDEF::disposing();
+
+ m_pImpl->m_xConnection = nullptr;
+ m_pImpl->m_xMetaData = nullptr;
+
+}
+
+
+namespace
+{
+ /** collects ColumnDesc's from a resultset produced by XDatabaseMetaData::getColumns
+ */
+ void lcl_collectColumnDescs_throw( const Reference< XResultSet >& _rxResult, std::vector< ColumnDesc >& _out_rColumns )
+ {
+ Reference< XRow > xRow( _rxResult, UNO_QUERY_THROW );
+ OUString sName;
+ OrdinalPosition nOrdinalPosition( 0 );
+ while ( _rxResult->next() )
+ {
+ sName = xRow->getString( 4 ); // COLUMN_NAME
+ sal_Int32 nField5 = xRow->getInt(5);
+ OUString aField6 = xRow->getString(6);
+ sal_Int32 nField7 = xRow->getInt(7)
+ , nField9 = xRow->getInt(9)
+ , nField11= xRow->getInt(11);
+ OUString sField12 = xRow->getString(12)
+ ,sField13 = xRow->getString(13);
+ nOrdinalPosition = xRow->getInt( 17 ); // ORDINAL_POSITION
+ _out_rColumns.push_back( ColumnDesc( sName,nField5,aField6,nField7,nField9,nField11,sField12,sField13, nOrdinalPosition ) );
+ }
+ }
+
+ /** checks a given array of ColumnDesc's whether it has reasonable ordinal positions. If not,
+ they will be normalized to be the array index.
+ */
+ void lcl_sanitizeColumnDescs( std::vector< ColumnDesc >& _rColumns )
+ {
+ if ( _rColumns.empty() )
+ return;
+
+ // collect all used ordinals
+ std::set< OrdinalPosition > aUsedOrdinals;
+ for ( const auto& collect : _rColumns )
+ aUsedOrdinals.insert( collect.nOrdinalPosition );
+
+ // we need to have as much different ordinals as we have different columns
+ bool bDuplicates = aUsedOrdinals.size() != _rColumns.size();
+ // and it needs to be a continuous range
+ size_t nOrdinalsRange = *aUsedOrdinals.rbegin() - *aUsedOrdinals.begin() + 1;
+ bool bGaps = nOrdinalsRange != _rColumns.size();
+
+ // if that's not the case, normalize it
+ if ( bGaps || bDuplicates )
+ {
+ OSL_FAIL( "lcl_sanitizeColumnDescs: database did provide invalid ORDINAL_POSITION values!" );
+
+ OrdinalPosition nNormalizedPosition = 1;
+ for ( auto& normalize : _rColumns )
+ normalize.nOrdinalPosition = nNormalizedPosition++;
+ return;
+ }
+
+ // what's left is that the range might not be from 1 to <column count>, but for instance
+ // 0 to <column count>-1.
+ size_t nOffset = *aUsedOrdinals.begin() - 1;
+ for ( auto& offset : _rColumns )
+ offset.nOrdinalPosition -= nOffset;
+ }
+}
+
+
+void OTableHelper::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+ if(!isNew())
+ {
+ Any aCatalog;
+ if ( !m_CatalogName.isEmpty() )
+ aCatalog <<= m_CatalogName;
+
+ ::utl::SharedUNOComponent< XResultSet > xResult( getMetaData()->getColumns(
+ aCatalog,
+ m_SchemaName,
+ m_Name,
+ "%"
+ ) );
+
+ // collect the column names, together with their ordinal position
+ m_pImpl->m_aColumnDesc.clear();
+ lcl_collectColumnDescs_throw( xResult, m_pImpl->m_aColumnDesc );
+
+ // ensure that the ordinal positions as obtained from the meta data do make sense
+ lcl_sanitizeColumnDescs( m_pImpl->m_aColumnDesc );
+
+ // sort by ordinal position
+ std::map< OrdinalPosition, OUString > aSortedColumns;
+ for (const auto& copy : m_pImpl->m_aColumnDesc)
+ aSortedColumns[ copy.nOrdinalPosition ] = copy.sName;
+
+ // copy them to aVector, now that we have the proper ordering
+ std::transform(
+ aSortedColumns.begin(),
+ aSortedColumns.end(),
+ std::insert_iterator< ::std::vector< OUString> >( aVector, aVector.begin() ),
+ ::o3tl::select2nd< std::map< OrdinalPosition, OUString >::value_type >()
+ );
+ }
+
+ if(m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(createColumns(aVector));
+}
+
+const ColumnDesc* OTableHelper::getColumnDescription(const OUString& _sName) const
+{
+ const ColumnDesc* pRet = nullptr;
+ auto aIter = std::find_if(m_pImpl->m_aColumnDesc.begin(), m_pImpl->m_aColumnDesc.end(),
+ [&_sName](const ColumnDesc& rColumnDesc) { return rColumnDesc.sName == _sName; });
+ if (aIter != m_pImpl->m_aColumnDesc.end())
+ pRet = &*aIter;
+ return pRet;
+}
+
+void OTableHelper::refreshPrimaryKeys(::std::vector< OUString>& _rNames)
+{
+ Any aCatalog;
+ if ( !m_CatalogName.isEmpty() )
+ aCatalog <<= m_CatalogName;
+ Reference< XResultSet > xResult = getMetaData()->getPrimaryKeys(aCatalog,m_SchemaName,m_Name);
+
+ if ( xResult.is() )
+ {
+ auto pKeyProps = std::make_shared<sdbcx::KeyProperties>(OUString(),KeyType::PRIMARY,0,0);
+ OUString aPkName;
+ bool bAlreadyFetched = false;
+ const Reference< XRow > xRow(xResult,UNO_QUERY);
+ while ( xResult->next() )
+ {
+ pKeyProps->m_aKeyColumnNames.push_back(xRow->getString(4));
+ if ( !bAlreadyFetched )
+ {
+ aPkName = xRow->getString(6);
+ SAL_WARN_IF(xRow->wasNull(),"connectivity.commontools", "NULL Primary Key name");
+ SAL_WARN_IF(aPkName.isEmpty(),"connectivity.commontools", "empty Primary Key name");
+ bAlreadyFetched = true;
+ }
+ }
+
+ if(bAlreadyFetched)
+ {
+ SAL_WARN_IF(aPkName.isEmpty(),"connectivity.commontools", "empty Primary Key name");
+ SAL_WARN_IF(pKeyProps->m_aKeyColumnNames.empty(),"connectivity.commontools", "Primary Key has no columns");
+ m_pImpl->m_aKeys.emplace(aPkName,pKeyProps);
+ _rNames.push_back(aPkName);
+ }
+ } // if ( xResult.is() && xResult->next() )
+ ::comphelper::disposeComponent(xResult);
+}
+
+void OTableHelper::refreshForeignKeys(::std::vector< OUString>& _rNames)
+{
+ Any aCatalog;
+ if ( !m_CatalogName.isEmpty() )
+ aCatalog <<= m_CatalogName;
+ Reference< XResultSet > xResult = getMetaData()->getImportedKeys(aCatalog,m_SchemaName,m_Name);
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+
+ if ( !xRow.is() )
+ return;
+
+ std::shared_ptr<sdbcx::KeyProperties> pKeyProps;
+ OUString aName,sCatalog,aSchema,sOldFKName;
+ while( xResult->next() )
+ {
+ // this must be outside the "if" because we have to call in a right order
+ sCatalog = xRow->getString(1);
+ if ( xRow->wasNull() )
+ sCatalog.clear();
+ aSchema = xRow->getString(2);
+ aName = xRow->getString(3);
+
+ const OUString sForeignKeyColumn = xRow->getString(8);
+ const sal_Int32 nUpdateRule = xRow->getInt(10);
+ const sal_Int32 nDeleteRule = xRow->getInt(11);
+ const OUString sFkName = xRow->getString(12);
+
+ if ( !sFkName.isEmpty() && !xRow->wasNull() )
+ {
+ if ( sOldFKName != sFkName )
+ {
+ if ( pKeyProps )
+ m_pImpl->m_aKeys.emplace(sOldFKName,pKeyProps);
+
+ const OUString sReferencedName = ::dbtools::composeTableName(getMetaData(),sCatalog,aSchema,aName,false,::dbtools::EComposeRule::InDataManipulation);
+ pKeyProps = std::make_shared<sdbcx::KeyProperties>(sReferencedName,KeyType::FOREIGN,nUpdateRule,nDeleteRule);
+ pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn);
+ _rNames.push_back(sFkName);
+ if ( m_pTables->hasByName(sReferencedName) )
+ {
+ if ( !m_pImpl->m_xTablePropertyListener.is() )
+ m_pImpl->m_xTablePropertyListener = new OTableContainerListener(this);
+ m_pTables->addContainerListener(m_pImpl->m_xTablePropertyListener);
+ m_pImpl->m_xTablePropertyListener->add(sReferencedName);
+ } // if ( m_pTables->hasByName(sReferencedName) )
+ sOldFKName = sFkName;
+ } // if ( sOldFKName != sFkName )
+ else if ( pKeyProps )
+ {
+ pKeyProps->m_aKeyColumnNames.push_back(sForeignKeyColumn);
+ }
+ }
+ } // while( xResult->next() )
+ if ( pKeyProps )
+ m_pImpl->m_aKeys.emplace(sOldFKName,pKeyProps);
+ ::comphelper::disposeComponent(xResult);
+}
+
+void OTableHelper::refreshKeys()
+{
+ m_pImpl->m_aKeys.clear();
+
+ ::std::vector< OUString> aNames;
+
+ if(!isNew())
+ {
+ refreshPrimaryKeys(aNames);
+ refreshForeignKeys(aNames);
+ m_xKeys.reset(createKeys(aNames));
+ } // if(!isNew())
+ else if (!m_xKeys )
+ m_xKeys.reset(createKeys(aNames));
+ /*if(m_pKeys)
+ m_pKeys->reFill(aVector);
+ else*/
+
+}
+
+void OTableHelper::refreshIndexes()
+{
+ ::std::vector< OUString> aVector;
+ if(!isNew())
+ {
+ // fill indexes
+ Any aCatalog;
+ if ( !m_CatalogName.isEmpty() )
+ aCatalog <<= m_CatalogName;
+ Reference< XResultSet > xResult = getMetaData()->getIndexInfo(aCatalog,m_SchemaName,m_Name,false,false);
+
+ if(xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ OUString sCatalogSep = getMetaData()->getCatalogSeparator();
+ OUString sPreviousRoundName;
+ while( xResult->next() )
+ {
+ OUString aName = xRow->getString(5);
+ if(!aName.isEmpty())
+ aName += sCatalogSep;
+ aName += xRow->getString(6);
+ if ( !aName.isEmpty() )
+ {
+ // don't insert the name if the last one we inserted was the same
+ if (sPreviousRoundName != aName)
+ aVector.push_back(aName);
+ }
+ sPreviousRoundName = aName;
+ }
+ ::comphelper::disposeComponent(xResult);
+ }
+ }
+
+ if(m_xIndexes)
+ m_xIndexes->reFill(aVector);
+ else
+ m_xIndexes.reset(createIndexes(aVector));
+}
+
+OUString OTableHelper::getRenameStart() const
+{
+ OUString sSql("RENAME ");
+ if ( m_Type == "VIEW" )
+ sSql += " VIEW ";
+ else
+ sSql += " TABLE ";
+
+ return sSql;
+}
+
+// XRename
+void SAL_CALL OTableHelper::rename( const OUString& newName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(
+#ifdef __GNUC__
+ ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
+#else
+ rBHelper.bDisposed
+#endif
+ );
+
+ if(!isNew())
+ {
+ if ( m_pImpl->m_xRename.is() )
+ {
+ m_pImpl->m_xRename->rename(this,newName);
+ }
+ else
+ {
+ OUString sSql = getRenameStart();
+
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+
+ OUString sComposedName;
+ sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,true,::dbtools::EComposeRule::InDataManipulation);
+ sSql += sComposedName
+ + " TO ";
+ sComposedName = ::dbtools::composeTableName(getMetaData(),sCatalog,sSchema,sTable,true,::dbtools::EComposeRule::InDataManipulation);
+ sSql += sComposedName;
+
+ Reference< XStatement > xStmt = m_pImpl->m_xConnection->createStatement( );
+ if ( xStmt.is() )
+ {
+ xStmt->execute(sSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+
+ OTable_TYPEDEF::rename(newName);
+ }
+ else
+ ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InTableDefinitions);
+}
+
+Reference< XDatabaseMetaData> OTableHelper::getMetaData() const
+{
+ return m_pImpl->m_xMetaData;
+}
+
+void SAL_CALL OTableHelper::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(
+#ifdef __GNUC__
+ ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed
+#else
+ rBHelper.bDisposed
+#endif
+ );
+
+ Reference< XPropertySet > xOld(
+ m_xColumns->getByIndex(index), css::uno::UNO_QUERY);
+ if(xOld.is())
+ alterColumnByName(getString(xOld->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),descriptor);
+}
+
+
+OUString SAL_CALL OTableHelper::getName()
+{
+ OUString sComposedName = ::dbtools::composeTableName(getMetaData(),m_CatalogName,m_SchemaName,m_Name,false,::dbtools::EComposeRule::InDataManipulation);
+ return sComposedName;
+}
+
+const OUString & OTableHelper::getTableName()
+{
+ return m_Name;
+}
+
+std::shared_ptr<sdbcx::KeyProperties> OTableHelper::getKeyProperties(const OUString& _sName) const
+{
+ std::shared_ptr<sdbcx::KeyProperties> pKeyProps;
+ TKeyMap::const_iterator aFind = m_pImpl->m_aKeys.find(_sName);
+ if ( aFind != m_pImpl->m_aKeys.end() )
+ {
+ pKeyProps = aFind->second;
+ }
+ else // only a fall back
+ {
+ OSL_FAIL("No key with the given name found");
+ pKeyProps = std::make_shared<sdbcx::KeyProperties>();
+ }
+
+ return pKeyProps;
+}
+
+void OTableHelper::addKey(const OUString& _sName,const std::shared_ptr<sdbcx::KeyProperties>& _aKeyProperties)
+{
+ m_pImpl->m_aKeys.emplace(_sName,_aKeyProperties);
+}
+
+OUString OTableHelper::getTypeCreatePattern() const
+{
+ return OUString();
+}
+
+Reference< XConnection> const & OTableHelper::getConnection() const
+{
+ return m_pImpl->m_xConnection;
+}
+
+Reference< css::sdb::tools::XTableRename> const & OTableHelper::getRenameService() const
+{
+ return m_pImpl->m_xRename;
+}
+
+Reference< css::sdb::tools::XTableAlteration> const & OTableHelper::getAlterService() const
+{
+ return m_pImpl->m_xAlter;
+}
+
+Reference< css::sdb::tools::XKeyAlteration> const & OTableHelper::getKeyService() const
+{
+ return m_pImpl->m_xKeyAlter;
+}
+
+Reference< css::sdb::tools::XIndexAlteration> const & OTableHelper::getIndexService() const
+{
+ return m_pImpl->m_xIndexAlter;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/conncleanup.cxx b/connectivity/source/commontools/conncleanup.cxx
new file mode 100644
index 000000000..52bbf2104
--- /dev/null
+++ b/connectivity/source/commontools/conncleanup.cxx
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/conncleanup.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+
+namespace dbtools
+{
+
+
+ using namespace css::uno;
+ using namespace css::beans;
+ using namespace css::sdbc;
+ using namespace css::lang;
+
+ constexpr OUStringLiteral ACTIVE_CONNECTION_PROPERTY_NAME = u"ActiveConnection";
+
+ OAutoConnectionDisposer::OAutoConnectionDisposer(const Reference< XRowSet >& _rxRowSet, const Reference< XConnection >& _rxConnection)
+ :m_xRowSet( _rxRowSet )
+ ,m_bRSListening( false )
+ ,m_bPropertyListening( false )
+ {
+ Reference< XPropertySet > xProps(_rxRowSet, UNO_QUERY);
+ OSL_ENSURE(xProps.is(), "OAutoConnectionDisposer::OAutoConnectionDisposer: invalid rowset (no XPropertySet)!");
+
+ if (!xProps.is())
+ return;
+
+ try
+ {
+ xProps->setPropertyValue( ACTIVE_CONNECTION_PROPERTY_NAME, Any( _rxConnection ) );
+ m_xOriginalConnection = _rxConnection;
+ startPropertyListening( xProps );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::OAutoConnectionDisposer" );
+ }
+ }
+
+
+ void OAutoConnectionDisposer::startPropertyListening( const Reference< XPropertySet >& _rxRowSet )
+ {
+ try
+ {
+ _rxRowSet->addPropertyChangeListener( ACTIVE_CONNECTION_PROPERTY_NAME, this );
+ m_bPropertyListening = true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::startPropertyListening" );
+ }
+ }
+
+
+ void OAutoConnectionDisposer::stopPropertyListening( const Reference< XPropertySet >& _rxEventSource )
+ {
+ // prevent deletion of ourself while we're herein
+ Reference< XInterface > xKeepAlive(static_cast< XWeak* >(this));
+
+ try
+ { // remove ourself as property change listener
+ OSL_ENSURE( _rxEventSource.is(), "OAutoConnectionDisposer::stopPropertyListening: invalid event source (no XPropertySet)!" );
+ if ( _rxEventSource.is() )
+ {
+ _rxEventSource->removePropertyChangeListener( ACTIVE_CONNECTION_PROPERTY_NAME, this );
+ m_bPropertyListening = false;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::stopPropertyListening" );
+ }
+ }
+
+
+ void OAutoConnectionDisposer::startRowSetListening()
+ {
+ OSL_ENSURE( !m_bRSListening, "OAutoConnectionDisposer::startRowSetListening: already listening!" );
+ try
+ {
+ if ( !m_bRSListening )
+ m_xRowSet->addRowSetListener( this );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::startRowSetListening" );
+ }
+ m_bRSListening = true;
+ }
+
+
+ void OAutoConnectionDisposer::stopRowSetListening()
+ {
+ OSL_ENSURE( m_bRSListening, "OAutoConnectionDisposer::stopRowSetListening: not listening!" );
+ try
+ {
+ m_xRowSet->removeRowSetListener( this );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::stopRowSetListening" );
+ }
+ m_bRSListening = false;
+ }
+
+
+ void SAL_CALL OAutoConnectionDisposer::propertyChange( const PropertyChangeEvent& _rEvent )
+ {
+ if ( _rEvent.PropertyName != ACTIVE_CONNECTION_PROPERTY_NAME )
+ return;
+
+// somebody set a new ActiveConnection
+
+ Reference< XConnection > xNewConnection;
+ _rEvent.NewValue >>= xNewConnection;
+
+ if ( isRowSetListening() )
+ {
+ // we're listening at the row set, this means that the row set does not have our
+ // m_xOriginalConnection as active connection anymore
+ // So there are two possibilities
+ // a. somebody sets a new connection which is not our original one
+ // b. somebody sets a new connection, which is exactly the original one
+ // a. we're not interested in a, but in b: In this case, we simply need to move to the state
+ // we had originally: listen for property changes, do not listen for row set changes, and
+ // do not dispose the connection until the row set does not need it anymore
+ if ( xNewConnection.get() == m_xOriginalConnection.get() )
+ {
+ stopRowSetListening();
+ }
+ }
+ else
+ {
+ // start listening at the row set. We're allowed to dispose the old connection as soon
+ // as the RowSet changed
+
+ // Unfortunately, the our database form implementations sometimes fire the change of their
+ // ActiveConnection twice. This is an error in forms/source/component/DatabaseForm.cxx, but
+ // changing this would require incompatible changes we can't do for a while.
+ // So for the moment, we have to live with it here.
+ //
+ // The only scenario where this doubled notification causes problems is when the connection
+ // of the form is reset to the one we're responsible for (m_xOriginalConnection), so we
+ // check this here.
+ //
+ // Yes, this is a HACK :(
+ if ( xNewConnection.get() != m_xOriginalConnection.get() )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ Reference< XConnection > xOldConnection;
+ _rEvent.OldValue >>= xOldConnection;
+ OSL_ENSURE( xOldConnection.get() == m_xOriginalConnection.get(), "OAutoConnectionDisposer::propertyChange: unexpected (original) property value!" );
+#endif
+ startRowSetListening();
+ }
+ }
+ }
+
+
+ void SAL_CALL OAutoConnectionDisposer::disposing( const EventObject& _rSource )
+ {
+ // the rowset is being disposed, and nobody has set a new ActiveConnection in the meantime
+ if ( isRowSetListening() )
+ stopRowSetListening();
+
+ clearConnection();
+
+ if ( m_bPropertyListening )
+ stopPropertyListening( Reference< XPropertySet >( _rSource.Source, UNO_QUERY ) );
+ }
+
+ void OAutoConnectionDisposer::clearConnection()
+ {
+ try
+ {
+ // dispose the old connection
+ Reference< XComponent > xComp(m_xOriginalConnection, UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ m_xOriginalConnection.clear();
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.commontools", "OAutoConnectionDisposer::clearConnection");
+ }
+ }
+
+ void SAL_CALL OAutoConnectionDisposer::cursorMoved( const css::lang::EventObject& /*event*/ )
+ {
+ }
+
+ void SAL_CALL OAutoConnectionDisposer::rowChanged( const css::lang::EventObject& /*event*/ )
+ {
+ }
+
+ void SAL_CALL OAutoConnectionDisposer::rowSetChanged( const css::lang::EventObject& /*event*/ )
+ {
+ stopRowSetListening();
+ clearConnection();
+
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbcharset.cxx b/connectivity/source/commontools/dbcharset.cxx
new file mode 100644
index 000000000..ebe45c028
--- /dev/null
+++ b/connectivity/source/commontools/dbcharset.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 <connectivity/dbcharset.hxx>
+#include <osl/diagnose.h>
+#include <rtl/tencinfo.h>
+
+
+namespace dbtools
+{
+
+ OCharsetMap::OCharsetMap()
+ {
+ }
+
+
+ void OCharsetMap::lateConstruct()
+ {
+ const rtl_TextEncoding eFirstEncoding = RTL_TEXTENCODING_DONTKNOW;
+ const rtl_TextEncoding eLastEncoding = 100; // TODO: a define in rtl/textenc.h would be fine here ...
+ OSL_ENSURE( 0 == eFirstEncoding, "OCharsetMap::OCharsetMap: somebody changed the numbers!" );
+
+ rtl_TextEncodingInfo aInfo; aInfo.StructSize = sizeof( rtl_TextEncodingInfo );
+ for ( rtl_TextEncoding eEncoding = eFirstEncoding; eEncoding < eLastEncoding; ++eEncoding )
+ {
+ if ( ( RTL_TEXTENCODING_DONTKNOW == eEncoding ) // this is always allowed - it has the special meaning "system encoding"
+ || ( rtl_getTextEncodingInfo( eEncoding, &aInfo )
+ && approveEncoding( eEncoding, aInfo )
+ )
+ )
+ {
+ m_aEncodings.insert( eEncoding );
+ }
+ }
+
+ OSL_ENSURE( find( RTL_TEXTENCODING_MS_1252 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding ANSI!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_APPLE_ROMAN ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding macintosh!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_437 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM437!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_850) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM850!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_860 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM860!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_861 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM861!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_863 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM863!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_865 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM865!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_IBM_866 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding IBM866!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_DONTKNOW ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding SYSTEM!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_UTF8 ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding UTF-8!" );
+ OSL_ENSURE( find( RTL_TEXTENCODING_BIG5_HKSCS ) != end(), "OCharsetMap::lateConstruct: missing compatibility encoding Big5-HKSCS!" );
+ }
+
+
+ bool OCharsetMap::approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const
+ {
+ bool bIsMimeEncoding = 0 != ( _rInfo.Flags & RTL_TEXTENCODING_INFO_MIME );
+ OSL_ENSURE( !bIsMimeEncoding || rtl_getMimeCharsetFromTextEncoding( _eEncoding ),
+ "OCharsetMap::OCharsetMap: inconsistence in rtl!" );
+ return bIsMimeEncoding;
+ }
+
+
+ OCharsetMap::~OCharsetMap()
+ {
+ }
+
+
+ OCharsetMap::CharsetIterator OCharsetMap::begin() const
+ {
+ ensureConstructed( );
+ return CharsetIterator(this, m_aEncodings.begin() );
+ }
+
+
+ OCharsetMap::CharsetIterator OCharsetMap::find(const rtl_TextEncoding _eEncoding) const
+ {
+ ensureConstructed( );
+ return CharsetIterator( this, m_aEncodings.find( _eEncoding ) );
+ }
+
+
+ OCharsetMap::CharsetIterator OCharsetMap::findIanaName(const OUString& _rIanaName) const
+ {
+ ensureConstructed( );
+
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
+ if ( !_rIanaName.isEmpty() )
+ {
+ // byte string conversion
+ OString sMimeByteString( _rIanaName.getStr(), _rIanaName.getLength(), RTL_TEXTENCODING_ASCII_US );
+ // look up
+ eEncoding = rtl_getTextEncodingFromMimeCharset( sMimeByteString.getStr() );
+
+ if ( RTL_TEXTENCODING_DONTKNOW == eEncoding )
+ { // if we're here, the name is not empty, but unknown -> this is an invalid name
+ return end();
+ }
+ }
+
+ return find( eEncoding );
+ }
+
+
+ OCharsetMap::CharsetIterator OCharsetMap::end() const
+ {
+ ensureConstructed( );
+
+ return CharsetIterator( this, m_aEncodings.end() );
+ }
+
+
+ CharsetIteratorDerefHelper::CharsetIteratorDerefHelper( const CharsetIteratorDerefHelper& _rSource )
+ :m_eEncoding( _rSource.m_eEncoding )
+ ,m_aIanaName( _rSource.m_aIanaName )
+ {
+ }
+
+
+ CharsetIteratorDerefHelper:: CharsetIteratorDerefHelper(const rtl_TextEncoding _eEncoding, const OUString& _rIanaName )
+ :m_eEncoding( _eEncoding )
+ ,m_aIanaName( _rIanaName )
+ {
+ }
+
+ OCharsetMap::CharsetIterator::CharsetIterator(const OCharsetMap* _pContainer, OCharsetMap::TextEncBag::const_iterator const & _aPos )
+ :m_pContainer( _pContainer )
+ ,m_aPos( _aPos )
+ {
+ OSL_ENSURE( m_pContainer, "OCharsetMap::CharsetIterator::CharsetIterator : invalid container!" );
+ }
+
+ CharsetIteratorDerefHelper OCharsetMap::CharsetIterator::operator*() const
+ {
+ OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.end(), "OCharsetMap::CharsetIterator::operator*: invalid position!");
+
+ rtl_TextEncoding eEncoding = *m_aPos;
+ OUString sIanaName;
+
+ if ( RTL_TEXTENCODING_DONTKNOW != eEncoding )
+ { // it's not the virtual "system charset"
+ const char* pIanaName = rtl_getMimeCharsetFromTextEncoding( eEncoding );
+ OSL_ENSURE( pIanaName, "OCharsetMap::CharsetIterator: invalid mime name!" );
+ if ( pIanaName )
+ sIanaName = OUString::createFromAscii( pIanaName );
+ }
+ return CharsetIteratorDerefHelper( eEncoding, sIanaName );
+ }
+
+
+ const OCharsetMap::CharsetIterator& OCharsetMap::CharsetIterator::operator++()
+ {
+ OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.end(), "OCharsetMap::CharsetIterator::operator++ : invalid position!" );
+ if ( m_aPos != m_pContainer->m_aEncodings.end())
+ ++m_aPos;
+ return *this;
+ }
+
+
+ const OCharsetMap::CharsetIterator& OCharsetMap::CharsetIterator::operator--()
+ {
+ OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.begin(), "OCharsetMap::CharsetIterator::operator-- : invalid position!" );
+ if ( m_aPos != m_pContainer->m_aEncodings.begin() )
+ --m_aPos;
+ return *this;
+ }
+
+
+ bool operator==(const OCharsetMap::CharsetIterator& lhs, const OCharsetMap::CharsetIterator& rhs)
+ {
+ return ( lhs.m_pContainer == rhs.m_pContainer ) && ( lhs.m_aPos == rhs.m_aPos );
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbconversion.cxx b/connectivity/source/commontools/dbconversion.cxx
new file mode 100644
index 000000000..af80efb60
--- /dev/null
+++ b/connectivity/source/commontools/dbconversion.cxx
@@ -0,0 +1,463 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbconversion.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <rtl/character.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <unotools/datetime.hxx>
+#include <o3tl/string_view.hxx>
+#include <sstream>
+#include <iomanip>
+
+namespace
+{
+ const sal_Int64 nanoSecInSec = 1000000000;
+ const sal_Int16 secInMin = 60;
+ const sal_Int16 minInHour = 60;
+
+ const sal_Int64 secMask = 1000000000;
+ const sal_Int64 minMask = 100000000000LL;
+ const sal_Int64 hourMask = 10000000000000LL;
+
+ const double fNanoSecondsPerDay = nanoSecInSec * secInMin * minInHour * 24.0;
+
+ // 32767-12-31 in "(days since 0001-01-01) + 1" format
+ const sal_Int32 maxDays = 11967896;
+ // -32768-01-01 in "(days since 0001-01-01) + 1" format
+ // Yes, I know it is currently unused. Will have to be used
+ // when we implement negative years. Writing down the correct
+ // value for future reference.
+ // *** Please don't remove just because it is unused ***
+ // Lionel Élie Mamane 2017-08-02
+ // const sal_Int32 minDays = -11968270;
+}
+
+
+namespace dbtools
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+
+ css::util::Date const & DBTypeConversion::getStandardDate()
+ {
+ static css::util::Date STANDARD_DB_DATE(1,1,1900);
+ return STANDARD_DB_DATE;
+ }
+
+ OUString DBTypeConversion::toDateString(const css::util::Date& rDate)
+ {
+ std::ostringstream ostr;
+ using std::setw;
+ ostr.fill('0');
+ ostr << setw(4) << rDate.Year << "-"
+ << setw(2) << rDate.Month << "-"
+ << setw(2) << rDate.Day;
+ return OUString::createFromAscii(ostr.str().c_str());
+ }
+
+ OUString DBTypeConversion::toTimeStringS(const css::util::Time& rTime)
+ {
+ std::ostringstream ostr;
+ using std::setw;
+ ostr.fill('0');
+ ostr << setw(2) << rTime.Hours << ":"
+ << setw(2) << rTime.Minutes << ":"
+ << setw(2) << rTime.Seconds;
+ return OUString::createFromAscii(ostr.str().c_str());
+ }
+
+ OUString DBTypeConversion::toTimeString(const css::util::Time& rTime)
+ {
+ std::ostringstream ostr;
+ using std::setw;
+ ostr.fill('0');
+ ostr << setw(2) << rTime.Hours << ":"
+ << setw(2) << rTime.Minutes << ":"
+ << setw(2) << rTime.Seconds << "."
+ << setw(9) << rTime.NanoSeconds;
+ return OUString::createFromAscii(ostr.str().c_str());
+ }
+
+ OUString DBTypeConversion::toDateTimeString(const css::util::DateTime& _rDateTime)
+ {
+ css::util::Date aDate(_rDateTime.Day,_rDateTime.Month,_rDateTime.Year);
+ css::util::Time const aTime(_rDateTime.NanoSeconds, _rDateTime.Seconds,
+ _rDateTime.Minutes, _rDateTime.Hours, _rDateTime.IsUTC);
+ return toDateString(aDate) + " " + toTimeString(aTime);
+ }
+
+ css::util::Date DBTypeConversion::toDate(const sal_Int32 _nVal)
+ {
+ css::util::Date aReturn;
+ aReturn.Day = static_cast<sal_uInt16>(_nVal % 100);
+ aReturn.Month = static_cast<sal_uInt16>((_nVal / 100) % 100);
+ aReturn.Year = static_cast<sal_uInt16>(_nVal / 10000);
+ return aReturn;
+ }
+
+
+ css::util::Time DBTypeConversion::toTime(const sal_Int64 _nVal)
+ {
+ css::util::Time aReturn;
+ sal_uInt64 unVal = static_cast<sal_uInt64>(_nVal >= 0 ? _nVal : -_nVal);
+ aReturn.Hours = unVal / hourMask;
+ aReturn.Minutes = (unVal / minMask) % 100;
+ aReturn.Seconds = (unVal / secMask) % 100;
+ aReturn.NanoSeconds = unVal % secMask;
+ return aReturn;
+ }
+
+ sal_Int64 DBTypeConversion::getNsFromTime(const css::util::Time& rVal)
+ {
+ sal_Int32 nHour = rVal.Hours;
+ sal_Int32 nMin = rVal.Minutes;
+ sal_Int32 nSec = rVal.Seconds;
+ sal_Int32 nNanoSec = rVal.NanoSeconds;
+
+ return nNanoSec +
+ nSec * nanoSecInSec +
+ nMin * (secInMin * nanoSecInSec) +
+ nHour * (minInHour * secInMin * nanoSecInSec);
+ }
+
+
+ const sal_Int32 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 };
+
+
+ static bool implIsLeapYear(sal_Int32 _nYear)
+ {
+ return ( ((_nYear % 4) == 0)
+ && ((_nYear % 100) != 0)
+ )
+
+ || ((_nYear % 400) == 0)
+ ;
+ }
+
+ static sal_Int32 implDaysInMonth(sal_Int32 _nMonth, sal_Int32 _nYear)
+ {
+ SAL_WARN_IF(_nMonth < 1 || _nMonth > 12, "connectivity.commontools", "Month has invalid value: " << _nMonth);
+ if (_nMonth < 1)
+ _nMonth = 1;
+ else if (_nMonth > 12)
+ _nMonth = 12;
+ if (_nMonth != 2)
+ return aDaysInMonth[_nMonth-1];
+ else
+ {
+ if (implIsLeapYear(_nYear))
+ return aDaysInMonth[_nMonth-1] + 1;
+ else
+ return aDaysInMonth[_nMonth-1];
+ }
+ }
+
+ static sal_Int32 implRelativeToAbsoluteNull(const css::util::Date& _rDate)
+ {
+ sal_Int32 nDays = 0;
+
+ // ripped this code from the implementation of tools::Date
+ sal_Int32 nNormalizedYear = _rDate.Year - 1;
+ nDays = nNormalizedYear * 365;
+ // leap years
+ nDays += (nNormalizedYear / 4) - (nNormalizedYear / 100) + (nNormalizedYear / 400);
+
+ for (sal_Int32 i = 1; i < _rDate.Month; ++i)
+ nDays += implDaysInMonth(i, _rDate.Year);
+
+ nDays += _rDate.Day;
+ return nDays;
+ }
+
+ static void implBuildFromRelative( const sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_Int16& rYear)
+ {
+ sal_Int32 nTempDays;
+ sal_Int32 i = 0;
+ bool bCalc;
+
+ do
+ {
+ nTempDays = nDays;
+ rYear = static_cast<sal_uInt16>((nTempDays / 365) - i);
+ nTempDays -= (rYear-1) * 365;
+ nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
+ bCalc = false;
+ if ( nTempDays < 1 )
+ {
+ i++;
+ bCalc = true;
+ }
+ else
+ {
+ if ( nTempDays > 365 )
+ {
+ if ( (nTempDays != 366) || !implIsLeapYear( rYear ) )
+ {
+ i--;
+ bCalc = true;
+ }
+ }
+ }
+ }
+ while ( bCalc );
+
+ rMonth = 1;
+ while ( nTempDays > implDaysInMonth( rMonth, rYear ) )
+ {
+ nTempDays -= implDaysInMonth( rMonth, rYear );
+ rMonth++;
+ }
+ rDay = static_cast<sal_uInt16>(nTempDays);
+ }
+
+ sal_Int32 DBTypeConversion::toDays(const css::util::Date& _rVal, const css::util::Date& _rNullDate)
+ {
+ return implRelativeToAbsoluteNull(_rVal) - implRelativeToAbsoluteNull(_rNullDate);
+ }
+
+
+ double DBTypeConversion::toDouble(const css::util::Date& rVal, const css::util::Date& _rNullDate)
+ {
+ return static_cast<double>(toDays(rVal, _rNullDate));
+ }
+
+
+ double DBTypeConversion::toDouble(const css::util::Time& rVal)
+ {
+ return static_cast<double>(getNsFromTime(rVal)) / fNanoSecondsPerDay;
+ }
+
+
+ double DBTypeConversion::toDouble(const css::util::DateTime& _rVal, const css::util::Date& _rNullDate)
+ {
+ sal_Int64 nTime = toDays(css::util::Date(_rVal.Day, _rVal.Month, _rVal.Year), _rNullDate);
+ css::util::Time aTimePart;
+
+ aTimePart.Hours = _rVal.Hours;
+ aTimePart.Minutes = _rVal.Minutes;
+ aTimePart.Seconds = _rVal.Seconds;
+ aTimePart.NanoSeconds = _rVal.NanoSeconds;
+
+ return static_cast<double>(nTime) + toDouble(aTimePart);
+ }
+
+ static void addDays(const sal_Int32 nDays, css::util::Date& _rDate)
+ {
+ sal_Int64 nTempDays = implRelativeToAbsoluteNull(_rDate);
+
+ nTempDays += nDays;
+ if ( nTempDays > maxDays )
+ {
+ _rDate.Day = 31;
+ _rDate.Month = 12;
+ _rDate.Year = 9999;
+ }
+ // TODO: can we replace that check by minDays? Would allow dates BCE
+ // implBuildFromRelative probably needs to be updated for the "no year 0" question
+ else if ( nTempDays <= 0 )
+ {
+ _rDate.Day = 1;
+ _rDate.Month = 1;
+ _rDate.Year = 1;
+ }
+ else
+ implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
+ }
+
+ static void subDays(const sal_Int32 nDays, css::util::Date& _rDate )
+ {
+ sal_Int64 nTempDays = implRelativeToAbsoluteNull(_rDate);
+
+ nTempDays -= nDays;
+ if ( nTempDays > maxDays )
+ {
+ _rDate.Day = 31;
+ _rDate.Month = 12;
+ _rDate.Year = 9999;
+ }
+ // TODO: can we replace that check by minDays? Would allow dates BCE
+ // implBuildFromRelative probably needs to be updated for the "no year 0" question
+ else if ( nTempDays <= 0 )
+ {
+ _rDate.Day = 1;
+ _rDate.Month = 1;
+ _rDate.Year = 1;
+ }
+ else
+ implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
+ }
+
+ css::util::Date DBTypeConversion::toDate(const double dVal, const css::util::Date& _rNullDate)
+ {
+ css::util::Date aRet = _rNullDate;
+
+ if (dVal >= 0)
+ addDays(static_cast<sal_Int32>(dVal),aRet);
+ else
+ subDays(static_cast<sal_uInt32>(-dVal),aRet);
+ // x -= (sal_uInt32)(-nDays);
+
+ return aRet;
+ }
+
+ css::util::Time DBTypeConversion::toTime(const double dVal, short nDigits)
+ {
+ const double nDays = std::trunc(dVal);
+ double fSeconds((dVal - nDays) * (fNanoSecondsPerDay / nanoSecInSec));
+ fSeconds = ::rtl::math::round(fSeconds, nDigits);
+ sal_Int64 nNS = fSeconds * nanoSecInSec;
+
+ sal_Int16 nSign;
+ if ( nNS < 0 )
+ {
+ nNS *= -1;
+ nSign = -1;
+ }
+ else
+ nSign = 1;
+
+ css::util::Time aRet;
+ // normalize time
+ // we have to sal_Int32 here because otherwise we get an overflow
+ sal_Int64 nNanoSeconds = nNS;
+ sal_Int32 nSeconds = nNanoSeconds / nanoSecInSec;
+ sal_Int32 nMinutes = nSeconds / secInMin;
+
+ aRet.NanoSeconds = nNanoSeconds % nanoSecInSec;
+ aRet.Seconds = nSeconds % secInMin;
+ aRet.Hours = nMinutes / minInHour;
+ aRet.Minutes = nMinutes % minInHour;
+
+ // assemble time
+ sal_Int64 nTime = nSign *
+ (aRet.NanoSeconds +
+ aRet.Seconds * secMask +
+ aRet.Minutes * minMask +
+ aRet.Hours * hourMask);
+
+ if(nTime < 0)
+ {
+ aRet.NanoSeconds = nanoSecInSec-1;
+ aRet.Seconds = secInMin-1;
+ aRet.Minutes = minInHour-1;
+ aRet.Hours = 23;
+ }
+ return aRet;
+ }
+
+ css::util::DateTime DBTypeConversion::toDateTime(const double dVal, const css::util::Date& _rNullDate)
+ {
+ css::util::DateTime aRet;
+
+ if (!std::isfinite(dVal))
+ {
+ SAL_WARN("connectivity.commontools", "DateTime has invalid value: " << dVal);
+ return aRet;
+ }
+
+ css::util::Date aDate = toDate(dVal, _rNullDate);
+ // there is not enough precision in a double to have both a date
+ // and a time up to nanoseconds -> limit to microseconds to have
+ // correct rounding, that is e.g. 13:00:00.000000000 instead of
+ // 12:59:59.999999790
+ css::util::Time aTime = toTime(dVal, 6);
+
+ aRet.Day = aDate.Day;
+ aRet.Month = aDate.Month;
+ aRet.Year = aDate.Year;
+
+ aRet.NanoSeconds = aTime.NanoSeconds;
+ aRet.Minutes = aTime.Minutes;
+ aRet.Seconds = aTime.Seconds;
+ aRet.Hours = aTime.Hours;
+
+
+ return aRet;
+ }
+
+ css::util::Date DBTypeConversion::toDate(std::u16string_view _sSQLString)
+ {
+ // get the token out of a string
+ static const sal_Unicode sDateSep = '-';
+
+ sal_Int32 nIndex = 0;
+ sal_uInt16 nYear = 0,
+ nMonth = 0,
+ nDay = 0;
+ nYear = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex)));
+ if(nIndex != -1)
+ {
+ nMonth = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex)));
+ if(nIndex != -1)
+ nDay = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(_sSQLString, 0,sDateSep,nIndex)));
+ }
+
+ return css::util::Date(nDay,nMonth,nYear);
+ }
+
+
+ css::util::DateTime DBTypeConversion::toDateTime(const OUString& _sSQLString)
+ {
+ //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Timestamp.html#valueOf(java.lang.String)
+ //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Date.html#valueOf(java.lang.String)
+ //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Time.html#valueOf(java.lang.String)
+
+ // the date part
+ css::util::Date aDate = toDate(_sSQLString);
+ css::util::Time aTime;
+ sal_Int32 nSeparation = _sSQLString.indexOf( ' ' );
+ if ( -1 != nSeparation )
+ {
+ const sal_Unicode *p = _sSQLString.getStr() + nSeparation;
+ const sal_Unicode *const begin = p;
+ while (rtl::isAsciiWhiteSpace(*p)) { ++p; }
+ nSeparation += p - begin;
+ aTime = toTime( _sSQLString.subView( nSeparation ) );
+ }
+
+ return css::util::DateTime(aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours,
+ aDate.Day, aDate.Month, aDate.Year, false);
+ }
+
+
+ css::util::Time DBTypeConversion::toTime(std::u16string_view _sSQLString)
+ {
+ css::util::Time aTime;
+ ::utl::ISO8601parseTime(_sSQLString, aTime);
+ return aTime;
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbexception.cxx b/connectivity/source/commontools/dbexception.cxx
new file mode 100644
index 000000000..e6663f7d1
--- /dev/null
+++ b/connectivity/source/commontools/dbexception.cxx
@@ -0,0 +1,495 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdb/SQLErrorEvent.hpp>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbtools
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::comphelper;
+ using namespace ::connectivity;
+
+SQLExceptionInfo::SQLExceptionInfo()
+ :m_eType(TYPE::Undefined)
+{
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo(const css::sdbc::SQLException& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo(const css::sdbc::SQLWarning& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo(const css::sdb::SQLContext& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo( const OUString& _rSimpleErrorMessage )
+{
+ SQLException aError;
+ aError.Message = _rSimpleErrorMessage;
+ m_aContent <<= aError;
+ implDetermineType();
+}
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdbc::SQLException& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdbc::SQLWarning& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdb::SQLContext& _rError)
+{
+ m_aContent <<= _rError;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdb::SQLErrorEvent& _rErrorEvent)
+{
+ m_aContent = _rErrorEvent.Reason;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo& SQLExceptionInfo::operator=(const css::uno::Any& _rCaughtSQLException)
+{
+ m_aContent = _rCaughtSQLException;
+ implDetermineType();
+ return *this;
+}
+
+
+SQLExceptionInfo::SQLExceptionInfo(const css::uno::Any& _rError)
+{
+ const css::uno::Type& aSQLExceptionType = cppu::UnoType<css::sdbc::SQLException>::get();
+ bool bValid = isAssignableFrom(aSQLExceptionType, _rError.getValueType());
+ if (bValid)
+ m_aContent = _rError;
+ // no assertion here : if used with the NextException member of an SQLException bValid==sal_False is allowed.
+
+ implDetermineType();
+}
+
+
+void SQLExceptionInfo::implDetermineType()
+{
+ const Type& aSQLExceptionType = ::cppu::UnoType<SQLException>::get();
+ const Type& aSQLWarningType = ::cppu::UnoType<SQLWarning>::get();
+ const Type& aSQLContextType = ::cppu::UnoType<SQLContext>::get();
+
+ if ( isAssignableFrom( aSQLContextType, m_aContent.getValueType() ) )
+ m_eType = TYPE::SQLContext;
+ else if ( isAssignableFrom( aSQLWarningType, m_aContent.getValueType() ) )
+ m_eType = TYPE::SQLWarning;
+ else if ( isAssignableFrom( aSQLExceptionType, m_aContent.getValueType() ) )
+ m_eType = TYPE::SQLException;
+ else
+ {
+ m_eType = TYPE::Undefined;
+ m_aContent.clear();
+ }
+}
+
+
+bool SQLExceptionInfo::isKindOf(TYPE _eType) const
+{
+ switch (_eType)
+ {
+ case TYPE::SQLContext:
+ return (m_eType == TYPE::SQLContext);
+ case TYPE::SQLWarning:
+ return (m_eType == TYPE::SQLContext) || (m_eType == TYPE::SQLWarning);
+ case TYPE::SQLException:
+ return (m_eType == TYPE::SQLContext) || (m_eType == TYPE::SQLWarning) || (m_eType == TYPE::SQLException);
+ case TYPE::Undefined:
+ return (m_eType == TYPE::Undefined);
+ }
+ return false;
+}
+
+
+SQLExceptionInfo::operator const css::sdbc::SQLException*() const
+{
+ OSL_ENSURE(isKindOf(TYPE::SQLException), "SQLExceptionInfo::operator SQLException* : invalid call !");
+ return o3tl::doAccess<css::sdbc::SQLException>(m_aContent);
+}
+
+
+SQLExceptionInfo::operator const css::sdb::SQLContext*() const
+{
+ OSL_ENSURE(isKindOf(TYPE::SQLContext), "SQLExceptionInfo::operator SQLException* : invalid call !");
+ return o3tl::doAccess<css::sdb::SQLContext>(m_aContent);
+}
+
+
+void SQLExceptionInfo::prepend( const OUString& _rErrorMessage )
+{
+ SQLException aException;
+ aException.Message = _rErrorMessage;
+ aException.ErrorCode = 0;
+ aException.SQLState = "S1000";
+ aException.NextException = m_aContent;
+ m_aContent <<= aException;
+
+ m_eType = TYPE::SQLException;
+}
+
+// create the to-be-appended exception
+Any SQLExceptionInfo::createException(TYPE eType, const OUString& rErrorMessage, const OUString& rSQLState, const sal_Int32 nErrorCode)
+{
+ Any aAppend;
+ switch (eType)
+ {
+ case TYPE::SQLException:
+ aAppend <<= SQLException();
+ break;
+ case TYPE::SQLWarning:
+ aAppend <<= SQLWarning();
+ break;
+ case TYPE::SQLContext:
+ aAppend <<= SQLContext();
+ break;
+ default:
+ TOOLS_WARN_EXCEPTION("connectivity.commontools", "SQLExceptionInfo::createException: invalid exception type: this will crash!");
+ break;
+ }
+
+ SQLException& pAppendException = const_cast<SQLException &>(*o3tl::forceAccess<SQLException>(aAppend));
+ pAppendException.Message = rErrorMessage;
+ pAppendException.SQLState = rSQLState;
+ pAppendException.ErrorCode = nErrorCode;
+
+ return aAppend;
+}
+
+// find the end of the exception chain
+SQLException* SQLExceptionInfo::getLastException(SQLException* pLastException)
+{
+ SQLException* pException = pLastException;
+ while (pException)
+ {
+ pException = const_cast<SQLException*>(o3tl::tryAccess<SQLException>(pException->NextException));
+ if (!pException)
+ break;
+ pLastException = pException;
+ }
+ return pLastException;
+}
+
+void SQLExceptionInfo::append( TYPE _eType, const OUString& _rErrorMessage, const OUString& _rSQLState, const sal_Int32 _nErrorCode )
+{
+ // create the to-be-appended exception
+ Any aAppend = createException(_eType, _rErrorMessage, _rSQLState, _nErrorCode);
+
+ // find the end of the current chain
+ SQLException* pLastException = getLastException(const_cast<SQLException*>(o3tl::tryAccess<SQLException>(m_aContent)));
+
+ // append
+ if (pLastException)
+ pLastException->NextException = aAppend;
+ else
+ {
+ m_aContent = aAppend;
+ m_eType = _eType;
+ }
+}
+
+void SQLExceptionInfo::doThrow()
+{
+ if ( m_aContent.getValueTypeClass() == TypeClass_EXCEPTION )
+ ::cppu::throwException( m_aContent );
+ throw RuntimeException();
+}
+
+SQLExceptionIteratorHelper::SQLExceptionIteratorHelper( const SQLExceptionInfo& _rChainStart )
+ :m_pCurrent( nullptr )
+ ,m_eCurrentType( SQLExceptionInfo::TYPE::Undefined )
+{
+ if ( _rChainStart.isValid() )
+ {
+ m_pCurrent = _rChainStart;
+ m_eCurrentType = _rChainStart.getType();
+ }
+}
+
+
+SQLExceptionIteratorHelper::SQLExceptionIteratorHelper( const css::sdbc::SQLException& _rChainStart )
+ :m_pCurrent( &_rChainStart )
+ ,m_eCurrentType( SQLExceptionInfo::TYPE::SQLException )
+{
+}
+
+
+void SQLExceptionIteratorHelper::current( SQLExceptionInfo& _out_rInfo ) const
+{
+ switch ( m_eCurrentType )
+ {
+ case SQLExceptionInfo::TYPE::SQLException:
+ _out_rInfo = *m_pCurrent;
+ break;
+
+ case SQLExceptionInfo::TYPE::SQLWarning:
+ _out_rInfo = *static_cast< const SQLWarning* >( m_pCurrent );
+ break;
+
+ case SQLExceptionInfo::TYPE::SQLContext:
+ _out_rInfo = *static_cast< const SQLContext* >( m_pCurrent );
+ break;
+
+ default:
+ _out_rInfo = Any();
+ break;
+ }
+}
+
+
+const css::sdbc::SQLException* SQLExceptionIteratorHelper::next()
+{
+ OSL_ENSURE( hasMoreElements(), "SQLExceptionIteratorHelper::next : invalid call (please use hasMoreElements)!" );
+
+ const css::sdbc::SQLException* pReturn = m_pCurrent;
+ if ( !m_pCurrent )
+ return pReturn;
+
+ // check for the next element within the chain
+ const Type aTypeException( ::cppu::UnoType< SQLException >::get() );
+
+ Type aNextElementType = m_pCurrent->NextException.getValueType();
+ if ( !isAssignableFrom( aTypeException, aNextElementType ) )
+ {
+ // no SQLException at all in the next chain element
+ m_pCurrent = nullptr;
+ m_eCurrentType = SQLExceptionInfo::TYPE::Undefined;
+ return pReturn;
+ }
+
+ m_pCurrent = o3tl::doAccess< SQLException >( m_pCurrent->NextException );
+
+ // no finally determine the proper type of the exception
+ const Type aTypeContext( ::cppu::UnoType< SQLContext >::get() );
+ if ( isAssignableFrom( aTypeContext, aNextElementType ) )
+ {
+ m_eCurrentType = SQLExceptionInfo::TYPE::SQLContext;
+ return pReturn;
+ }
+
+ const Type aTypeWarning( ::cppu::UnoType< SQLWarning >::get() );
+ if ( isAssignableFrom( aTypeWarning, aNextElementType ) )
+ {
+ m_eCurrentType = SQLExceptionInfo::TYPE::SQLWarning;
+ return pReturn;
+ }
+
+ // a simple SQLException
+ m_eCurrentType = SQLExceptionInfo::TYPE::SQLException;
+ return pReturn;
+}
+
+
+void SQLExceptionIteratorHelper::next( SQLExceptionInfo& _out_rInfo )
+{
+ current( _out_rInfo );
+ next();
+}
+
+
+void throwFunctionSequenceException(const Reference< XInterface >& Context, const Any& Next)
+{
+ ::connectivity::SharedResources aResources;
+ throw SQLException(
+ aResources.getResourceString(STR_ERRORMSG_SEQUENCE),
+ Context,
+ getStandardSQLState( StandardSQLState::FUNCTION_SEQUENCE_ERROR ),
+ 0,
+ Next
+ );
+}
+
+void throwInvalidIndexException(const css::uno::Reference< css::uno::XInterface >& Context,
+ const css::uno::Any& Next)
+{
+ ::connectivity::SharedResources aResources;
+ throw SQLException(
+ aResources.getResourceString(STR_INVALID_INDEX),
+ Context,
+ getStandardSQLState( StandardSQLState::INVALID_DESCRIPTOR_INDEX ),
+ 0,
+ Next
+ );
+}
+
+void throwFunctionNotSupportedSQLException(const OUString& _rFunctionName,
+ const css::uno::Reference<css::uno::XInterface>& _rxContext)
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNSUPPORTED_FUNCTION,
+ "$functionname$", _rFunctionName
+ ) );
+ throw SQLException(
+ sError,
+ _rxContext,
+ getStandardSQLState( StandardSQLState::FUNCTION_NOT_SUPPORTED ),
+ 0,
+ css::uno::Any()
+ );
+}
+
+void throwFunctionNotSupportedRuntimeException(const OUString& _rFunctionName,
+ const css::uno::Reference<css::uno::XInterface>& _rxContext)
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNSUPPORTED_FUNCTION,
+ "$functionname$", _rFunctionName
+ ) );
+ throw RuntimeException(
+ sError,
+ _rxContext
+ );
+}
+
+void throwGenericSQLException(const OUString& _rMsg, const css::uno::Reference< css::uno::XInterface >& _rxSource)
+{
+ throwGenericSQLException(_rMsg, _rxSource, Any());
+}
+
+
+void throwGenericSQLException(const OUString& _rMsg, const Reference< XInterface >& _rxSource, const Any& _rNextException)
+{
+ throw SQLException( _rMsg, _rxSource, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 0, _rNextException);
+}
+
+void throwFeatureNotImplementedSQLException( const OUString& _rFeatureName, const Reference< XInterface >& _rxContext, const Any& _rNextException )
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNSUPPORTED_FEATURE,
+ "$featurename$", _rFeatureName
+ ) );
+
+ throw SQLException(
+ sError,
+ _rxContext,
+ getStandardSQLState( StandardSQLState::FEATURE_NOT_IMPLEMENTED ),
+ 0,
+ _rNextException
+ );
+}
+
+void throwFeatureNotImplementedRuntimeException(const OUString& _rFeatureName, const Reference< XInterface >& _rxContext)
+{
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNSUPPORTED_FEATURE,
+ "$featurename$", _rFeatureName
+ ) );
+
+ throw RuntimeException(sError, _rxContext);
+}
+
+void throwInvalidColumnException( const OUString& _rColumnName, const Reference< XInterface >& _rxContext)
+{
+ ::connectivity::SharedResources aResources;
+ OUString sErrorMessage( aResources.getResourceStringWithSubstitution(
+ STR_INVALID_COLUMNNAME,
+ "$columnname$",_rColumnName) );
+ throwSQLException( sErrorMessage, StandardSQLState::COLUMN_NOT_FOUND, _rxContext );
+}
+
+void throwSQLException( const OUString& _rMessage, const OUString& _rSQLState,
+ const Reference< XInterface >& _rxContext, const sal_Int32 _nErrorCode )
+{
+ throw SQLException(
+ _rMessage,
+ _rxContext,
+ _rSQLState,
+ _nErrorCode,
+ Any()
+ );
+}
+
+
+void throwSQLException( const OUString& _rMessage, StandardSQLState _eSQLState,
+ const Reference< XInterface >& _rxContext, const sal_Int32 _nErrorCode )
+{
+ throwSQLException( _rMessage, getStandardSQLState( _eSQLState ), _rxContext, _nErrorCode );
+}
+
+
+OUString getStandardSQLState( StandardSQLState _eState )
+{
+ switch ( _eState )
+ {
+ case StandardSQLState::INVALID_DESCRIPTOR_INDEX: return "07009";
+ case StandardSQLState::INVALID_CURSOR_STATE: return "24000";
+ case StandardSQLState::COLUMN_NOT_FOUND: return "42S22";
+ case StandardSQLState::GENERAL_ERROR: return "HY000";
+ case StandardSQLState::INVALID_SQL_DATA_TYPE: return "HY004";
+ case StandardSQLState::FUNCTION_SEQUENCE_ERROR: return "HY010";
+ case StandardSQLState::INVALID_CURSOR_POSITION: return "HY109";
+ case StandardSQLState::FEATURE_NOT_IMPLEMENTED: return "HYC00";
+ case StandardSQLState::FUNCTION_NOT_SUPPORTED: return "IM001";
+ case StandardSQLState::CONNECTION_DOES_NOT_EXIST: return "08003";
+ default: return "HY001"; // General Error
+ }
+}
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbmetadata.cxx b/connectivity/source/commontools/dbmetadata.cxx
new file mode 100644
index 000000000..7eb148735
--- /dev/null
+++ b/connectivity/source/commontools/dbmetadata.cxx
@@ -0,0 +1,443 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/dbmetadata.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/DriversConfig.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sal/log.hxx>
+
+#include <optional>
+
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdbc::XDatabaseMetaData;
+ using ::com::sun::star::sdbc::XDatabaseMetaData2;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::container::XChild;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::sdbcx::XUsersSupplier;
+ using ::com::sun::star::sdbcx::XDataDefinitionSupplier;
+ using ::com::sun::star::sdbc::DriverManager;
+ using ::com::sun::star::sdbc::XDriverManager2;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+
+ namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode;
+
+ struct DatabaseMetaData_Impl
+ {
+ Reference< XConnection > xConnection;
+ Reference< XDatabaseMetaData > xConnectionMetaData;
+ ::connectivity::DriversConfig aDriverConfig;
+
+ ::std::optional< OUString > sCachedIdentifierQuoteString;
+ ::std::optional< OUString > sCachedCatalogSeparator;
+
+ DatabaseMetaData_Impl()
+ : aDriverConfig( ::comphelper::getProcessComponentContext() )
+ {
+ }
+ };
+
+
+ namespace
+ {
+
+ void lcl_construct( DatabaseMetaData_Impl& _metaDataImpl, const Reference< XConnection >& _connection )
+ {
+ _metaDataImpl.xConnection = _connection;
+ if ( !_metaDataImpl.xConnection.is() )
+ return;
+
+ _metaDataImpl.xConnectionMetaData = _connection->getMetaData();
+ if ( !_metaDataImpl.xConnectionMetaData.is() )
+ throw IllegalArgumentException();
+ }
+
+
+ void lcl_checkConnected( const DatabaseMetaData_Impl& _metaDataImpl )
+ {
+ if ( !_metaDataImpl.xConnection.is() || !_metaDataImpl.xConnectionMetaData.is() )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceString(STR_NO_CONNECTION_GIVEN));
+ throwSQLException( sError, StandardSQLState::CONNECTION_DOES_NOT_EXIST, nullptr );
+ }
+ }
+
+
+ bool lcl_getDriverSetting( const OUString& _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting )
+ {
+ lcl_checkConnected( _metaData );
+ const ::comphelper::NamedValueCollection& rDriverMetaData = _metaData.aDriverConfig.getMetaData( _metaData.xConnectionMetaData->getURL() );
+ if ( !rDriverMetaData.has( _asciiName ) )
+ return false;
+ _out_setting = rDriverMetaData.get( _asciiName );
+ return true;
+ }
+
+
+ bool lcl_getConnectionSetting(const OUString& _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting )
+ {
+ try
+ {
+ Reference< XChild > xConnectionAsChild( _metaData.xConnection, UNO_QUERY );
+ if ( xConnectionAsChild.is() )
+ {
+ Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY_THROW );
+ Reference< XPropertySet > xDataSourceSettings(
+ xDataSource->getPropertyValue("Settings"),
+ UNO_QUERY_THROW );
+
+ _out_setting = xDataSourceSettings->getPropertyValue( _asciiName );
+ }
+ else
+ {
+ Reference< XDatabaseMetaData2 > xExtendedMetaData( _metaData.xConnectionMetaData, UNO_QUERY_THROW );
+ _out_setting = ::comphelper::NamedValueCollection::get( xExtendedMetaData->getConnectionInfo(), _asciiName );
+ return _out_setting.hasValue();
+ }
+ return true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return false;
+ }
+
+
+ const OUString& lcl_getConnectionStringSetting(
+ const DatabaseMetaData_Impl& _metaData, ::std::optional< OUString >& _cachedSetting,
+ OUString (SAL_CALL XDatabaseMetaData::*_getter)() )
+ {
+ if ( !_cachedSetting )
+ {
+ lcl_checkConnected( _metaData );
+ try
+ {
+ _cachedSetting = (_metaData.xConnectionMetaData.get()->*_getter)();
+ }
+ catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); }
+ }
+ return *_cachedSetting;
+ }
+ }
+
+ DatabaseMetaData::DatabaseMetaData()
+ :m_pImpl( new DatabaseMetaData_Impl )
+ {
+ }
+
+ DatabaseMetaData::DatabaseMetaData( const Reference< XConnection >& _connection )
+ :m_pImpl( new DatabaseMetaData_Impl )
+ {
+ lcl_construct( *m_pImpl, _connection );
+ }
+
+
+ DatabaseMetaData::DatabaseMetaData( const DatabaseMetaData& _copyFrom )
+ :m_pImpl( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) )
+ {
+ }
+
+ DatabaseMetaData::DatabaseMetaData(DatabaseMetaData&& _copyFrom) noexcept
+ :m_pImpl(std::move(_copyFrom.m_pImpl))
+ {
+ }
+
+ DatabaseMetaData& DatabaseMetaData::operator=( const DatabaseMetaData& _copyFrom )
+ {
+ if ( this == &_copyFrom )
+ return *this;
+
+ m_pImpl.reset( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) );
+ return *this;
+ }
+
+ DatabaseMetaData& DatabaseMetaData::operator=(DatabaseMetaData&& _copyFrom) noexcept
+ {
+ m_pImpl = std::move(_copyFrom.m_pImpl);
+ return *this;
+ }
+
+ DatabaseMetaData::~DatabaseMetaData()
+ {
+ }
+
+ bool DatabaseMetaData::isConnected() const
+ {
+ return m_pImpl->xConnection.is();
+ }
+
+
+ bool DatabaseMetaData::supportsSubqueriesInFrom() const
+ {
+ lcl_checkConnected( *m_pImpl );
+
+ bool bSupportsSubQueries = false;
+ try
+ {
+ sal_Int32 maxTablesInselect = m_pImpl->xConnectionMetaData->getMaxTablesInSelect();
+ bSupportsSubQueries = ( maxTablesInselect > 1 ) || ( maxTablesInselect == 0 );
+ // TODO: is there a better way to determine this? The above is not really true. More precise,
+ // it's a *very* generous heuristics ...
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bSupportsSubQueries;
+ }
+
+
+ bool DatabaseMetaData::supportsPrimaryKeys() const
+ {
+ lcl_checkConnected( *m_pImpl );
+
+ bool bDoesSupportPrimaryKeys = false;
+ try
+ {
+ Any setting;
+ if ( !( lcl_getConnectionSetting( "PrimaryKeySupport", *m_pImpl, setting ) )
+ || !( setting >>= bDoesSupportPrimaryKeys )
+ )
+ bDoesSupportPrimaryKeys = m_pImpl->xConnectionMetaData->supportsCoreSQLGrammar()
+ || m_pImpl->xConnectionMetaData->supportsANSI92EntryLevelSQL();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bDoesSupportPrimaryKeys;
+ }
+
+
+ const OUString& DatabaseMetaData::getIdentifierQuoteString() const
+ {
+ return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedIdentifierQuoteString, &XDatabaseMetaData::getIdentifierQuoteString );
+ }
+
+
+ const OUString& DatabaseMetaData::getCatalogSeparator() const
+ {
+ return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedCatalogSeparator, &XDatabaseMetaData::getCatalogSeparator );
+ }
+
+
+ bool DatabaseMetaData::restrictIdentifiersToSQL92() const
+ {
+ lcl_checkConnected( *m_pImpl );
+
+ bool restrict( false );
+ Any setting;
+ if ( lcl_getConnectionSetting( "EnableSQL92Check", *m_pImpl, setting ) )
+ if( ! (setting >>= restrict) )
+ SAL_WARN("connectivity.commontools", "restrictIdentifiersToSQL92: unable to assign EnableSQL92Check");
+ return restrict;
+ }
+
+
+ bool DatabaseMetaData::generateASBeforeCorrelationName() const
+ {
+ bool doGenerate( false );
+ Any setting;
+ if ( lcl_getConnectionSetting( "GenerateASBeforeCorrelationName", *m_pImpl, setting ) )
+ if( ! (setting >>= doGenerate) )
+ SAL_WARN("connectivity.commontools", "generateASBeforeCorrelationName: unable to assign GenerateASBeforeCorrelationName");
+ return doGenerate;
+ }
+
+ bool DatabaseMetaData::shouldEscapeDateTime() const
+ {
+ bool doGenerate( true );
+ Any setting;
+ if ( lcl_getConnectionSetting( "EscapeDateTime", *m_pImpl, setting ) )
+ if( ! (setting >>= doGenerate) )
+ SAL_WARN("connectivity.commontools", "shouldEscapeDateTime: unable to assign EscapeDateTime");
+ return doGenerate;
+ }
+
+ bool DatabaseMetaData::shouldSubstituteParameterNames() const
+ {
+ bool doSubstitute( true );
+ Any setting;
+ if ( lcl_getConnectionSetting( "ParameterNameSubstitution", *m_pImpl, setting ) )
+ if( ! (setting >>= doSubstitute) )
+ SAL_WARN("connectivity.commontools", "shouldSubstituteParameterNames: unable to assign ParameterNameSubstitution");
+ return doSubstitute;
+ }
+
+ bool DatabaseMetaData::isAutoIncrementPrimaryKey() const
+ {
+ bool is( true );
+ Any setting;
+ if ( lcl_getDriverSetting( "AutoIncrementIsPrimaryKey", *m_pImpl, setting ) )
+ if( ! (setting >>= is) )
+ SAL_WARN("connectivity.commontools", "isAutoIncrementPrimaryKey: unable to assign AutoIncrementIsPrimaryKey");
+ return is;
+ }
+
+ sal_Int32 DatabaseMetaData::getBooleanComparisonMode() const
+ {
+ sal_Int32 mode( BooleanComparisonMode::EQUAL_INTEGER );
+ Any setting;
+ if ( lcl_getConnectionSetting( "BooleanComparisonMode", *m_pImpl, setting ) )
+ if( ! (setting >>= mode) )
+ SAL_WARN("connectivity.commontools", "getBooleanComparisonMode: unable to assign BooleanComparisonMode");
+ return mode;
+ }
+
+ bool DatabaseMetaData::supportsRelations() const
+ {
+ lcl_checkConnected( *m_pImpl );
+ bool bSupport = false;
+ try
+ {
+ bSupport = m_pImpl->xConnectionMetaData->supportsIntegrityEnhancementFacility();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ try
+ {
+ if ( !bSupport )
+ {
+ const OUString url = m_pImpl->xConnectionMetaData->getURL();
+ bSupport = url.startsWith("sdbc:mysql");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bSupport;
+ }
+
+
+ bool DatabaseMetaData::supportsColumnAliasInOrderBy() const
+ {
+ bool doGenerate( true );
+ Any setting;
+ if ( lcl_getConnectionSetting( "ColumnAliasInOrderBy", *m_pImpl, setting ) )
+ if( ! (setting >>= doGenerate) )
+ SAL_WARN("connectivity.commontools", "supportsColumnAliasInOrderBy: unable to assign ColumnAliasInOrderBy");
+ return doGenerate;
+ }
+
+
+ bool DatabaseMetaData::supportsUserAdministration( const Reference<XComponentContext>& _rContext ) const
+ {
+ lcl_checkConnected( *m_pImpl );
+
+ bool isSupported( false );
+ try
+ {
+ // find the XUsersSupplier interface
+ // - either directly at the connection
+ Reference< XUsersSupplier > xUsersSupp( m_pImpl->xConnection, UNO_QUERY );
+ if ( !xUsersSupp.is() )
+ {
+ // - or at the driver manager
+ Reference< XDriverManager2 > xDriverManager = DriverManager::create( _rContext );
+ Reference< XDataDefinitionSupplier > xDriver( xDriverManager->getDriverByURL( m_pImpl->xConnectionMetaData->getURL() ), UNO_QUERY );
+ if ( xDriver.is() )
+ xUsersSupp.set( xDriver->getDataDefinitionByConnection( m_pImpl->xConnection ), UNO_QUERY );
+ }
+
+ isSupported = ( xUsersSupp.is() && xUsersSupp->getUsers().is() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return isSupported;
+ }
+
+
+ bool DatabaseMetaData::displayEmptyTableFolders() const
+ {
+ bool doDisplay( true );
+#ifdef IMPLEMENTED_LATER
+ Any setting;
+ if ( lcl_getConnectionSetting( "DisplayEmptyTableFolders", *m_pImpl, setting ) )
+ if( ! (setting >>= doDisplay) )
+ SAL_WARN("connectivity.commontools", "displayEmptyTableFolders: unable to assign DisplayEmptyTableFolders");
+#else
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW );
+ OUString sConnectionURL( xMeta->getURL() );
+ doDisplay = sConnectionURL.startsWith( "sdbc:mysql:mysqlc" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+#endif
+ return doDisplay;
+ }
+
+ bool DatabaseMetaData::supportsThreads() const
+ {
+ bool bSupported( true );
+ try
+ {
+ Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW );
+ OUString sConnectionURL( xMeta->getURL() );
+ bSupported = !sConnectionURL.startsWith( "sdbc:mysql:mysqlc" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bSupported;
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbtools.cxx b/connectivity/source/commontools/dbtools.cxx
new file mode 100644
index 000000000..7f6f5fb17
--- /dev/null
+++ b/connectivity/source/commontools/dbtools.cxx
@@ -0,0 +1,2073 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/CommonTools.hxx>
+#include <TConnection.hxx>
+#include <ParameterCont.hxx>
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/ErrorMessageDialog.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdb/RowSetVetoException.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/ConnectionPool.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/NumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/conncleanup.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/statementcomposer.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/stream.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::ui::dialogs;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::form;
+using namespace connectivity;
+
+namespace dbtools
+{
+
+namespace
+{
+ typedef sal_Bool (SAL_CALL XDatabaseMetaData::*FMetaDataSupport)();
+}
+
+sal_Int32 getDefaultNumberFormat(const Reference< XPropertySet >& _xColumn,
+ const Reference< XNumberFormatTypes >& _xTypes,
+ const Locale& _rLocale)
+{
+ OSL_ENSURE(_xTypes.is() && _xColumn.is(), "dbtools::getDefaultNumberFormat: invalid arg !");
+ if (!_xTypes.is() || !_xColumn.is())
+ return NumberFormat::UNDEFINED;
+
+ sal_Int32 nDataType = 0;
+ sal_Int32 nScale = 0;
+ try
+ {
+ // determine the datatype of the column
+ _xColumn->getPropertyValue("Type") >>= nDataType;
+
+ if (DataType::NUMERIC == nDataType || DataType::DECIMAL == nDataType)
+ _xColumn->getPropertyValue("Scale") >>= nScale;
+ }
+ catch (Exception&)
+ {
+ return NumberFormat::UNDEFINED;
+ }
+ return getDefaultNumberFormat(nDataType,
+ nScale,
+ ::cppu::any2bool(_xColumn->getPropertyValue("IsCurrency")),
+ _xTypes,
+ _rLocale);
+}
+
+sal_Int32 getDefaultNumberFormat(sal_Int32 _nDataType,
+ sal_Int32 _nScale,
+ bool _bIsCurrency,
+ const Reference< XNumberFormatTypes >& _xTypes,
+ const Locale& _rLocale)
+{
+ OSL_ENSURE(_xTypes.is() , "dbtools::getDefaultNumberFormat: invalid arg !");
+ if (!_xTypes.is())
+ return NumberFormat::UNDEFINED;
+
+ sal_Int32 nFormat = 0;
+ sal_Int32 nNumberType = _bIsCurrency ? NumberFormat::CURRENCY : NumberFormat::NUMBER;
+ switch (_nDataType)
+ {
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::LOGICAL, _rLocale);
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ {
+ try
+ {
+ nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
+ if(_nScale > 0)
+ {
+ // generate a new format if necessary
+ Reference< XNumberFormats > xFormats(_xTypes, UNO_QUERY);
+ OUString sNewFormat = xFormats->generateFormat( 0, _rLocale, false, false, static_cast<sal_Int16>(_nScale), 1);
+
+ // and add it to the formatter if necessary
+ nFormat = xFormats->queryKey(sNewFormat, _rLocale, false);
+ if (nFormat == sal_Int32(-1))
+ nFormat = xFormats->addNew(sNewFormat, _rLocale);
+ }
+ }
+ catch (Exception&)
+ {
+ nFormat = _xTypes->getStandardFormat(static_cast<sal_Int16>(nNumberType), _rLocale);
+ }
+ } break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::TEXT, _rLocale);
+ break;
+ case DataType::DATE:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::DATE, _rLocale);
+ break;
+ case DataType::TIME:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::TIME, _rLocale);
+ break;
+ case DataType::TIMESTAMP:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::DATETIME, _rLocale);
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::SQLNULL:
+ case DataType::OTHER:
+ case DataType::OBJECT:
+ case DataType::DISTINCT:
+ case DataType::STRUCT:
+ case DataType::ARRAY:
+ case DataType::BLOB:
+ case DataType::REF:
+ default:
+ nFormat = _xTypes->getStandardFormat(NumberFormat::UNDEFINED, _rLocale);
+ }
+ return nFormat;
+}
+
+static Reference< XConnection> findConnection(const Reference< XInterface >& xParent)
+{
+ Reference< XConnection> xConnection(xParent, UNO_QUERY);
+ if (!xConnection.is())
+ {
+ Reference< XChild> xChild(xParent, UNO_QUERY);
+ if (xChild.is())
+ xConnection = findConnection(xChild->getParent());
+ }
+ return xConnection;
+}
+
+static Reference< XDataSource> getDataSource_allowException(
+ const OUString& _rsTitleOrPath,
+ const Reference< XComponentContext >& _rxContext )
+{
+ ENSURE_OR_RETURN( !_rsTitleOrPath.isEmpty(), "getDataSource_allowException: invalid arg !", nullptr );
+
+ Reference< XDatabaseContext> xDatabaseContext = DatabaseContext::create(_rxContext);
+
+ return Reference< XDataSource >( xDatabaseContext->getByName( _rsTitleOrPath ), UNO_QUERY );
+}
+
+Reference< XDataSource > getDataSource(
+ const OUString& _rsTitleOrPath,
+ const Reference< XComponentContext >& _rxContext )
+{
+ Reference< XDataSource > xDS;
+ try
+ {
+ xDS = getDataSource_allowException( _rsTitleOrPath, _rxContext );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ return xDS;
+}
+
+static Reference< XConnection > getConnection_allowException(
+ const OUString& _rsTitleOrPath,
+ const OUString& _rsUser,
+ const OUString& _rsPwd,
+ const Reference< XComponentContext>& _rxContext,
+ const Reference< XWindow >& _rxParent)
+{
+ Reference< XDataSource> xDataSource( getDataSource_allowException(_rsTitleOrPath, _rxContext) );
+ Reference<XConnection> xConnection;
+ if (xDataSource.is())
+ {
+
+ //set ParentWindow for dialog, but just for the duration of this
+ //call, undo at end of scope
+ Reference<XInitialization> xIni(xDataSource, UNO_QUERY);
+ if (xIni.is())
+ {
+ Sequence< Any > aArgs{ Any(NamedValue( "ParentWindow", Any(_rxParent) )) };
+ xIni->initialize(aArgs);
+ }
+
+ // do it with interaction handler
+ if(_rsUser.isEmpty() || _rsPwd.isEmpty())
+ {
+ Reference<XPropertySet> xProp(xDataSource,UNO_QUERY);
+ OUString sPwd, sUser;
+ bool bPwdReq = false;
+ try
+ {
+ xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
+ bPwdReq = ::cppu::any2bool(xProp->getPropertyValue("IsPasswordRequired"));
+ xProp->getPropertyValue("User") >>= sUser;
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("dbtools::getConnection: error while retrieving data source properties!");
+ }
+ if(bPwdReq && sPwd.isEmpty())
+ { // password required, but empty -> connect using an interaction handler
+ Reference<XCompletedConnection> xConnectionCompletion(xProp, UNO_QUERY);
+ if (xConnectionCompletion.is())
+ { // instantiate the default SDB interaction handler
+ Reference< XInteractionHandler > xHandler =
+ InteractionHandler::createWithParent(_rxContext, _rxParent);
+ xConnection = xConnectionCompletion->connectWithCompletion(xHandler);
+ }
+ }
+ else
+ xConnection = xDataSource->getConnection(sUser, sPwd);
+ }
+ if(!xConnection.is()) // try to get one if not already have one, just to make sure
+ xConnection = xDataSource->getConnection(_rsUser, _rsPwd);
+
+ if (xIni.is())
+ {
+ Sequence< Any > aArgs{ Any(NamedValue( "ParentWindow", Any(Reference<XWindow>()) )) };
+ xIni->initialize(aArgs);
+ }
+
+ }
+ return xConnection;
+}
+
+Reference< XConnection> getConnection_withFeedback(const OUString& _rDataSourceName,
+ const OUString& _rUser, const OUString& _rPwd, const Reference< XComponentContext>& _rxContext,
+ const Reference< XWindow >& _rxParent)
+{
+ Reference< XConnection > xReturn;
+ try
+ {
+ xReturn = getConnection_allowException(_rDataSourceName, _rUser, _rPwd, _rxContext, _rxParent);
+ }
+ catch(SQLException&)
+ {
+ // allowed to pass
+ throw;
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getConnection_withFeedback: unexpected (non-SQL) exception caught!");
+ }
+ return xReturn;
+}
+
+Reference< XConnection> getConnection(const Reference< XRowSet>& _rxRowSet)
+{
+ Reference< XConnection> xReturn;
+ Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY);
+ if (xRowSetProps.is())
+ xRowSetProps->getPropertyValue("ActiveConnection") >>= xReturn;
+ return xReturn;
+}
+
+// helper function which allows to implement both the connectRowset and the ensureRowSetConnection semantics
+// if connectRowset (which is deprecated) is removed, this function and one of its parameters are
+// not needed anymore, the whole implementation can be moved into ensureRowSetConnection then)
+static SharedConnection lcl_connectRowSet(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext,
+ bool _bAttachAutoDisposer, const Reference< XWindow >& _rxParent)
+{
+ SharedConnection xConnection;
+
+ do
+ {
+ Reference< XPropertySet> xRowSetProps(_rxRowSet, UNO_QUERY);
+ if ( !xRowSetProps.is() )
+ break;
+
+ // 1. already connected?
+ Reference< XConnection > xExistingConn(
+ xRowSetProps->getPropertyValue("ActiveConnection"),
+ UNO_QUERY );
+
+ if ( xExistingConn.is()
+ // 2. embedded in a database?
+ || isEmbeddedInDatabase( _rxRowSet, xExistingConn )
+ // 3. is there a connection in the parent hierarchy?
+ || ( xExistingConn = findConnection( _rxRowSet ) ).is()
+ )
+ {
+ xRowSetProps->setPropertyValue("ActiveConnection", Any( xExistingConn ) );
+ // no auto disposer needed, since we did not create the connection
+
+ xConnection.reset( xExistingConn, SharedConnection::NoTakeOwnership );
+ break;
+ }
+
+ // build a connection with its current settings (4. data source name, or 5. URL)
+
+ static const OUStringLiteral sUserProp( u"User" );
+ OUString sDataSourceName;
+ xRowSetProps->getPropertyValue("DataSourceName") >>= sDataSourceName;
+ OUString sURL;
+ xRowSetProps->getPropertyValue("URL") >>= sURL;
+
+ Reference< XConnection > xPureConnection;
+ if (!sDataSourceName.isEmpty())
+ { // the row set's data source property is set
+ // -> try to connect, get user and pwd setting for that
+ OUString sUser, sPwd;
+
+ if (hasProperty(sUserProp, xRowSetProps))
+ xRowSetProps->getPropertyValue(sUserProp) >>= sUser;
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps))
+ xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
+
+ xPureConnection = getConnection_allowException( sDataSourceName, sUser, sPwd, _rxContext, _rxParent );
+ }
+ else if (!sURL.isEmpty())
+ { // the row set has no data source, but a connection url set
+ // -> try to connection with that url
+ Reference< XConnectionPool > xDriverManager;
+ try {
+ xDriverManager = ConnectionPool::create( _rxContext );
+ } catch( const Exception& ) { }
+ if (xDriverManager.is())
+ {
+ OUString sUser, sPwd;
+ if (hasProperty(sUserProp, xRowSetProps))
+ xRowSetProps->getPropertyValue(sUserProp) >>= sUser;
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps))
+ xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd;
+ if (!sUser.isEmpty())
+ { // use user and pwd together with the url
+ auto aInfo(::comphelper::InitPropertySequence({
+ { "user", Any(sUser) },
+ { "password", Any(sPwd) }
+ }));
+ xPureConnection = xDriverManager->getConnectionWithInfo( sURL, aInfo );
+ }
+ else
+ // just use the url
+ xPureConnection = xDriverManager->getConnection( sURL );
+ }
+ }
+ xConnection.reset(
+ xPureConnection,
+ _bAttachAutoDisposer ? SharedConnection::NoTakeOwnership : SharedConnection::TakeOwnership
+ /* take ownership if and only if we're *not* going to auto-dispose the connection */
+ );
+
+ // now if we created a connection, forward it to the row set
+ if ( xConnection.is() )
+ {
+ try
+ {
+ if ( _bAttachAutoDisposer )
+ {
+ new OAutoConnectionDisposer( _rxRowSet, xConnection );
+ }
+ else
+ xRowSetProps->setPropertyValue(
+ "ActiveConnection",
+ Any( xConnection.getTyped() )
+ );
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "EXception when we set the new active connection!");
+ }
+ }
+ }
+ while ( false );
+
+ return xConnection;
+}
+
+Reference< XConnection> connectRowset(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent)
+{
+ SharedConnection xConnection = lcl_connectRowSet( _rxRowSet, _rxContext, true, _rxParent );
+ return xConnection.getTyped();
+}
+
+SharedConnection ensureRowSetConnection(const Reference< XRowSet>& _rxRowSet, const Reference< XComponentContext>& _rxContext, const Reference< XWindow >& _rxParent)
+{
+ return lcl_connectRowSet( _rxRowSet, _rxContext, false/*bUseAutoConnectionDisposer*/, _rxParent );
+}
+
+Reference< XNameAccess> getTableFields(const Reference< XConnection>& _rxConn,const OUString& _rName)
+{
+ Reference< XComponent > xDummy;
+ return getFieldsByCommandDescriptor( _rxConn, CommandType::TABLE, _rName, xDummy );
+}
+
+Reference< XNameAccess> getPrimaryKeyColumns_throw(const Any& i_aTable)
+{
+ const Reference< XPropertySet > xTable(i_aTable,UNO_QUERY_THROW);
+ return getPrimaryKeyColumns_throw(xTable);
+}
+
+Reference< XNameAccess> getPrimaryKeyColumns_throw(const Reference< XPropertySet >& i_xTable)
+{
+ Reference<XNameAccess> xKeyColumns;
+ const Reference<XKeysSupplier> xKeySup(i_xTable,UNO_QUERY);
+ if ( xKeySup.is() )
+ {
+ const Reference<XIndexAccess> xKeys = xKeySup->getKeys();
+ if ( xKeys.is() )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ const OUString& sPropName = rPropMap.getNameByIndex(PROPERTY_ID_TYPE);
+ Reference<XPropertySet> xProp;
+ const sal_Int32 nCount = xKeys->getCount();
+ for(sal_Int32 i = 0;i< nCount;++i)
+ {
+ xProp.set(xKeys->getByIndex(i),UNO_QUERY_THROW);
+ sal_Int32 nKeyType = 0;
+ xProp->getPropertyValue(sPropName) >>= nKeyType;
+ if(KeyType::PRIMARY == nKeyType)
+ {
+ const Reference<XColumnsSupplier> xKeyColsSup(xProp,UNO_QUERY_THROW);
+ xKeyColumns = xKeyColsSup->getColumns();
+ break;
+ }
+ }
+ }
+ }
+
+ return xKeyColumns;
+}
+
+namespace
+{
+ enum FieldLookupState
+ {
+ HANDLE_TABLE, HANDLE_QUERY, HANDLE_SQL, RETRIEVE_OBJECT, RETRIEVE_COLUMNS, DONE, FAILED
+ };
+}
+
+Reference< XNameAccess > getFieldsByCommandDescriptor( const Reference< XConnection >& _rxConnection,
+ const sal_Int32 _nCommandType, const OUString& _rCommand,
+ Reference< XComponent >& _rxKeepFieldsAlive, SQLExceptionInfo* _pErrorInfo )
+{
+ OSL_PRECOND( _rxConnection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection!" );
+ OSL_PRECOND( ( CommandType::TABLE == _nCommandType ) || ( CommandType::QUERY == _nCommandType ) || ( CommandType::COMMAND == _nCommandType ),
+ "::dbtools::getFieldsByCommandDescriptor: invalid command type!" );
+ OSL_PRECOND( !_rCommand.isEmpty(), "::dbtools::getFieldsByCommandDescriptor: invalid command (empty)!" );
+
+ Reference< XNameAccess > xFields;
+
+ // reset the error
+ if ( _pErrorInfo )
+ *_pErrorInfo = SQLExceptionInfo();
+ // reset the ownership holder
+ _rxKeepFieldsAlive.clear();
+
+ // go for the fields
+ try
+ {
+ // some kind of state machine to ease the sharing of code
+ FieldLookupState eState = FAILED;
+ switch ( _nCommandType )
+ {
+ case CommandType::TABLE:
+ eState = HANDLE_TABLE;
+ break;
+ case CommandType::QUERY:
+ eState = HANDLE_QUERY;
+ break;
+ case CommandType::COMMAND:
+ eState = HANDLE_SQL;
+ break;
+ }
+
+ // needed in various states:
+ Reference< XNameAccess > xObjectCollection;
+ Reference< XColumnsSupplier > xSupplyColumns;
+
+ // go!
+ while ( ( DONE != eState ) && ( FAILED != eState ) )
+ {
+ switch ( eState )
+ {
+ case HANDLE_TABLE:
+ {
+ // initial state for handling the tables
+
+ // get the table objects
+ Reference< XTablesSupplier > xSupplyTables( _rxConnection, UNO_QUERY );
+ if ( xSupplyTables.is() )
+ xObjectCollection = xSupplyTables->getTables();
+ // if something went wrong 'til here, then this will be handled in the next state
+
+ // next state: get the object
+ eState = RETRIEVE_OBJECT;
+ }
+ break;
+
+ case HANDLE_QUERY:
+ {
+ // initial state for handling the tables
+
+ // get the table objects
+ Reference< XQueriesSupplier > xSupplyQueries( _rxConnection, UNO_QUERY );
+ if ( xSupplyQueries.is() )
+ xObjectCollection = xSupplyQueries->getQueries();
+ // if something went wrong 'til here, then this will be handled in the next state
+
+ // next state: get the object
+ eState = RETRIEVE_OBJECT;
+ }
+ break;
+
+ case RETRIEVE_OBJECT:
+ // here we should have an object (aka query or table) collection, and are going
+ // to retrieve the desired object
+
+ // next state: default to FAILED
+ eState = FAILED;
+
+ OSL_ENSURE( xObjectCollection.is(), "::dbtools::getFieldsByCommandDescriptor: invalid connection (no sdb.Connection, or no Tables-/QueriesSupplier)!");
+ if ( xObjectCollection.is() && xObjectCollection->hasByName( _rCommand ) )
+ {
+ xObjectCollection->getByName( _rCommand ) >>= xSupplyColumns;
+ // (xSupplyColumns being NULL will be handled in the next state)
+
+ // next: go for the columns
+ eState = RETRIEVE_COLUMNS;
+ }
+ break;
+
+ case RETRIEVE_COLUMNS:
+ OSL_ENSURE( xSupplyColumns.is(), "::dbtools::getFieldsByCommandDescriptor: could not retrieve the columns supplier!" );
+
+ // next state: default to FAILED
+ eState = FAILED;
+
+ if ( xSupplyColumns.is() )
+ {
+ xFields = xSupplyColumns->getColumns();
+ // that's it
+ eState = DONE;
+ }
+ break;
+
+ case HANDLE_SQL:
+ {
+ OUString sStatementToExecute( _rCommand );
+
+ // well, the main problem here is to handle statements which contain a parameter
+ // If we would simply execute a parametrized statement, then this will fail because
+ // we cannot supply any parameter values.
+ // Thus, we try to analyze the statement, and to append a WHERE 0=1 filter criterion
+ // This should cause every driver to not really execute the statement, but to return
+ // an empty result set with the proper structure. We then can use this result set
+ // to retrieve the columns.
+
+ try
+ {
+ Reference< XMultiServiceFactory > xComposerFac( _rxConnection, UNO_QUERY );
+
+ if ( xComposerFac.is() )
+ {
+ Reference< XSingleSelectQueryComposer > xComposer(xComposerFac->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),UNO_QUERY);
+ if ( xComposer.is() )
+ {
+ xComposer->setQuery( sStatementToExecute );
+
+ // Now set the filter to a dummy restriction which will result in an empty
+ // result set.
+ xComposer->setFilter( "0=1" );
+ sStatementToExecute = xComposer->getQuery( );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ // silent this error, this was just a try. If we're here, we did not change sStatementToExecute,
+ // so it will still be _rCommand, which then will be executed without being touched
+ }
+
+ // now execute
+ Reference< XPreparedStatement > xStatement = _rxConnection->prepareStatement( sStatementToExecute );
+ // transfer ownership of this temporary object to the caller
+ _rxKeepFieldsAlive.set(xStatement, css::uno::UNO_QUERY);
+
+ // set the "MaxRows" to 0. This is just in case our attempt to append a 0=1 filter
+ // failed - in this case, the MaxRows restriction should at least ensure that there
+ // is no data returned (which would be potentially expensive)
+ Reference< XPropertySet > xStatementProps( xStatement,UNO_QUERY );
+ try
+ {
+ if ( xStatementProps.is() )
+ xStatementProps->setPropertyValue( "MaxRows", Any( sal_Int32( 0 ) ) );
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: could not set the MaxRows!" );
+ // oh damn. Not much of a chance to recover, we will no retrieve the complete
+ // full blown result set
+ }
+
+ xSupplyColumns.set(xStatement->executeQuery(), css::uno::UNO_QUERY);
+ // this should have given us a result set which does not contain any data, but
+ // the structural information we need
+
+ // so the next state is to get the columns
+ eState = RETRIEVE_COLUMNS;
+ }
+ break;
+
+ default:
+ OSL_FAIL( "::dbtools::getFieldsByCommandDescriptor: oops! unhandled state here!" );
+ eState = FAILED;
+ }
+ }
+ }
+ catch( const SQLContext& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
+ catch( const SQLWarning& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
+ catch( const SQLException& e ) { if ( _pErrorInfo ) *_pErrorInfo = SQLExceptionInfo( e ); }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::dbtools::getFieldsByCommandDescriptor: caught an exception while retrieving the fields!" );
+ }
+
+ return xFields;
+}
+
+Sequence< OUString > getFieldNamesByCommandDescriptor( const Reference< XConnection >& _rxConnection,
+ const sal_Int32 _nCommandType, const OUString& _rCommand,
+ SQLExceptionInfo* _pErrorInfo )
+{
+ // get the container for the fields
+ Reference< XComponent > xKeepFieldsAlive;
+ Reference< XNameAccess > xFieldContainer = getFieldsByCommandDescriptor( _rxConnection, _nCommandType, _rCommand, xKeepFieldsAlive, _pErrorInfo );
+
+ // get the names of the fields
+ Sequence< OUString > aNames;
+ if ( xFieldContainer.is() )
+ aNames = xFieldContainer->getElementNames();
+
+ // clean up any temporary objects which have been created
+ disposeComponent( xKeepFieldsAlive );
+
+ // outta here
+ return aNames;
+}
+
+SQLException prependErrorInfo( const SQLException& _rChainedException, const Reference< XInterface >& _rxContext,
+ const OUString& _rAdditionalError, const StandardSQLState _eSQLState )
+{
+ return SQLException( _rAdditionalError, _rxContext,
+ _eSQLState == StandardSQLState::ERROR_UNSPECIFIED ? OUString() : getStandardSQLState( _eSQLState ),
+ 0, Any( _rChainedException ) );
+}
+
+namespace
+{
+ struct NameComponentSupport
+ {
+ const bool bCatalogs;
+ const bool bSchemas;
+
+ NameComponentSupport( const bool _bCatalogs, const bool _bSchemas )
+ :bCatalogs( _bCatalogs )
+ ,bSchemas( _bSchemas )
+ {
+ }
+ };
+
+ NameComponentSupport lcl_getNameComponentSupport( const Reference< XDatabaseMetaData >& _rxMetaData, EComposeRule _eComposeRule )
+ {
+ OSL_PRECOND( _rxMetaData.is(), "lcl_getNameComponentSupport: invalid meta data!" );
+
+ FMetaDataSupport pCatalogCall = &XDatabaseMetaData::supportsCatalogsInDataManipulation;
+ FMetaDataSupport pSchemaCall = &XDatabaseMetaData::supportsSchemasInDataManipulation;
+ bool bIgnoreMetaData = false;
+
+ switch ( _eComposeRule )
+ {
+ case EComposeRule::InTableDefinitions:
+ pCatalogCall = &XDatabaseMetaData::supportsCatalogsInTableDefinitions;
+ pSchemaCall = &XDatabaseMetaData::supportsSchemasInTableDefinitions;
+ break;
+ case EComposeRule::InIndexDefinitions:
+ pCatalogCall = &XDatabaseMetaData::supportsCatalogsInIndexDefinitions;
+ pSchemaCall = &XDatabaseMetaData::supportsSchemasInIndexDefinitions;
+ break;
+ case EComposeRule::InProcedureCalls:
+ pCatalogCall = &XDatabaseMetaData::supportsCatalogsInProcedureCalls;
+ pSchemaCall = &XDatabaseMetaData::supportsSchemasInProcedureCalls;
+ break;
+ case EComposeRule::InPrivilegeDefinitions:
+ pCatalogCall = &XDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions;
+ pSchemaCall = &XDatabaseMetaData::supportsSchemasInPrivilegeDefinitions;
+ break;
+ case EComposeRule::Complete:
+ bIgnoreMetaData = true;
+ break;
+ case EComposeRule::InDataManipulation:
+ // already properly set above
+ break;
+ }
+ return NameComponentSupport(
+ bIgnoreMetaData || (_rxMetaData.get()->*pCatalogCall)(),
+ bIgnoreMetaData || (_rxMetaData.get()->*pSchemaCall)()
+ );
+ }
+}
+
+static OUString impl_doComposeTableName( const Reference< XDatabaseMetaData >& _rxMetaData,
+ const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName,
+ bool _bQuote, EComposeRule _eComposeRule )
+{
+ OSL_ENSURE(_rxMetaData.is(), "impl_doComposeTableName : invalid meta data !");
+ if ( !_rxMetaData.is() )
+ return OUString();
+ OSL_ENSURE(!_rName.isEmpty(), "impl_doComposeTableName : at least the name should be non-empty !");
+
+ const OUString sQuoteString = _rxMetaData->getIdentifierQuoteString();
+ const NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxMetaData, _eComposeRule ) );
+
+ OUStringBuffer aComposedName;
+
+ OUString sCatalogSep;
+ bool bCatlogAtStart = true;
+ if ( !_rCatalog.isEmpty() && aNameComps.bCatalogs )
+ {
+ sCatalogSep = _rxMetaData->getCatalogSeparator();
+ bCatlogAtStart = _rxMetaData->isCatalogAtStart();
+
+ if ( bCatlogAtStart && !sCatalogSep.isEmpty())
+ {
+ aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog );
+ aComposedName.append( sCatalogSep );
+ }
+ }
+
+ if ( !_rSchema.isEmpty() && aNameComps.bSchemas )
+ {
+ aComposedName.append( _bQuote ? quoteName( sQuoteString, _rSchema ) : _rSchema );
+ aComposedName.append( "." );
+ }
+
+ aComposedName.append( _bQuote ? quoteName( sQuoteString, _rName ) : _rName );
+
+ if ( !_rCatalog.isEmpty()
+ && !bCatlogAtStart
+ && !sCatalogSep.isEmpty()
+ && aNameComps.bCatalogs
+ )
+ {
+ aComposedName.append( sCatalogSep );
+ aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog );
+ }
+
+ return aComposedName.makeStringAndClear();
+}
+
+OUString quoteTableName(const Reference< XDatabaseMetaData>& _rxMeta
+ , const OUString& _rName
+ , EComposeRule _eComposeRule)
+{
+ OUString sCatalog, sSchema, sTable;
+ qualifiedNameComponents(_rxMeta,_rName,sCatalog,sSchema,sTable,_eComposeRule);
+ return impl_doComposeTableName( _rxMeta, sCatalog, sSchema, sTable, true, _eComposeRule );
+}
+
+void qualifiedNameComponents(const Reference< XDatabaseMetaData >& _rxConnMetaData, const OUString& _rQualifiedName, OUString& _rCatalog, OUString& _rSchema, OUString& _rName,EComposeRule _eComposeRule)
+{
+ OSL_ENSURE(_rxConnMetaData.is(), "QualifiedNameComponents : invalid meta data!");
+
+ NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxConnMetaData, _eComposeRule ) );
+
+ OUString sSeparator = _rxConnMetaData->getCatalogSeparator();
+
+ OUString sName(_rQualifiedName);
+ // do we have catalogs?
+ if ( aNameComps.bCatalogs )
+ {
+ if (_rxConnMetaData->isCatalogAtStart())
+ {
+ // search for the catalog name at the beginning
+ sal_Int32 nIndex = sName.indexOf(sSeparator);
+ if (-1 != nIndex)
+ {
+ _rCatalog = sName.copy(0, nIndex);
+ sName = sName.copy(nIndex + 1);
+ }
+ }
+ else
+ {
+ // Catalog name at the end
+ sal_Int32 nIndex = sName.lastIndexOf(sSeparator);
+ if (-1 != nIndex)
+ {
+ _rCatalog = sName.copy(nIndex + 1);
+ sName = sName.copy(0, nIndex);
+ }
+ }
+ }
+
+ if ( aNameComps.bSchemas )
+ {
+ sal_Int32 nIndex = sName.indexOf('.');
+ // OSL_ENSURE(-1 != nIndex, "QualifiedNameComponents: no schema separator!");
+ if ( nIndex != -1 )
+ _rSchema = sName.copy(0, nIndex);
+ sName = sName.copy(nIndex + 1);
+ }
+
+ _rName = sName;
+}
+
+Reference< XNumberFormatsSupplier> getNumberFormats(
+ const Reference< XConnection>& _rxConn,
+ bool _bAlloweDefault,
+ const Reference< XComponentContext>& _rxContext)
+{
+ // ask the parent of the connection (should be a DatabaseAccess)
+ Reference< XNumberFormatsSupplier> xReturn;
+ Reference< XChild> xConnAsChild(_rxConn, UNO_QUERY);
+ static constexpr OUStringLiteral sPropFormatsSupplier( u"NumberFormatsSupplier" );
+ if (xConnAsChild.is())
+ {
+ Reference< XPropertySet> xConnParentProps(xConnAsChild->getParent(), UNO_QUERY);
+ if (xConnParentProps.is() && hasProperty(sPropFormatsSupplier, xConnParentProps))
+ xConnParentProps->getPropertyValue(sPropFormatsSupplier) >>= xReturn;
+ }
+ else if(_bAlloweDefault && _rxContext.is())
+ {
+ xReturn = NumberFormatsSupplier::createWithDefaultLocale( _rxContext );
+ }
+ return xReturn;
+}
+
+void TransferFormComponentProperties(
+ const Reference< XPropertySet>& xOldProps,
+ const Reference< XPropertySet>& xNewProps,
+ const Locale& _rLocale)
+{
+try
+{
+ OSL_ENSURE( xOldProps.is() && xNewProps.is(), "TransferFormComponentProperties: invalid source/dest!" );
+ if ( !xOldProps.is() || !xNewProps.is() )
+ return;
+
+ // First we copy all the Props, that are available in source and target and have the same description
+ Reference< XPropertySetInfo> xOldInfo( xOldProps->getPropertySetInfo());
+ Reference< XPropertySetInfo> xNewInfo( xNewProps->getPropertySetInfo());
+
+ const Sequence< Property> aOldProperties = xOldInfo->getProperties();
+ const Sequence< Property> aNewProperties = xNewInfo->getProperties();
+
+ static constexpr OUStringLiteral sPropFormatsSupplier(u"FormatsSupplier");
+ static constexpr OUStringLiteral sPropCurrencySymbol(u"CurrencySymbol");
+ static constexpr OUStringLiteral sPropDecimals(u"Decimals");
+ static constexpr OUStringLiteral sPropEffectiveMin(u"EffectiveMin");
+ static constexpr OUStringLiteral sPropEffectiveMax(u"EffectiveMax");
+ static constexpr OUStringLiteral sPropEffectiveDefault(u"EffectiveDefault");
+ static constexpr OUStringLiteral sPropDefaultText(u"DefaultText");
+ static constexpr OUStringLiteral sPropDefaultDate(u"DefaultDate");
+ static constexpr OUStringLiteral sPropDefaultTime(u"DefaultTime");
+ static constexpr OUStringLiteral sPropValueMin(u"ValueMin");
+ static constexpr OUStringLiteral sPropValueMax(u"ValueMax");
+ static constexpr OUStringLiteral sPropDecimalAccuracy(u"DecimalAccuracy");
+ static constexpr OUStringLiteral sPropClassId(u"ClassId");
+ static constexpr OUStringLiteral sFormattedServiceName( u"com.sun.star.form.component.FormattedField" );
+
+ for (const Property& rOldProp : aOldProperties)
+ {
+ if ( rOldProp.Name != "DefaultControl" && rOldProp.Name != "LabelControl" )
+ {
+ // binary search
+ const Property* pResult = std::lower_bound(
+ aNewProperties.begin(), aNewProperties.end(), rOldProp, ::comphelper::PropertyCompareByName());
+
+ if ( ( pResult != aNewProperties.end() )
+ && ( pResult->Name == rOldProp.Name )
+ && ( (pResult->Attributes & PropertyAttribute::READONLY) == 0 )
+ && ( pResult->Type.equals(rOldProp.Type)) )
+ { // Attributes match and the property is not read-only
+ try
+ {
+ xNewProps->setPropertyValue(pResult->Name, xOldProps->getPropertyValue(pResult->Name));
+ }
+ catch(IllegalArgumentException const &)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties : could not transfer the value for property \""
+ << pResult->Name << "\"");
+ }
+ }
+ }
+ }
+
+ // for formatted fields (either old or new) we have some special treatments
+ Reference< XServiceInfo > xSI( xOldProps, UNO_QUERY );
+ bool bOldIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName );
+ xSI.set( xNewProps, UNO_QUERY );
+ bool bNewIsFormatted = xSI.is() && xSI->supportsService( sFormattedServiceName );
+
+ if (!bOldIsFormatted && !bNewIsFormatted)
+ return; // nothing to do
+
+ if (bOldIsFormatted && bNewIsFormatted)
+ // if both fields are formatted we do no conversions
+ return;
+
+ if (bOldIsFormatted)
+ {
+ // get some properties from the selected format and put them in the new Set
+ Any aFormatKey( xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) );
+ if (aFormatKey.hasValue())
+ {
+ Reference< XNumberFormatsSupplier> xSupplier;
+ xOldProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier;
+ if (xSupplier.is())
+ {
+ Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
+ Reference< XPropertySet> xFormat(xFormats->getByKey(getINT32(aFormatKey)));
+ if (hasProperty(sPropCurrencySymbol, xFormat))
+ {
+ Any aVal( xFormat->getPropertyValue(sPropCurrencySymbol) );
+ if (aVal.hasValue() && hasProperty(sPropCurrencySymbol, xNewProps))
+ // If the source value hasn't been set then don't copy it
+ // so we don't overwrite the default value
+ xNewProps->setPropertyValue(sPropCurrencySymbol, aVal);
+ }
+ if (hasProperty(sPropDecimals, xFormat) && hasProperty(sPropDecimals, xNewProps))
+ xNewProps->setPropertyValue(sPropDecimals, xFormat->getPropertyValue(sPropDecimals));
+ }
+ }
+
+ // a potential Min-Max-Conversion
+ Any aEffectiveMin( xOldProps->getPropertyValue(sPropEffectiveMin) );
+ if (aEffectiveMin.hasValue())
+ { // Unlike the ValueMin the EffectiveMin can be void
+ if (hasProperty(sPropValueMin, xNewProps))
+ {
+ OSL_ENSURE(aEffectiveMin.getValueType().getTypeClass() == TypeClass_DOUBLE,
+ "TransferFormComponentProperties : invalid property type !");
+ xNewProps->setPropertyValue(sPropValueMin, aEffectiveMin);
+ }
+ }
+ Any aEffectiveMax( xOldProps->getPropertyValue(sPropEffectiveMax) );
+ if (aEffectiveMax.hasValue())
+ { // analog
+ if (hasProperty(sPropValueMax, xNewProps))
+ {
+ OSL_ENSURE(aEffectiveMax.getValueType().getTypeClass() == TypeClass_DOUBLE,
+ "TransferFormComponentProperties : invalid property type !");
+ xNewProps->setPropertyValue(sPropValueMax, aEffectiveMax);
+ }
+ }
+
+ // then we can still convert and copy the default values
+ Any aEffectiveDefault( xOldProps->getPropertyValue(sPropEffectiveDefault) );
+ if (aEffectiveDefault.hasValue())
+ {
+ bool bIsString = aEffectiveDefault.getValueType().getTypeClass() == TypeClass_STRING;
+ OSL_ENSURE(bIsString || aEffectiveDefault.getValueType().getTypeClass() == TypeClass_DOUBLE,
+ "TransferFormComponentProperties : invalid property type !");
+ // The Effective-Properties should always be void or string or double...
+
+ if (hasProperty(sPropDefaultDate, xNewProps) && !bIsString)
+ { // (to convert an OUString into a date will not always succeed, because it might be bound to a text-column,
+ // but we can work with a double)
+ Date aDate = DBTypeConversion::toDate(getDouble(aEffectiveDefault));
+ xNewProps->setPropertyValue(sPropDefaultDate, Any(aDate));
+ }
+
+ if (hasProperty(sPropDefaultTime, xNewProps) && !bIsString)
+ { // Completely analogous to time
+ css::util::Time aTime = DBTypeConversion::toTime(getDouble(aEffectiveDefault));
+ xNewProps->setPropertyValue(sPropDefaultTime, Any(aTime));
+ }
+
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xNewProps) && !bIsString)
+ { // Here we can simply pass the double
+ xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), aEffectiveDefault);
+ }
+
+ if (hasProperty(sPropDefaultText, xNewProps) && bIsString)
+ { // and here the OUString
+ xNewProps->setPropertyValue(sPropDefaultText, aEffectiveDefault);
+ }
+
+ // nyi: The translation between doubles and OUString would offer more alternatives
+ }
+ }
+
+ // The other direction: the new Control shall be formatted
+ if (bNewIsFormatted)
+ {
+ // first the formatting
+ // we can't set a Supplier, so the new Set must bring one in
+ Reference< XNumberFormatsSupplier> xSupplier;
+ xNewProps->getPropertyValue(sPropFormatsSupplier) >>= xSupplier;
+ if (xSupplier.is())
+ {
+ Reference< XNumberFormats> xFormats(xSupplier->getNumberFormats());
+
+ // Set number of decimals
+ sal_Int16 nDecimals = 2;
+ if (hasProperty(sPropDecimalAccuracy, xOldProps))
+ xOldProps->getPropertyValue(sPropDecimalAccuracy) >>= nDecimals;
+
+ // base format (depending on the ClassId of the old Set)
+ sal_Int32 nBaseKey = 0;
+ if (hasProperty(sPropClassId, xOldProps))
+ {
+ Reference< XNumberFormatTypes> xTypeList(xFormats, UNO_QUERY);
+ if (xTypeList.is())
+ {
+ sal_Int16 nClassId = 0;
+ xOldProps->getPropertyValue(sPropClassId) >>= nClassId;
+ switch (nClassId)
+ {
+ case FormComponentType::DATEFIELD :
+ nBaseKey = xTypeList->getStandardFormat(NumberFormat::DATE, _rLocale);
+ break;
+
+ case FormComponentType::TIMEFIELD :
+ nBaseKey = xTypeList->getStandardFormat(NumberFormat::TIME, _rLocale);
+ break;
+
+ case FormComponentType::CURRENCYFIELD :
+ nBaseKey = xTypeList->getStandardFormat(NumberFormat::CURRENCY, _rLocale);
+ break;
+ }
+ }
+ }
+
+ // With this we can generate a new format ...
+ OUString sNewFormat = xFormats->generateFormat(nBaseKey, _rLocale, false, false, nDecimals, 0);
+ // No thousands separator, negative numbers are not in red, no leading zeros
+
+ // ... and add at FormatsSupplier (if needed)
+ sal_Int32 nKey = xFormats->queryKey(sNewFormat, _rLocale, false);
+ if (nKey == sal_Int32(-1))
+ { // not added yet in my formatter ...
+ nKey = xFormats->addNew(sNewFormat, _rLocale);
+ }
+
+ xNewProps->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY), Any(nKey));
+ }
+
+ // min-/max-Value
+ Any aNewMin, aNewMax;
+ if (hasProperty(sPropValueMin, xOldProps))
+ aNewMin = xOldProps->getPropertyValue(sPropValueMin);
+ if (hasProperty(sPropValueMax, xOldProps))
+ aNewMax = xOldProps->getPropertyValue(sPropValueMax);
+ xNewProps->setPropertyValue(sPropEffectiveMin, aNewMin);
+ xNewProps->setPropertyValue(sPropEffectiveMax, aNewMax);
+
+ // Default-Value
+ Any aNewDefault;
+ if (hasProperty(sPropDefaultDate, xOldProps))
+ {
+ Any aDate( xOldProps->getPropertyValue(sPropDefaultDate) );
+ if (aDate.hasValue())
+ aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Date>(aDate));
+ }
+
+ if (hasProperty(sPropDefaultTime, xOldProps))
+ {
+ Any aTime( xOldProps->getPropertyValue(sPropDefaultTime) );
+ if (aTime.hasValue())
+ aNewDefault <<= DBTypeConversion::toDouble(*o3tl::doAccess<Time>(aTime));
+ }
+
+ // double or OUString will be copied directly
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), xOldProps))
+ aNewDefault = xOldProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE));
+ if (hasProperty(sPropDefaultText, xOldProps))
+ aNewDefault = xOldProps->getPropertyValue(sPropDefaultText);
+
+ if (aNewDefault.hasValue())
+ xNewProps->setPropertyValue(sPropEffectiveDefault, aNewDefault);
+ }
+}
+catch(const Exception&)
+{
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "TransferFormComponentProperties" );
+}
+}
+
+bool canInsert(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::INSERT) != 0);
+}
+
+bool canUpdate(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::UPDATE) != 0);
+}
+
+bool canDelete(const Reference< XPropertySet>& _rxCursorSet)
+{
+ return (_rxCursorSet.is() && (getINT32(_rxCursorSet->getPropertyValue("Privileges")) & Privilege::DELETE) != 0);
+}
+
+Reference< XDataSource> findDataSource(const Reference< XInterface >& _xParent)
+{
+ Reference< XOfficeDatabaseDocument> xDatabaseDocument(_xParent, UNO_QUERY);
+ Reference< XDataSource> xDataSource;
+ if ( xDatabaseDocument.is() )
+ xDataSource = xDatabaseDocument->getDataSource();
+ if ( !xDataSource.is() )
+ xDataSource.set(_xParent, UNO_QUERY);
+ if (!xDataSource.is())
+ {
+ Reference< XChild> xChild(_xParent, UNO_QUERY);
+ if ( xChild.is() )
+ xDataSource = findDataSource(xChild->getParent());
+ }
+ return xDataSource;
+}
+
+static Reference< XSingleSelectQueryComposer > getComposedRowSetStatement( const Reference< XPropertySet >& _rxRowSet, const Reference< XComponentContext >& _rxContext, const Reference< XWindow >& _rxParent )
+{
+ Reference< XSingleSelectQueryComposer > xComposer;
+ try
+ {
+ Reference< XConnection> xConn = connectRowset( Reference< XRowSet >( _rxRowSet, UNO_QUERY ), _rxContext, _rxParent );
+ if ( xConn.is() ) // implies _rxRowSet.is()
+ {
+ // build the statement the row set is based on (can't use the ActiveCommand property of the set
+ // as this reflects the status after the last execute, not the currently set properties)
+
+ sal_Int32 nCommandType = CommandType::COMMAND;
+ OUString sCommand;
+ bool bEscapeProcessing = false;
+
+ OSL_VERIFY( _rxRowSet->getPropertyValue("CommandType") >>= nCommandType );
+ OSL_VERIFY( _rxRowSet->getPropertyValue("Command") >>= sCommand );
+ OSL_VERIFY( _rxRowSet->getPropertyValue("EscapeProcessing") >>= bEscapeProcessing );
+
+ StatementComposer aComposer( xConn, sCommand, nCommandType, bEscapeProcessing );
+ // append sort
+ aComposer.setOrder( getString( _rxRowSet->getPropertyValue("Order") ) );
+
+ // append filter
+ bool bApplyFilter = true;
+ _rxRowSet->getPropertyValue("ApplyFilter") >>= bApplyFilter;
+ if ( bApplyFilter )
+ {
+ aComposer.setFilter( getString( _rxRowSet->getPropertyValue("Filter") ) );
+ aComposer.setHavingClause( getString( _rxRowSet->getPropertyValue("HavingClause") ) );
+ }
+
+ aComposer.getQuery();
+
+ xComposer = aComposer.getComposer();
+ aComposer.setDisposeComposer( false );
+ }
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ return xComposer;
+}
+
+Reference< XSingleSelectQueryComposer > getCurrentSettingsComposer(
+ const Reference< XPropertySet>& _rxRowSetProps,
+ const Reference< XComponentContext>& _rxContext,
+ const Reference< XWindow >& _rxParent)
+{
+ Reference< XSingleSelectQueryComposer > xReturn;
+ try
+ {
+ xReturn = getComposedRowSetStatement( _rxRowSetProps, _rxContext, _rxParent );
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "::getCurrentSettingsComposer : caught an exception !" );
+ }
+
+ return xReturn;
+}
+
+OUString composeTableName( const Reference< XDatabaseMetaData >& _rxMetaData,
+ const OUString& _rCatalog,
+ const OUString& _rSchema,
+ const OUString& _rName,
+ bool _bQuote,
+ EComposeRule _eComposeRule)
+{
+ return impl_doComposeTableName( _rxMetaData, _rCatalog, _rSchema, _rName, _bQuote, _eComposeRule );
+}
+
+OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection,
+ const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName )
+{
+ bool bUseCatalogInSelect = isDataSourcePropertyEnabled( _rxConnection, "UseCatalogInSelect", true );
+ bool bUseSchemaInSelect = isDataSourcePropertyEnabled( _rxConnection, "UseSchemaInSelect", true );
+
+ return impl_doComposeTableName(
+ _rxConnection->getMetaData(),
+ bUseCatalogInSelect ? _rCatalog : OUString(),
+ bUseSchemaInSelect ? _rSchema : OUString(),
+ _rName,
+ true,
+ EComposeRule::InDataManipulation
+ );
+}
+
+namespace
+{
+ void lcl_getTableNameComponents( const Reference<XPropertySet>& _xTable,
+ OUString& _out_rCatalog, OUString& _out_rSchema, OUString& _out_rName )
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ Reference< XPropertySetInfo > xInfo;
+ if (_xTable.is())
+ xInfo = _xTable->getPropertySetInfo();
+ if ( xInfo.is()
+ && xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) )
+ {
+ if ( xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))
+ && xInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) )
+ {
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= _out_rCatalog;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= _out_rSchema;
+ }
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= _out_rName;
+ }
+ else
+ OSL_FAIL( "::dbtools::lcl_getTableNameComponents: this is no table object!" );
+ }
+}
+
+OUString composeTableNameForSelect( const Reference< XConnection >& _rxConnection, const Reference<XPropertySet>& _xTable )
+{
+ OUString sCatalog, sSchema, sName;
+ lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
+
+ return composeTableNameForSelect( _rxConnection, sCatalog, sSchema, sName );
+}
+
+OUString composeTableName(const Reference<XDatabaseMetaData>& _xMetaData,
+ const Reference<XPropertySet>& _xTable,
+ EComposeRule _eComposeRule,
+ bool _bQuote )
+{
+ OUString sCatalog, sSchema, sName;
+ lcl_getTableNameComponents( _xTable, sCatalog, sSchema, sName );
+
+ return impl_doComposeTableName(
+ _xMetaData,
+ sCatalog,
+ sSchema,
+ sName,
+ _bQuote,
+ _eComposeRule
+ );
+}
+
+sal_Int32 getSearchColumnFlag( const Reference< XConnection>& _rxConn,sal_Int32 _nDataType)
+{
+ sal_Int32 nSearchFlag = 0;
+ Reference<XResultSet> xSet = _rxConn->getMetaData()->getTypeInfo();
+ if(xSet.is())
+ {
+ Reference<XRow> xRow(xSet,UNO_QUERY);
+ while(xSet->next())
+ {
+ if(xRow->getInt(2) == _nDataType)
+ {
+ nSearchFlag = xRow->getInt(9);
+ break;
+ }
+ }
+ }
+ return nSearchFlag;
+}
+
+OUString createUniqueName( const Sequence< OUString >& _rNames, const OUString& _rBaseName, bool _bStartWithNumber )
+{
+ std::set< OUString > aUsedNames(_rNames.begin(), _rNames.end());
+
+ OUString sName( _rBaseName );
+ sal_Int32 nPos = 1;
+ if ( _bStartWithNumber )
+ sName += OUString::number( nPos );
+
+ while ( aUsedNames.find( sName ) != aUsedNames.end() )
+ {
+ sName = _rBaseName + OUString::number( ++nPos );
+ }
+ return sName;
+}
+
+OUString createUniqueName(const Reference<XNameAccess>& _rxContainer,const OUString& _rBaseName, bool _bStartWithNumber)
+{
+ Sequence< OUString > aElementNames;
+
+ OSL_ENSURE( _rxContainer.is(), "createUniqueName: invalid container!" );
+ if ( _rxContainer.is() )
+ aElementNames = _rxContainer->getElementNames();
+
+ return createUniqueName( aElementNames, _rBaseName, _bStartWithNumber );
+}
+
+void showError(const SQLExceptionInfo& _rInfo,
+ const Reference< XWindow>& _xParent,
+ const Reference< XComponentContext >& _rxContext)
+{
+ if (_rInfo.isValid())
+ {
+ try
+ {
+ Reference< XExecutableDialog > xErrorDialog = ErrorMessageDialog::create( _rxContext, "", _xParent, _rInfo.get() );
+ xErrorDialog->execute();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("showError: could not display the error message!");
+ }
+ }
+}
+
+bool implUpdateObject(const Reference< XRowUpdate >& _rxUpdatedObject,
+ const sal_Int32 _nColumnIndex, const Any& _rValue)
+{
+ bool bSuccessfullyReRouted = true;
+ switch (_rValue.getValueTypeClass())
+ {
+ case TypeClass_ANY:
+ {
+ bSuccessfullyReRouted = implUpdateObject(_rxUpdatedObject, _nColumnIndex, _rValue);
+ }
+ break;
+
+ case TypeClass_VOID:
+ _rxUpdatedObject->updateNull(_nColumnIndex);
+ break;
+
+ case TypeClass_STRING:
+ _rxUpdatedObject->updateString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
+ break;
+
+ case TypeClass_BOOLEAN:
+ _rxUpdatedObject->updateBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
+ break;
+
+ case TypeClass_BYTE:
+ _rxUpdatedObject->updateByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
+ break;
+
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_SHORT:
+ _rxUpdatedObject->updateShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
+ break;
+
+ case TypeClass_CHAR:
+ _rxUpdatedObject->updateString(_nColumnIndex,OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
+ break;
+
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_LONG:
+ _rxUpdatedObject->updateInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue));
+ break;
+
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxUpdatedObject->updateLong( _nColumnIndex, nValue );
+ }
+ break;
+
+ case TypeClass_FLOAT:
+ _rxUpdatedObject->updateFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
+ break;
+
+ case TypeClass_DOUBLE:
+ _rxUpdatedObject->updateDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
+ break;
+
+ case TypeClass_SEQUENCE:
+ if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
+ _rxUpdatedObject->updateBytes(_nColumnIndex, *s);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+ case TypeClass_STRUCT:
+ if (auto s1 = o3tl::tryAccess<DateTime>(_rValue))
+ _rxUpdatedObject->updateTimestamp(_nColumnIndex, *s1);
+ else if (auto s2 = o3tl::tryAccess<Date>(_rValue))
+ _rxUpdatedObject->updateDate(_nColumnIndex, *s2);
+ else if (auto s3 = o3tl::tryAccess<Time>(_rValue))
+ _rxUpdatedObject->updateTime(_nColumnIndex, *s3);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+
+ case TypeClass_INTERFACE:
+ if (auto xStream = o3tl::tryAccess<Reference<XInputStream>>(_rValue))
+ {
+ _rxUpdatedObject->updateBinaryStream(_nColumnIndex, *xStream, (*xStream)->available());
+ break;
+ }
+ [[fallthrough]];
+ default:
+ bSuccessfullyReRouted = false;
+ }
+
+ return bSuccessfullyReRouted;
+}
+
+bool implSetObject( const Reference< XParameters >& _rxParameters,
+ const sal_Int32 _nColumnIndex, const Any& _rValue)
+{
+ bool bSuccessfullyReRouted = true;
+ switch (_rValue.getValueTypeClass())
+ {
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ sal_uInt64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setString(_nColumnIndex, OUString::number(nValue));
+ }
+ break;
+
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ {
+ sal_Int64 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setLong( _nColumnIndex, nValue );
+ }
+ break;
+
+ case TypeClass_ANY:
+ {
+ bSuccessfullyReRouted = implSetObject(_rxParameters, _nColumnIndex, _rValue);
+ }
+ break;
+
+ case TypeClass_VOID:
+ _rxParameters->setNull(_nColumnIndex,DataType::VARCHAR);
+ break;
+
+ case TypeClass_STRING:
+ _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
+ break;
+
+ case TypeClass_BOOLEAN:
+ _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
+ break;
+
+ case TypeClass_BYTE:
+ _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
+ break;
+
+ case TypeClass_SHORT:
+ _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
+ break;
+
+ case TypeClass_CHAR:
+ _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
+ break;
+
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_LONG:
+ {
+ sal_Int32 nValue = 0;
+ OSL_VERIFY( _rValue >>= nValue );
+ _rxParameters->setInt(_nColumnIndex, nValue);
+ break;
+ }
+
+ case TypeClass_FLOAT:
+ _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
+ break;
+
+ case TypeClass_DOUBLE:
+ _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
+ break;
+
+ case TypeClass_SEQUENCE:
+ if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
+ {
+ _rxParameters->setBytes(_nColumnIndex, *s);
+ }
+ else
+ bSuccessfullyReRouted = false;
+ break;
+ case TypeClass_STRUCT:
+ if (auto s1 = o3tl::tryAccess<DateTime>(_rValue))
+ _rxParameters->setTimestamp(_nColumnIndex, *s1);
+ else if (auto s2 = o3tl::tryAccess<Date>(_rValue))
+ _rxParameters->setDate(_nColumnIndex, *s2);
+ else if (auto s3 = o3tl::tryAccess<Time>(_rValue))
+ _rxParameters->setTime(_nColumnIndex, *s3);
+ else
+ bSuccessfullyReRouted = false;
+ break;
+
+ case TypeClass_INTERFACE:
+ if (_rValue.getValueType() == cppu::UnoType<XInputStream>::get())
+ {
+ Reference< XInputStream > xStream;
+ _rValue >>= xStream;
+ _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
+ break;
+ }
+ [[fallthrough]];
+ default:
+ bSuccessfullyReRouted = false;
+
+ }
+
+ return bSuccessfullyReRouted;
+}
+
+namespace
+{
+ class OParameterWrapper : public ::cppu::WeakImplHelper< XIndexAccess >
+ {
+ std::vector<bool, std::allocator<bool> > m_aSet;
+ Reference<XIndexAccess> m_xSource;
+ public:
+ OParameterWrapper(std::vector<bool, std::allocator<bool> >&& _aSet,const Reference<XIndexAccess>& _xSource)
+ : m_aSet(std::move(_aSet)), m_xSource(_xSource) {}
+ private:
+ // css::container::XElementAccess
+ virtual Type SAL_CALL getElementType() override
+ {
+ return m_xSource->getElementType();
+ }
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->hasElements();
+ return std::count(m_aSet.begin(),m_aSet.end(),false) != 0;
+ }
+ // css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->getCount();
+ return std::count(m_aSet.begin(),m_aSet.end(),false);
+ }
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override
+ {
+ if ( m_aSet.empty() )
+ return m_xSource->getByIndex(Index);
+ if ( Index < 0 || m_aSet.size() < o3tl::make_unsigned(Index) )
+ throw IndexOutOfBoundsException();
+
+ std::vector<bool, std::allocator<bool> >::const_iterator aIter = m_aSet.begin();
+ std::vector<bool, std::allocator<bool> >::const_iterator aEnd = m_aSet.end();
+ sal_Int32 i = 0;
+ for(; aIter != aEnd && i <= Index; ++aIter)
+ {
+ if ( !*aIter )
+ {
+ ++i;
+ }
+ }
+ auto nParamPos = static_cast<sal_Int32>(std::distance(m_aSet.cbegin(), aIter)) - 1;
+ return m_xSource->getByIndex(nParamPos);
+ }
+ };
+}
+
+void askForParameters(const Reference< XSingleSelectQueryComposer >& _xComposer,
+ const Reference<XParameters>& _xParameters,
+ const Reference< XConnection>& _xConnection,
+ const Reference< XInteractionHandler >& _rxHandler,
+ const std::vector<bool, std::allocator<bool> >& _aParametersSet)
+{
+ OSL_ENSURE(_xComposer.is(),"dbtools::askForParameters XSQLQueryComposer is null!");
+ OSL_ENSURE(_xParameters.is(),"dbtools::askForParameters XParameters is null!");
+ OSL_ENSURE(_xConnection.is(),"dbtools::askForParameters XConnection is null!");
+ OSL_ENSURE(_rxHandler.is(),"dbtools::askForParameters XInteractionHandler is null!");
+
+ // we have to set this here again because getCurrentSettingsComposer can force a setpropertyvalue
+ Reference<XParametersSupplier> xParameters(_xComposer, UNO_QUERY);
+
+ Reference<XIndexAccess> xParamsAsIndicies = xParameters.is() ? xParameters->getParameters() : Reference<XIndexAccess>();
+ sal_Int32 nParamCount = xParamsAsIndicies.is() ? xParamsAsIndicies->getCount() : 0;
+ std::vector<bool, std::allocator<bool> > aNewParameterSet( _aParametersSet );
+ if ( !(nParamCount && std::count(aNewParameterSet.begin(),aNewParameterSet.end(),true) != nParamCount) )
+ return;
+
+ static const OUString PROPERTY_NAME(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME));
+ aNewParameterSet.resize(nParamCount ,false);
+ typedef std::map< OUString, std::vector<sal_Int32> > TParameterPositions;
+ TParameterPositions aParameterNames;
+ for(sal_Int32 i = 0; i < nParamCount; ++i)
+ {
+ Reference<XPropertySet> xParam(xParamsAsIndicies->getByIndex(i),UNO_QUERY);
+ OUString sName;
+ xParam->getPropertyValue(PROPERTY_NAME) >>= sName;
+
+ TParameterPositions::const_iterator aFind = aParameterNames.find(sName);
+ if ( aFind != aParameterNames.end() )
+ aNewParameterSet[i] = true;
+ aParameterNames[sName].push_back(i+1);
+ }
+ // build an interaction request
+ // two continuations (Ok and Cancel)
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ rtl::Reference<OParameterContinuation> pParams = new OParameterContinuation;
+ // the request
+ ParametersRequest aRequest;
+ Reference<XIndexAccess> xWrappedParameters = new OParameterWrapper(std::move(aNewParameterSet),xParamsAsIndicies);
+ aRequest.Parameters = xWrappedParameters;
+ aRequest.Connection = _xConnection;
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ pRequest->addContinuation(pAbort);
+ pRequest->addContinuation(pParams);
+
+ // execute the request
+ _rxHandler->handle(pRequest);
+
+ if (!pParams->wasSelected())
+ {
+ // canceled by the user (i.e. (s)he canceled the dialog)
+ RowSetVetoException e;
+ e.ErrorCode = ParameterInteractionCancelled;
+ throw e;
+ }
+
+ // now transfer the values from the continuation object to the parameter columns
+ Sequence< PropertyValue > aFinalValues = pParams->getValues();
+ const PropertyValue* pFinalValues = aFinalValues.getConstArray();
+ for (sal_Int32 i=0; i<aFinalValues.getLength(); ++i, ++pFinalValues)
+ {
+ Reference< XPropertySet > xParamColumn(xWrappedParameters->getByIndex(i),UNO_QUERY);
+ if (xParamColumn.is())
+ {
+ OUString sName;
+ xParamColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ OSL_ENSURE(sName == pFinalValues->Name, "::dbaui::askForParameters: inconsistent parameter names!");
+
+ // determine the field type and ...
+ sal_Int32 nParamType = 0;
+ xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nParamType;
+ // ... the scale of the parameter column
+ sal_Int32 nScale = 0;
+ if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE), xParamColumn))
+ xParamColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+ // (the index of the parameters is one-based)
+ TParameterPositions::const_iterator aFind = aParameterNames.find(pFinalValues->Name);
+ for(const auto& rItem : aFind->second)
+ {
+ if ( _aParametersSet.empty() || !_aParametersSet[rItem-1] )
+ {
+ _xParameters->setObjectWithInfo(rItem, pFinalValues->Value, nParamType, nScale);
+ }
+ }
+ }
+ }
+}
+
+void setObjectWithInfo(const Reference<XParameters>& _xParams,
+ sal_Int32 parameterIndex,
+ const Any& x,
+ sal_Int32 sqlType,
+ sal_Int32 scale)
+{
+ ORowSetValue aVal;
+ aVal.fill(x);
+ setObjectWithInfo(_xParams,parameterIndex,aVal,sqlType,scale);
+}
+
+void setObjectWithInfo(const Reference<XParameters>& _xParams,
+ sal_Int32 parameterIndex,
+ const ::connectivity::ORowSetValue& _rValue,
+ sal_Int32 sqlType,
+ sal_Int32 scale)
+{
+ if ( _rValue.isNull() )
+ _xParams->setNull(parameterIndex,sqlType);
+ else
+ {
+ switch(sqlType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ _xParams->setObjectWithInfo(parameterIndex,_rValue.makeAny(),sqlType,scale);
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ _xParams->setString(parameterIndex,_rValue.getString());
+ break;
+ case DataType::CLOB:
+ {
+ Any x(_rValue.makeAny());
+ OUString sValue;
+ if ( x >>= sValue )
+ _xParams->setString(parameterIndex,sValue);
+ else
+ {
+ Reference< XClob > xClob;
+ if(x >>= xClob)
+ _xParams->setClob(parameterIndex,xClob);
+ else
+ {
+ Reference< css::io::XInputStream > xStream;
+ if(x >>= xStream)
+ _xParams->setCharacterStream(parameterIndex,xStream,xStream->available());
+ }
+ }
+ }
+ break;
+ case DataType::BIGINT:
+ if ( _rValue.isSigned() )
+ _xParams->setLong(parameterIndex,_rValue.getLong());
+ else
+ _xParams->setString(parameterIndex,_rValue.getString());
+ break;
+
+ case DataType::FLOAT:
+ _xParams->setFloat(parameterIndex,_rValue.getFloat());
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ _xParams->setDouble(parameterIndex,_rValue.getDouble());
+ break;
+ case DataType::DATE:
+ _xParams->setDate(parameterIndex,_rValue.getDate());
+ break;
+ case DataType::TIME:
+ _xParams->setTime(parameterIndex,_rValue.getTime());
+ break;
+ case DataType::TIMESTAMP:
+ _xParams->setTimestamp(parameterIndex,_rValue.getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ case DataType::BLOB:
+ {
+ Any x(_rValue.makeAny());
+ Sequence< sal_Int8> aBytes;
+ if(x >>= aBytes)
+ _xParams->setBytes(parameterIndex,aBytes);
+ else
+ {
+ Reference< XBlob > xBlob;
+ if(x >>= xBlob)
+ _xParams->setBlob(parameterIndex,xBlob);
+ else
+ {
+ Reference< XClob > xClob;
+ if(x >>= xClob)
+ _xParams->setClob(parameterIndex,xClob);
+ else
+ {
+ Reference< css::io::XInputStream > xBinStream;
+ if(x >>= xBinStream)
+ _xParams->setBinaryStream(parameterIndex,xBinStream,xBinStream->available());
+ }
+ }
+ }
+ }
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ _xParams->setBoolean(parameterIndex,_rValue.getBool());
+ break;
+ case DataType::TINYINT:
+ if ( _rValue.isSigned() )
+ _xParams->setByte(parameterIndex,_rValue.getInt8());
+ else
+ _xParams->setShort(parameterIndex,_rValue.getInt16());
+ break;
+ case DataType::SMALLINT:
+ if ( _rValue.isSigned() )
+ _xParams->setShort(parameterIndex,_rValue.getInt16());
+ else
+ _xParams->setInt(parameterIndex,_rValue.getInt32());
+ break;
+ case DataType::INTEGER:
+ if ( _rValue.isSigned() )
+ _xParams->setInt(parameterIndex,_rValue.getULong());
+ else
+ _xParams->setLong(parameterIndex,_rValue.getLong());
+ break;
+ default:
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,nullptr);
+ }
+ }
+ }
+}
+
+void getBooleanComparisonPredicate( std::u16string_view _rExpression, const bool _bValue, const sal_Int32 _nBooleanComparisonMode,
+ OUStringBuffer& _out_rSQLPredicate )
+{
+ switch ( _nBooleanComparisonMode )
+ {
+ case BooleanComparisonMode::IS_LITERAL:
+ _out_rSQLPredicate.append( _rExpression );
+ if ( _bValue )
+ _out_rSQLPredicate.append( " IS TRUE" );
+ else
+ _out_rSQLPredicate.append( " IS FALSE" );
+ break;
+
+ case BooleanComparisonMode::EQUAL_LITERAL:
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.appendAscii( _bValue ? " = TRUE" : " = FALSE" );
+ break;
+
+ case BooleanComparisonMode::ACCESS_COMPAT:
+ if ( _bValue )
+ {
+ _out_rSQLPredicate.append( " NOT ( ( " );
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " = 0 ) OR ( " );
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " IS NULL ) )" );
+ }
+ else
+ {
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.append( " = 0" );
+ }
+ break;
+
+ case BooleanComparisonMode::EQUAL_INTEGER:
+ // fall through
+ default:
+ _out_rSQLPredicate.append( _rExpression );
+ _out_rSQLPredicate.appendAscii( _bValue ? " = 1" : " = 0" );
+ break;
+ }
+}
+
+} // namespace dbtools
+
+namespace connectivity
+{
+void checkDisposed(bool _bThrow)
+{
+ if (_bThrow)
+ throw DisposedException();
+
+}
+
+OSQLColumns::const_iterator find(const OSQLColumns::const_iterator& first,
+ const OSQLColumns::const_iterator& last,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ return find(first,last,sName,_rVal,_rCase);
+}
+
+OSQLColumns::const_iterator findRealName(const OSQLColumns::const_iterator& first,
+ const OSQLColumns::const_iterator& last,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME);
+ return find(first,last,sRealName,_rVal,_rCase);
+}
+
+OSQLColumns::const_iterator find(OSQLColumns::const_iterator first,
+ const OSQLColumns::const_iterator& last,
+ const OUString& _rProp,
+ std::u16string_view _rVal,
+ const ::comphelper::UStringMixEqual& _rCase)
+{
+ while (first != last && !_rCase(getString((*first)->getPropertyValue(_rProp)),_rVal))
+ ++first;
+ return first;
+}
+
+namespace dbase
+{
+ bool dbfDecodeCharset(rtl_TextEncoding &_out_encoding, sal_uInt8 nType, sal_uInt8 nCodepage)
+ {
+ switch (nType)
+ {
+ // dBaseIII header doesn't contain language driver ID
+ // See http://dbase.free.fr/tlcharge/structure%20tables.pdf
+ case dBaseIII:
+ case dBaseIIIMemo:
+ break;
+ case dBaseIV:
+ case dBaseV:
+ case VisualFoxPro:
+ case VisualFoxProAuto:
+ case dBaseFS:
+ case dBaseFSMemo:
+ case dBaseIVMemoSQL:
+ case FoxProMemo:
+ {
+ if (nCodepage != 0x00)
+ {
+ auto eEncoding(RTL_TEXTENCODING_DONTKNOW);
+ switch(nCodepage)
+ {
+ case 0x01: eEncoding = RTL_TEXTENCODING_IBM_437; break; // DOS USA code page 437
+ case 0x02: eEncoding = RTL_TEXTENCODING_IBM_850; break; // DOS Multilingual code page 850
+ case 0x03: eEncoding = RTL_TEXTENCODING_MS_1252; break; // Windows ANSI code page 1252
+ case 0x04: eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; break; // Standard Macintosh
+ case 0x64: eEncoding = RTL_TEXTENCODING_IBM_852; break; // EE MS-DOS code page 852
+ case 0x65: eEncoding = RTL_TEXTENCODING_IBM_866; break; // Russian MS-DOS code page 866
+ case 0x66: eEncoding = RTL_TEXTENCODING_IBM_865; break; // Nordic MS-DOS code page 865
+ case 0x67: eEncoding = RTL_TEXTENCODING_IBM_861; break; // Icelandic MS-DOS
+ //case 0x68: eEncoding = ; break; // Kamenicky (Czech) MS-DOS
+ //case 0x69: eEncoding = ; break; // Mazovia (Polish) MS-DOS
+ case 0x6A: eEncoding = RTL_TEXTENCODING_IBM_737; break; // Greek MS-DOS (437G)
+ case 0x6B: eEncoding = RTL_TEXTENCODING_IBM_857; break; // Turkish MS-DOS
+ case 0x6C: eEncoding = RTL_TEXTENCODING_IBM_863; break; // MS-DOS, Canada
+ case 0x78: eEncoding = RTL_TEXTENCODING_MS_950; break; // Windows, Traditional Chinese
+ case 0x79: eEncoding = RTL_TEXTENCODING_MS_949; break; // Windows, Korean (Hangul)
+ case 0x7A: eEncoding = RTL_TEXTENCODING_MS_936; break; // Windows, Simplified Chinese
+ case 0x7B: eEncoding = RTL_TEXTENCODING_MS_932; break; // Windows, Japanese (Shift-jis)
+ case 0x7C: eEncoding = RTL_TEXTENCODING_MS_874; break; // Windows, Thai
+ case 0x7D: eEncoding = RTL_TEXTENCODING_MS_1255; break; // Windows, Hebrew
+ case 0x7E: eEncoding = RTL_TEXTENCODING_MS_1256; break; // Windows, Arabic
+ case 0x96: eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC; break; // Russian Macintosh
+ case 0x97: eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO; break; // Eastern European Macintosh
+ case 0x98: eEncoding = RTL_TEXTENCODING_APPLE_GREEK; break; // Greek Macintosh
+ case 0xC8: eEncoding = RTL_TEXTENCODING_MS_1250; break; // Windows EE code page 1250
+ case 0xC9: eEncoding = RTL_TEXTENCODING_MS_1251; break; // Russian Windows
+ case 0xCA: eEncoding = RTL_TEXTENCODING_MS_1254; break; // Turkish Windows
+ case 0xCB: eEncoding = RTL_TEXTENCODING_MS_1253; break; // Greek Windows
+ case 0xCC: eEncoding = RTL_TEXTENCODING_MS_1257; break; // Windows, Baltic
+ }
+ if(eEncoding != RTL_TEXTENCODING_DONTKNOW)
+ {
+ _out_encoding = eEncoding;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ bool dbfReadCharset(rtl_TextEncoding &nCharSet, SvStream* dbf_Stream)
+ {
+ sal_uInt8 nType=0;
+ dbf_Stream->ReadUChar( nType );
+
+ dbf_Stream->Seek(STREAM_SEEK_TO_BEGIN + 29);
+ if (dbf_Stream->eof())
+ {
+ return false;
+ }
+ else
+ {
+ sal_uInt8 nEncoding=0;
+ dbf_Stream->ReadUChar( nEncoding );
+ return dbfDecodeCharset(nCharSet, nType, nEncoding);
+ }
+ }
+
+}
+
+} //namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/dbtools2.cxx b/connectivity/source/commontools/dbtools2.cxx
new file mode 100644
index 000000000..b6a4a4875
--- /dev/null
+++ b/connectivity/source/commontools/dbtools2.cxx
@@ -0,0 +1,1018 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <SQLStatementHelper.hxx>
+#include <unotools/confignode.hxx>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <com/sun/star/sdbcx/KeyType.hpp>
+#include <TConnection.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <comphelper/types.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/sharedunocomponent.hxx>
+#include <algorithm>
+#include <string_view>
+
+namespace dbtools
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::frame;
+ using namespace connectivity;
+ using namespace comphelper;
+
+OUString createStandardTypePart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,std::u16string_view _sCreatePattern)
+{
+
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ OUString sTypeName;
+ sal_Int32 nDataType = 0;
+ sal_Int32 nPrecision = 0;
+ sal_Int32 nScale = 0;
+
+ nDataType = nPrecision = nScale = 0;
+
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sTypeName;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nDataType;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nPrecision;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+
+ OUStringBuffer aSql;
+
+ // check if the user enter a specific string to create autoincrement values
+ OUString sAutoIncrementValue;
+ Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
+ // look if we have to use precisions
+ bool bUseLiteral = false;
+ OUString sPrefix,sPostfix,sCreateParams;
+ {
+ Reference<XResultSet> xRes = xMetaData->getTypeInfo();
+ if(xRes.is())
+ {
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ while(xRes->next())
+ {
+ OUString sTypeName2Cmp = xRow->getString(1);
+ sal_Int32 nType = xRow->getShort(2);
+ sPrefix = xRow->getString (4);
+ sPostfix = xRow->getString (5);
+ sCreateParams = xRow->getString(6);
+ // first identical type will be used if typename is empty
+ if ( sTypeName.isEmpty() && nType == nDataType )
+ sTypeName = sTypeName2Cmp;
+
+ if( sTypeName.equalsIgnoreAsciiCase(sTypeName2Cmp) && nType == nDataType && !sCreateParams.isEmpty() && !xRow->wasNull())
+ {
+ bUseLiteral = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !sAutoIncrementValue.isEmpty() )
+ {
+ sal_Int32 nIndex = sTypeName.indexOf(sAutoIncrementValue);
+ if (nIndex != -1)
+ sTypeName = sTypeName.replaceAt(nIndex,sTypeName.getLength() - nIndex, u"");
+ }
+
+ if ( (nPrecision > 0 || nScale > 0) && bUseLiteral )
+ {
+ sal_Int32 nParenPos = sTypeName.indexOf('(');
+ if ( nParenPos == -1 )
+ {
+ aSql.append(sTypeName);
+ aSql.append("(");
+ }
+ else
+ {
+ aSql.append(sTypeName.subView(0, ++nParenPos));
+ }
+
+ if ( nPrecision > 0 && nDataType != DataType::TIMESTAMP )
+ {
+ aSql.append(nPrecision);
+ if ( (nScale > 0) || (!_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1) )
+ aSql.append(",");
+ }
+ if ( (nScale > 0) || ( !_sCreatePattern.empty() && sCreateParams.indexOf(_sCreatePattern) != -1 ) || nDataType == DataType::TIMESTAMP )
+ aSql.append(nScale);
+
+ if ( nParenPos == -1 )
+ aSql.append(")");
+ else
+ {
+ nParenPos = sTypeName.indexOf(')',nParenPos);
+ aSql.append(sTypeName.subView(nParenPos));
+ }
+ }
+ else
+ aSql.append(sTypeName); // simply add the type name
+
+ OUString aDefault = ::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)));
+ if ( !aDefault.isEmpty() )
+ {
+ aSql.append(" DEFAULT ");
+ aSql.append(sPrefix);
+ aSql.append(aDefault);
+ aSql.append(sPostfix);
+ } // if ( aDefault.getLength() )
+
+ return aSql.makeStringAndClear();
+}
+
+OUString createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,std::u16string_view _sCreatePattern)
+{
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ bool bIsAutoIncrement = false;
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bIsAutoIncrement;
+
+ const OUString sQuoteString = xMetaData->getIdentifierQuoteString();
+ OUStringBuffer aSql(::dbtools::quoteName(sQuoteString,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))));
+
+ // check if the user enter a specific string to create autoincrement values
+ OUString sAutoIncrementValue;
+ Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
+ xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
+
+ aSql.append(" ");
+
+ aSql.append(createStandardTypePart(xColProp, _xConnection, _sCreatePattern));
+
+ if(::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISNULLABLE))) == ColumnValue::NO_NULLS)
+ aSql.append(" NOT NULL");
+
+ if ( bIsAutoIncrement && !sAutoIncrementValue.isEmpty())
+ {
+ aSql.append(" ");
+ aSql.append(sAutoIncrementValue);
+ }
+
+ if ( _pHelper )
+ _pHelper->addComment(xColProp,aSql);
+
+ return aSql.makeStringAndClear();
+}
+
+
+OUString createStandardCreateStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,std::u16string_view _sCreatePattern)
+{
+ OUStringBuffer aSql("CREATE TABLE ");
+ OUString sCatalog,sSchema,sTable,sComposedName;
+
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= sCatalog;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= sSchema;
+ descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= sTable;
+
+ sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+ if ( sComposedName.isEmpty() )
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(sComposedName);
+ aSql.append(" (");
+
+ // columns
+ Reference<XColumnsSupplier> xColumnSup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+ // check if there are columns
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ Reference< XPropertySet > xColProp;
+
+ sal_Int32 nCount = xColumns->getCount();
+ for(sal_Int32 i=0;i<nCount;++i)
+ {
+ if ( (xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
+ {
+ aSql.append(createStandardColumnPart(xColProp,_xConnection,_pHelper,_sCreatePattern));
+ aSql.append(",");
+ }
+ }
+ return aSql.makeStringAndClear();
+}
+namespace
+{
+ OUString generateColumnNames(const Reference<XIndexAccess>& _xColumns,const Reference<XDatabaseMetaData>& _xMetaData)
+ {
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ const OUString sQuote(_xMetaData->getIdentifierQuoteString());
+ OUStringBuffer sSql( " (" );
+ Reference< XPropertySet > xColProp;
+
+ sal_Int32 nColCount = _xColumns->getCount();
+ for(sal_Int32 i=0;i<nColCount;++i)
+ {
+ if ( (_xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
+ sSql.append( ::dbtools::quoteName(sQuote,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)))) +
+ ",");
+ }
+
+ if ( nColCount )
+ sSql[sSql.getLength()-1] = ')';
+ return sSql.makeStringAndClear();
+ }
+}
+
+OUString createStandardKeyStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection)
+{
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+ OUStringBuffer aSql;
+ // keys
+ Reference<XKeysSupplier> xKeySup(descriptor,UNO_QUERY);
+ Reference<XIndexAccess> xKeys = xKeySup->getKeys();
+ if ( xKeys.is() )
+ {
+ Reference< XPropertySet > xColProp;
+ Reference<XIndexAccess> xColumns;
+ Reference<XColumnsSupplier> xColumnSup;
+ OUString sCatalog,sSchema,sTable,sComposedName;
+ bool bPKey = false;
+ for(sal_Int32 i=0;i<xKeys->getCount();++i)
+ {
+ if ( (xKeys->getByIndex(i) >>= xColProp) && xColProp.is() )
+ {
+
+ sal_Int32 nKeyType = ::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)));
+
+ if ( nKeyType == KeyType::PRIMARY )
+ {
+ if(bPKey)
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ bPKey = true;
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" PRIMARY KEY ");
+ aSql.append(generateColumnNames(xColumns,xMetaData));
+ }
+ else if(nKeyType == KeyType::UNIQUE)
+ {
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" UNIQUE ");
+ aSql.append(generateColumnNames(xColumns,xMetaData));
+ }
+ else if(nKeyType == KeyType::FOREIGN)
+ {
+ sal_Int32 nDeleteRule = getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)));
+
+ xColumnSup.set(xColProp,UNO_QUERY);
+ xColumns.set(xColumnSup->getColumns(),UNO_QUERY);
+ if(!xColumns.is() || !xColumns->getCount())
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(" FOREIGN KEY ");
+ OUString sRefTable = getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)));
+ ::dbtools::qualifiedNameComponents(xMetaData,
+ sRefTable,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ sComposedName = ::dbtools::composeTableName( xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+
+
+ if ( sComposedName.isEmpty() )
+ ::dbtools::throwFunctionSequenceException(_xConnection);
+
+ aSql.append(generateColumnNames(xColumns,xMetaData));
+
+ switch(nDeleteRule)
+ {
+ case KeyRule::CASCADE:
+ aSql.append(" ON DELETE CASCADE ");
+ break;
+ case KeyRule::RESTRICT:
+ aSql.append(" ON DELETE RESTRICT ");
+ break;
+ case KeyRule::SET_NULL:
+ aSql.append(" ON DELETE SET NULL ");
+ break;
+ case KeyRule::SET_DEFAULT:
+ aSql.append(" ON DELETE SET DEFAULT ");
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ }
+ }
+
+ if ( !aSql.isEmpty() )
+ {
+ if ( aSql[aSql.getLength() - 1] == ',' )
+ aSql[aSql.getLength() - 1] = ')';
+ else
+ aSql.append(")");
+ }
+
+ return aSql.makeStringAndClear();
+
+}
+
+OUString createSqlCreateTableStatement( const Reference< XPropertySet >& descriptor,
+ const Reference< XConnection>& _xConnection)
+{
+ OUString aSql = ::dbtools::createStandardCreateStatement(descriptor,_xConnection,nullptr,{});
+ const OUString sKeyStmt = ::dbtools::createStandardKeyStatement(descriptor,_xConnection);
+ if ( !sKeyStmt.isEmpty() )
+ aSql += sKeyStmt;
+ else
+ {
+ if ( aSql.endsWith(",") )
+ aSql = aSql.replaceAt(aSql.getLength()-1, 1, u")");
+ else
+ aSql += ")";
+ }
+ return aSql;
+}
+namespace
+{
+ Reference<XPropertySet> lcl_createSDBCXColumn(const Reference<XNameAccess>& _xPrimaryKeyColumns,
+ const Reference<XConnection>& _xConnection,
+ const Any& _aCatalog,
+ const OUString& _aSchema,
+ const OUString& _aTable,
+ const OUString& _rQueryName,
+ const OUString& _rName,
+ bool _bCase,
+ bool _bQueryForInfo,
+ bool _bIsAutoIncrement,
+ bool _bIsCurrency,
+ sal_Int32 _nDataType)
+ {
+ Reference<XPropertySet> xProp;
+ Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+ Reference< XResultSet > xResult = xMetaData->getColumns(_aCatalog, _aSchema, _aTable, _rQueryName);
+ OUString sCatalog;
+ _aCatalog >>= sCatalog;
+
+ if ( xResult.is() )
+ {
+ UStringMixEqual aMixCompare(_bCase);
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while( xResult->next() )
+ {
+ if ( aMixCompare(xRow->getString(4),_rName) )
+ {
+ sal_Int32 nField5 = xRow->getInt(5);
+ OUString aField6 = xRow->getString(6);
+ sal_Int32 nField7 = xRow->getInt(7)
+ , nField9 = xRow->getInt(9)
+ , nField11= xRow->getInt(11);
+ OUString sField12 = xRow->getString(12),
+ sField13 = xRow->getString(13);
+ ::comphelper::disposeComponent(xRow);
+
+ bool bAutoIncrement = _bIsAutoIncrement
+ ,bIsCurrency = _bIsCurrency;
+ if ( _bQueryForInfo )
+ {
+ const OUString sQuote = xMetaData->getIdentifierQuoteString();
+ OUString sQuotedName = ::dbtools::quoteName(sQuote,_rName);
+ OUString sComposedName = composeTableNameForSelect(_xConnection, getString( _aCatalog ), _aSchema, _aTable );
+
+ ColumnInformationMap aInfo(_bCase);
+ collectColumnInformation(_xConnection,sComposedName,sQuotedName,aInfo);
+ ColumnInformationMap::const_iterator aIter = aInfo.begin();
+ if ( aIter != aInfo.end() )
+ {
+ bAutoIncrement = aIter->second.first.first;
+ bIsCurrency = aIter->second.first.second;
+ if ( DataType::OTHER == nField5 )
+ nField5 = aIter->second.second;
+ }
+ }
+ else if ( DataType::OTHER == nField5 )
+ nField5 = _nDataType;
+
+ if ( nField11 != ColumnValue::NO_NULLS )
+ {
+ try
+ {
+ if ( _xPrimaryKeyColumns.is() )
+ {
+ if ( _xPrimaryKeyColumns->hasByName(_rName) )
+ nField11 = ColumnValue::NO_NULLS;
+
+ }
+ else
+ {
+ Reference< XResultSet > xPKeys = xMetaData->getPrimaryKeys( _aCatalog, _aSchema, _aTable );
+ Reference< XRow > xPKeyRow( xPKeys, UNO_QUERY_THROW );
+ while( xPKeys->next() ) // there can be only one primary key
+ {
+ OUString sKeyColumn = xPKeyRow->getString(4);
+ if ( aMixCompare(_rName,sKeyColumn) )
+ {
+ nField11 = ColumnValue::NO_NULLS;
+ break;
+ }
+ }
+ }
+ }
+ catch(SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "lcl_createSDBCXColumn" );
+ }
+ }
+
+ xProp = new connectivity::sdbcx::OColumn(_rName,
+ aField6,
+ sField13,
+ sField12,
+ nField11,
+ nField7,
+ nField9,
+ nField5,
+ bAutoIncrement,
+ false,
+ bIsCurrency,
+ _bCase,
+ sCatalog,
+ _aSchema,
+ _aTable);
+
+ break;
+ }
+ }
+ }
+
+ return xProp;
+ }
+
+ Reference< XModel> lcl_getXModel(const Reference< XInterface>& _xIface)
+ {
+ Reference< XInterface > xParent = _xIface;
+ Reference< XModel > xModel(xParent,UNO_QUERY);
+ while( xParent.is() && !xModel.is() )
+ {
+ Reference<XChild> xChild(xParent,UNO_QUERY);
+ xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY);
+ xModel.set(xParent,UNO_QUERY);
+ }
+ return xModel;
+ }
+}
+
+Reference<XPropertySet> createSDBCXColumn(const Reference<XPropertySet>& _xTable,
+ const Reference<XConnection>& _xConnection,
+ const OUString& _rName,
+ bool _bCase,
+ bool _bQueryForInfo,
+ bool _bIsAutoIncrement,
+ bool _bIsCurrency,
+ sal_Int32 _nDataType)
+{
+ Reference<XPropertySet> xProp;
+ OSL_ENSURE(_xTable.is(),"Table is NULL!");
+ if ( !_xTable.is() )
+ return xProp;
+
+ ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+ Any aCatalog = _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME));
+ OUString sCatalog;
+ aCatalog >>= sCatalog;
+
+ OUString aSchema, aTable;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema;
+ _xTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable;
+
+ Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(_xTable);
+
+ xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, _rName,_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
+ if ( !xProp.is() )
+ {
+ xProp = lcl_createSDBCXColumn(xPrimaryKeyColumns,_xConnection,aCatalog, aSchema, aTable, "%",_rName,_bCase,_bQueryForInfo,_bIsAutoIncrement,_bIsCurrency,_nDataType);
+ if ( !xProp.is() )
+ xProp = new connectivity::sdbcx::OColumn(_rName,
+ OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ DataType::VARCHAR,
+ _bIsAutoIncrement,
+ false,
+ _bIsCurrency,
+ _bCase,
+ sCatalog,
+ aSchema,
+ aTable);
+
+ }
+
+ return xProp;
+}
+
+
+bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const char* _pAsciiSettingName )
+{
+ return getBooleanDataSourceSetting(_rxConnection, OUString::createFromAscii( _pAsciiSettingName ));
+}
+
+bool getBooleanDataSourceSetting( const Reference< XConnection >& _rxConnection, const OUString & rSettingName )
+{
+ bool bValue( false );
+ try
+ {
+ Reference< XPropertySet> xDataSourceProperties( findDataSource( _rxConnection ), UNO_QUERY );
+ OSL_ENSURE( xDataSourceProperties.is(), "::dbtools::getBooleanDataSourceSetting: somebody is using this with a non-SDB-level connection!" );
+ if ( xDataSourceProperties.is() )
+ {
+ Reference< XPropertySet > xSettings(
+ xDataSourceProperties->getPropertyValue("Settings"),
+ UNO_QUERY_THROW
+ );
+ OSL_VERIFY( xSettings->getPropertyValue( rSettingName ) >>= bValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bValue;
+}
+
+bool getDataSourceSetting( const Reference< XInterface >& _xChild, const OUString& _sAsciiSettingsName,
+ Any& /* [out] */ _rSettingsValue )
+{
+ bool bIsPresent = false;
+ try
+ {
+ const Reference< XPropertySet> xDataSourceProperties( findDataSource( _xChild ), UNO_QUERY );
+ if ( !xDataSourceProperties.is() )
+ return false;
+
+ const Reference< XPropertySet > xSettings(
+ xDataSourceProperties->getPropertyValue("Settings"),
+ UNO_QUERY_THROW
+ );
+
+ _rSettingsValue = xSettings->getPropertyValue( _sAsciiSettingsName );
+ bIsPresent = true;
+ }
+ catch( const Exception& )
+ {
+ bIsPresent = false;
+ }
+ return bIsPresent;
+}
+
+bool getDataSourceSetting( const Reference< XInterface >& _rxDataSource, const char* _pAsciiSettingsName,
+ Any& /* [out] */ _rSettingsValue )
+{
+ OUString sAsciiSettingsName = OUString::createFromAscii(_pAsciiSettingsName);
+ return getDataSourceSetting( _rxDataSource, sAsciiSettingsName,_rSettingsValue );
+}
+
+bool isDataSourcePropertyEnabled(const Reference<XInterface>& _xProp, const OUString& _sProperty, bool _bDefault)
+{
+ bool bEnabled = _bDefault;
+ try
+ {
+ Reference< XPropertySet> xProp(findDataSource(_xProp),UNO_QUERY);
+ if ( xProp.is() )
+ {
+ Sequence< PropertyValue > aInfo;
+ xProp->getPropertyValue("Info") >>= aInfo;
+ const PropertyValue* pValue =std::find_if(std::cbegin(aInfo),
+ std::cend(aInfo),
+ [&_sProperty](const PropertyValue& lhs)
+ { return lhs.Name == _sProperty; });
+ if ( pValue != std::cend(aInfo) )
+ pValue->Value >>= bEnabled;
+ }
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return bEnabled;
+}
+
+Reference< XTablesSupplier> getDataDefinitionByURLAndConnection(
+ const OUString& _rsUrl,
+ const Reference< XConnection>& _xConnection,
+ const Reference< XComponentContext >& _rxContext)
+{
+ Reference< XTablesSupplier> xTablesSup;
+ try
+ {
+ Reference< XDriverManager2 > xManager = DriverManager::create( _rxContext );
+ Reference< XDataDefinitionSupplier > xSupp( xManager->getDriverByURL( _rsUrl ), UNO_QUERY );
+
+ if ( xSupp.is() )
+ {
+ xTablesSup = xSupp->getDataDefinitionByConnection( _xConnection );
+ OSL_ENSURE(xTablesSup.is(),"No table supplier!");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ return xTablesSup;
+}
+
+
+sal_Int32 getTablePrivileges(const Reference< XDatabaseMetaData>& _xMetaData,
+ const OUString& _sCatalog,
+ const OUString& _sSchema,
+ const OUString& _sTable)
+{
+ OSL_ENSURE(_xMetaData.is(),"Invalid metadata!");
+ sal_Int32 nPrivileges = 0;
+ try
+ {
+ Any aVal;
+ if(!_sCatalog.isEmpty())
+ aVal <<= _sCatalog;
+ Reference< XResultSet > xPrivileges = _xMetaData->getTablePrivileges(aVal, _sSchema, _sTable);
+ Reference< XRow > xCurrentRow(xPrivileges, UNO_QUERY);
+
+ const OUString sUserWorkingFor = _xMetaData->getUserName();
+ static const char sSELECT[] = "SELECT";
+ static const char sINSERT[] = "INSERT";
+ static const char sUPDATE[] = "UPDATE";
+ static const char sDELETE[] = "DELETE";
+ static const char sREAD[] = "READ";
+ static const char sCREATE[] = "CREATE";
+ static const char sALTER[] = "ALTER";
+ static const char sREFERENCE[] = "REFERENCE";
+ static const char sDROP[] = "DROP";
+
+ if ( xCurrentRow.is() )
+ {
+ // after creation the set is positioned before the first record, per definition
+ OUString sPrivilege, sGrantee;
+ while ( xPrivileges->next() )
+ {
+ sGrantee = xCurrentRow->getString(5);
+ sPrivilege = xCurrentRow->getString(6);
+
+ if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
+ nPrivileges |= Privilege::SELECT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
+ nPrivileges |= Privilege::INSERT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
+ nPrivileges |= Privilege::UPDATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
+ nPrivileges |= Privilege::DELETE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
+ nPrivileges |= Privilege::READ;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
+ nPrivileges |= Privilege::CREATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
+ nPrivileges |= Privilege::ALTER;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
+ nPrivileges |= Privilege::REFERENCE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
+ nPrivileges |= Privilege::DROP;
+ }
+ }
+ disposeComponent(xPrivileges);
+
+ // Some drivers put a table privilege as soon as any column has the privilege,
+ // some drivers only if all columns have the privilege.
+ // To unify the situation, collect column privileges here, too.
+ Reference< XResultSet > xColumnPrivileges = _xMetaData->getColumnPrivileges(aVal, _sSchema, _sTable, "%");
+ Reference< XRow > xColumnCurrentRow(xColumnPrivileges, UNO_QUERY);
+ if ( xColumnCurrentRow.is() )
+ {
+ // after creation the set is positioned before the first record, per definition
+ OUString sPrivilege, sGrantee;
+ while ( xColumnPrivileges->next() )
+ {
+ sGrantee = xColumnCurrentRow->getString(6);
+ sPrivilege = xColumnCurrentRow->getString(7);
+
+ if (!sUserWorkingFor.equalsIgnoreAsciiCase(sGrantee))
+ continue;
+
+ if (sPrivilege.equalsIgnoreAsciiCase(sSELECT))
+ nPrivileges |= Privilege::SELECT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sINSERT))
+ nPrivileges |= Privilege::INSERT;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sUPDATE))
+ nPrivileges |= Privilege::UPDATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDELETE))
+ nPrivileges |= Privilege::DELETE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREAD))
+ nPrivileges |= Privilege::READ;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sCREATE))
+ nPrivileges |= Privilege::CREATE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sALTER))
+ nPrivileges |= Privilege::ALTER;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sREFERENCE))
+ nPrivileges |= Privilege::REFERENCE;
+ else if (sPrivilege.equalsIgnoreAsciiCase(sDROP))
+ nPrivileges |= Privilege::DROP;
+ }
+ }
+ disposeComponent(xColumnPrivileges);
+ }
+ catch(const SQLException& e)
+ {
+ // some drivers don't support any privileges so we assume that we are allowed to do all we want :-)
+ if(e.SQLState == "IM001")
+ nPrivileges |= Privilege::DROP |
+ Privilege::REFERENCE |
+ Privilege::ALTER |
+ Privilege::CREATE |
+ Privilege::READ |
+ Privilege::DELETE |
+ Privilege::UPDATE |
+ Privilege::INSERT |
+ Privilege::SELECT;
+ else
+ OSL_FAIL("Could not collect the privileges !");
+ }
+ return nPrivileges;
+}
+
+// we need some more information about the column
+void collectColumnInformation(const Reference< XConnection>& _xConnection,
+ std::u16string_view _sComposedName,
+ std::u16string_view _rName,
+ ColumnInformationMap& _rInfo)
+{
+ OUString sSelect = OUString::Concat("SELECT ") + _rName +
+ " FROM " + _sComposedName +
+ " WHERE 0 = 1";
+
+ try
+ {
+ ::utl::SharedUNOComponent< XStatement > xStmt( _xConnection->createStatement() );
+ Reference< XPropertySet > xStatementProps( xStmt, UNO_QUERY_THROW );
+ xStatementProps->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ), Any( false ) );
+ Reference< XResultSet > xResult( xStmt->executeQuery( sSelect ), UNO_SET_THROW );
+ Reference< XResultSetMetaDataSupplier > xSuppMeta( xResult, UNO_QUERY_THROW );
+ Reference< XResultSetMetaData > xMeta( xSuppMeta->getMetaData(), UNO_SET_THROW );
+
+ sal_Int32 nCount = xMeta->getColumnCount();
+ OSL_ENSURE( nCount != 0, "::dbtools::collectColumnInformation: result set has empty (column-less) meta data!" );
+ for (sal_Int32 i=1; i <= nCount ; ++i)
+ {
+ _rInfo.emplace( xMeta->getColumnName(i),
+ ColumnInformation(TBoolPair(xMeta->isAutoIncrement(i),xMeta->isCurrency(i)),xMeta->getColumnType(i)));
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+}
+
+
+bool isEmbeddedInDatabase( const Reference< XInterface >& _rxComponent, Reference< XConnection >& _rxActualConnection )
+{
+ bool bIsEmbedded = false;
+ try
+ {
+ Reference< XModel > xModel = lcl_getXModel( _rxComponent );
+
+ if ( xModel.is() )
+ {
+ Sequence< PropertyValue > aArgs = xModel->getArgs();
+ const PropertyValue* pIter = aArgs.getConstArray();
+ const PropertyValue* pEnd = pIter + aArgs.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( pIter->Name == "ComponentData" )
+ {
+ Sequence<PropertyValue> aDocumentContext;
+ pIter->Value >>= aDocumentContext;
+ const PropertyValue* pContextIter = aDocumentContext.getConstArray();
+ const PropertyValue* pContextEnd = pContextIter + aDocumentContext.getLength();
+ for(;pContextIter != pContextEnd;++pContextIter)
+ {
+ if ( pContextIter->Name == "ActiveConnection"
+ && ( pContextIter->Value >>= _rxActualConnection )
+ )
+ {
+ bIsEmbedded = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ // not interested in
+ }
+ return bIsEmbedded;
+}
+
+namespace
+{
+ OUString lcl_getEncodingName( rtl_TextEncoding _eEncoding )
+ {
+ OUString sEncodingName;
+
+ OCharsetMap aCharsets;
+ OCharsetMap::CharsetIterator aEncodingPos = aCharsets.find( _eEncoding );
+ OSL_ENSURE( aEncodingPos != aCharsets.end(), "lcl_getEncodingName: *which* encoding?" );
+ if ( aEncodingPos != aCharsets.end() )
+ sEncodingName = (*aEncodingPos).getIanaName();
+
+ return sEncodingName;
+ }
+}
+
+
+sal_Int32 DBTypeConversion::convertUnicodeString( const OUString& _rSource, OString& _rDest, rtl_TextEncoding _eEncoding )
+{
+ if ( !rtl_convertUStringToString( &_rDest.pData, _rSource.getStr(), _rSource.getLength(),
+ _eEncoding,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
+ RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 )
+ )
+ {
+ SharedResources aResources;
+ OUString sMessage = aResources.getResourceStringWithSubstitution( STR_CANNOT_CONVERT_STRING,
+ "$string$", _rSource,
+ "$charset$", lcl_getEncodingName( _eEncoding )
+ );
+
+ throw SQLException(
+ sMessage,
+ nullptr,
+ "22018",
+ 22018,
+ Any()
+ );
+ }
+
+ return _rDest.getLength();
+}
+
+
+sal_Int32 DBTypeConversion::convertUnicodeStringToLength( const OUString& _rSource, OString& _rDest,
+ sal_Int32 _nMaxLen, rtl_TextEncoding _eEncoding )
+{
+ sal_Int32 nLen = convertUnicodeString( _rSource, _rDest, _eEncoding );
+ if ( nLen > _nMaxLen )
+ {
+ SharedResources aResources;
+ OUString sMessage = aResources.getResourceStringWithSubstitution( STR_STRING_LENGTH_EXCEEDED,
+ "$string$", _rSource,
+ "$maxlen$", OUString::number( _nMaxLen ),
+ "$charset$", lcl_getEncodingName( _eEncoding )
+ );
+
+ throw SQLException(
+ sMessage,
+ nullptr,
+ "22001",
+ 22001,
+ Any()
+ );
+ }
+
+ return nLen;
+}
+
+OUString getDefaultReportEngineServiceName(const Reference< XComponentContext >& _rxORB)
+{
+ ::utl::OConfigurationTreeRoot aReportEngines = ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ _rxORB, "org.openoffice.Office.DataAccess/ReportEngines", -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
+
+ if ( aReportEngines.isValid() )
+ {
+ OUString sDefaultReportEngineName;
+ aReportEngines.getNodeValue("DefaultReportEngine") >>= sDefaultReportEngineName;
+ if ( !sDefaultReportEngineName.isEmpty() )
+ {
+ ::utl::OConfigurationNode aReportEngineNames = aReportEngines.openNode("ReportEngineNames");
+ if ( aReportEngineNames.isValid() )
+ {
+ ::utl::OConfigurationNode aReportEngine = aReportEngineNames.openNode(sDefaultReportEngineName);
+ if ( aReportEngine.isValid() )
+ {
+ OUString sRet;
+ aReportEngine.getNodeValue("ServiceName") >>= sRet;
+ return sRet;
+ }
+ }
+ }
+ else
+ return "org.libreoffice.report.pentaho.SOReportJobFactory";
+ }
+ else
+ return "org.libreoffice.report.pentaho.SOReportJobFactory";
+ return OUString();
+}
+
+bool isAggregateColumn(const Reference< XSingleSelectQueryComposer > &_xParser, const Reference< XPropertySet > &_xField)
+{
+ OUString sName;
+ _xField->getPropertyValue("Name") >>= sName;
+ Reference< XColumnsSupplier > xColumnsSupplier(_xParser, UNO_QUERY);
+ Reference< css::container::XNameAccess > xCols;
+ if (xColumnsSupplier.is())
+ xCols = xColumnsSupplier->getColumns();
+
+ return isAggregateColumn(xCols, sName);
+}
+
+bool isAggregateColumn(const Reference< XNameAccess > &_xColumns, const OUString &_sName)
+{
+ if ( _xColumns.is() && _xColumns->hasByName(_sName) )
+ {
+ Reference<XPropertySet> xProp(_xColumns->getByName(_sName),UNO_QUERY);
+ assert(xProp.is());
+ return isAggregateColumn( xProp );
+ }
+ return false;
+}
+
+bool isAggregateColumn( const Reference< XPropertySet > &_xColumn )
+{
+ bool bAgg(false);
+
+ static constexpr OUStringLiteral sAgg = u"AggregateFunction";
+ if ( _xColumn->getPropertySetInfo()->hasPropertyByName(sAgg) )
+ _xColumn->getPropertyValue(sAgg) >>= bAgg;
+
+ return bAgg;
+}
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/filtermanager.cxx b/connectivity/source/commontools/filtermanager.cxx
new file mode 100644
index 000000000..07d93984f
--- /dev/null
+++ b/connectivity/source/commontools/filtermanager.cxx
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/filtermanager.hxx>
+
+#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
+#include <TConnection.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+#include <rtl/ustrbuf.hxx>
+
+
+namespace dbtools
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace connectivity;
+
+ FilterManager::FilterManager( )
+ :m_bApplyPublicFilter( true )
+ {
+ }
+
+
+ void FilterManager::initialize( const Reference< XPropertySet >& _rxComponentAggregate )
+ {
+ m_xComponentAggregate = _rxComponentAggregate;
+ OSL_ENSURE( m_xComponentAggregate.is(), "FilterManager::initialize: invalid arguments!" );
+
+ if ( m_xComponentAggregate.is() )
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_APPLYFILTER), Any( true ) );
+ }
+
+
+ void FilterManager::dispose( )
+ {
+ m_xComponentAggregate.clear();
+ }
+
+
+ const OUString& FilterManager::getFilterComponent( FilterComponent _eWhich ) const
+ {
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ return m_aPublicFilterComponent;
+ case FilterComponent::PublicHaving:
+ return m_aPublicHavingComponent;
+ case FilterComponent::LinkFilter:
+ return m_aLinkFilterComponent;
+ case FilterComponent::LinkHaving:
+ return m_aLinkHavingComponent;
+ }
+ assert(false);
+
+ static const OUString sErr("#FilterManager::getFilterComponent unknown component#");
+ return sErr;
+ }
+
+
+ void FilterManager::setFilterComponent( FilterComponent _eWhich, const OUString& _rComponent )
+ {
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ m_aPublicFilterComponent = _rComponent;
+ break;
+ case FilterComponent::PublicHaving:
+ m_aPublicHavingComponent = _rComponent;
+ break;
+ case FilterComponent::LinkFilter:
+ m_aLinkFilterComponent = _rComponent;
+ break;
+ case FilterComponent::LinkHaving:
+ m_aLinkHavingComponent = _rComponent;
+ break;
+ }
+ try
+ {
+ if ( m_xComponentAggregate.is() )
+ {
+ bool propagate(true);
+ switch (_eWhich)
+ {
+ case FilterComponent::PublicFilter:
+ propagate = propagate && m_bApplyPublicFilter;
+ [[fallthrough]];
+ case FilterComponent::LinkFilter:
+ if (propagate)
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), Any( getComposedFilter() ) );
+ break;
+ case FilterComponent::PublicHaving:
+ propagate = propagate && m_bApplyPublicFilter;
+ [[fallthrough]];
+ case FilterComponent::LinkHaving:
+ if (propagate)
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), Any( getComposedHaving() ) );
+ break;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void FilterManager::setApplyPublicFilter( bool _bApply )
+ {
+ if ( m_bApplyPublicFilter == _bApply )
+ return;
+
+ m_bApplyPublicFilter = _bApply;
+
+ try
+ {
+ if ( m_xComponentAggregate.is())
+ {
+ // only where/if something changed
+ if (!getFilterComponent( FilterComponent::PublicFilter ).isEmpty())
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FILTER), Any( getComposedFilter() ) );
+ if (!getFilterComponent( FilterComponent::PublicHaving ).isEmpty())
+ m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), Any( getComposedHaving() ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void FilterManager::appendFilterComponent( OUStringBuffer& io_appendTo, std::u16string_view i_component )
+ {
+ if ( !io_appendTo.isEmpty() )
+ {
+ io_appendTo.insert( 0, '(' );
+ io_appendTo.insert( 1, ' ' );
+ io_appendTo.append( " ) AND " );
+ }
+
+ io_appendTo.append( "( " );
+ io_appendTo.append( i_component );
+ io_appendTo.append( " )" );
+ }
+
+
+ bool FilterManager::isThereAtMostOneFilterComponent( OUString& o_singleComponent ) const
+ {
+ if (m_bApplyPublicFilter) {
+ if (!m_aPublicFilterComponent.isEmpty() && !m_aLinkFilterComponent.isEmpty())
+ return false;
+ if (!m_aPublicFilterComponent.isEmpty())
+ o_singleComponent = m_aPublicFilterComponent;
+ else if (!m_aLinkFilterComponent.isEmpty())
+ o_singleComponent = m_aLinkFilterComponent;
+ else
+ o_singleComponent.clear();
+ return true;
+ }
+ else
+ {
+ if (m_aLinkFilterComponent.isEmpty())
+ o_singleComponent.clear();
+ else
+ o_singleComponent = m_aLinkFilterComponent;
+ return true;
+ }
+ }
+
+ bool FilterManager::isThereAtMostOneHavingComponent( OUString& o_singleComponent ) const
+ {
+ if (m_bApplyPublicFilter) {
+ if (!m_aPublicHavingComponent.isEmpty() && !m_aLinkHavingComponent.isEmpty())
+ return false;
+ if (!m_aPublicHavingComponent.isEmpty())
+ o_singleComponent = m_aPublicHavingComponent;
+ else if (!m_aLinkHavingComponent.isEmpty())
+ o_singleComponent = m_aLinkHavingComponent;
+ else
+ o_singleComponent.clear();
+ return true;
+ }
+ else
+ {
+ if (m_aLinkHavingComponent.isEmpty())
+ o_singleComponent.clear();
+ else
+ o_singleComponent = m_aLinkHavingComponent;
+ return true;
+ }
+ }
+
+
+ OUString FilterManager::getComposedFilter( ) const
+ {
+ // if we have only one non-empty component, then there's no need to compose anything
+ OUString singleComponent;
+ if ( isThereAtMostOneFilterComponent( singleComponent ) )
+ {
+ return singleComponent;
+ }
+ // append the single components
+ OUStringBuffer aComposedFilter(singleComponent);
+ if (m_bApplyPublicFilter)
+ appendFilterComponent( aComposedFilter, m_aPublicFilterComponent );
+ appendFilterComponent( aComposedFilter, m_aLinkFilterComponent );
+ return aComposedFilter.makeStringAndClear();
+ }
+
+
+ OUString FilterManager::getComposedHaving( ) const
+ {
+ // if we have only one non-empty component, then there's no need to compose anything
+ OUString singleComponent;
+ if ( isThereAtMostOneHavingComponent( singleComponent ) )
+ {
+ return singleComponent;
+ }
+ // append the single components
+ OUStringBuffer aComposedFilter(singleComponent);
+ if (m_bApplyPublicFilter)
+ appendFilterComponent( aComposedFilter, m_aPublicHavingComponent );
+ appendFilterComponent( aComposedFilter, m_aLinkHavingComponent );
+ return aComposedFilter.makeStringAndClear();
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/formattedcolumnvalue.cxx b/connectivity/source/commontools/formattedcolumnvalue.cxx
new file mode 100644
index 000000000..e29087523
--- /dev/null
+++ b/connectivity/source/commontools/formattedcolumnvalue.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/formattedcolumnvalue.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbconversion.hxx>
+
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <comphelper/numbers.hxx>
+
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::sdbc::XRowSet;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::util::XNumberFormatter;
+ using ::com::sun::star::util::Date;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::util::XNumberFormatTypes;
+ using ::com::sun::star::sdb::XColumn;
+ using ::com::sun::star::sdb::XColumnUpdate;
+
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+ namespace NumberFormat = ::com::sun::star::util::NumberFormat;
+
+ struct FormattedColumnValue_Data
+ {
+ Reference< XNumberFormatter > m_xFormatter;
+ Date m_aNullDate;
+ sal_Int32 m_nFormatKey;
+ sal_Int32 m_nFieldType;
+ sal_Int16 m_nKeyType;
+ bool m_bNumericField;
+
+ Reference< XColumn > m_xColumn;
+ Reference< XColumnUpdate > m_xColumnUpdate;
+
+ FormattedColumnValue_Data()
+ :m_aNullDate( DBTypeConversion::getStandardDate() )
+ ,m_nFormatKey( 0 )
+ ,m_nFieldType( DataType::OTHER )
+ ,m_nKeyType( NumberFormat::UNDEFINED )
+ ,m_bNumericField( false )
+ {
+ }
+ };
+
+
+ namespace
+ {
+
+ void lcl_clear_nothrow( FormattedColumnValue_Data& _rData )
+ {
+ _rData.m_xFormatter.clear();
+ _rData.m_nFormatKey = 0;
+ _rData.m_nFieldType = DataType::OTHER;
+ _rData.m_nKeyType = NumberFormat::UNDEFINED;
+ _rData.m_bNumericField = false;
+
+ _rData.m_xColumn.clear();
+ _rData.m_xColumnUpdate.clear();
+ }
+
+
+ void lcl_initColumnDataValue_nothrow( FormattedColumnValue_Data& _rData,
+ const Reference< XNumberFormatter >& i_rNumberFormatter, const Reference< XPropertySet >& _rxColumn )
+ {
+ lcl_clear_nothrow( _rData );
+
+ OSL_PRECOND( i_rNumberFormatter.is(), "lcl_initColumnDataValue_nothrow: no number formats -> no formatted values!" );
+ if ( !i_rNumberFormatter.is() )
+ return;
+
+ try
+ {
+ Reference< XNumberFormatsSupplier > xNumberFormatsSupp( i_rNumberFormatter->getNumberFormatsSupplier(), UNO_SET_THROW );
+
+ // remember the column
+ _rData.m_xColumn.set( _rxColumn, UNO_QUERY_THROW );
+ _rData.m_xColumnUpdate.set( _rxColumn, UNO_QUERY );
+
+ // determine the field type, and whether it's a numeric field
+ OSL_VERIFY( _rxColumn->getPropertyValue("Type") >>= _rData.m_nFieldType );
+
+ switch ( _rData.m_nFieldType )
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::REAL:
+ case DataType::BIGINT:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ _rData.m_bNumericField = true;
+ break;
+ default:
+ _rData.m_bNumericField = false;
+ break;
+ }
+
+ // get the format key of our bound field
+ Reference< XPropertySetInfo > xPSI( _rxColumn->getPropertySetInfo(), UNO_SET_THROW );
+ bool bHaveFieldFormat = false;
+ static const OUStringLiteral sFormatKeyProperty( u"FormatKey" );
+ if ( xPSI->hasPropertyByName( sFormatKeyProperty ) )
+ {
+ bHaveFieldFormat = ( _rxColumn->getPropertyValue( sFormatKeyProperty ) >>= _rData.m_nFormatKey );
+ }
+ if ( !bHaveFieldFormat )
+ {
+ // fall back to a format key as indicated by the field type
+ Locale aSystemLocale( LanguageTag( MsLangId::getConfiguredSystemLanguage() ).getLocale() );
+ Reference< XNumberFormatTypes > xNumTypes( xNumberFormatsSupp->getNumberFormats(), UNO_QUERY_THROW );
+ _rData.m_nFormatKey = getDefaultNumberFormat( _rxColumn, xNumTypes, aSystemLocale );
+ }
+
+ // some more formatter settings
+ _rData.m_nKeyType = ::comphelper::getNumberFormatType( xNumberFormatsSupp->getNumberFormats(), _rData.m_nFormatKey );
+ Reference< XPropertySet > xFormatSettings( xNumberFormatsSupp->getNumberFormatSettings(), UNO_SET_THROW );
+ OSL_VERIFY( xFormatSettings->getPropertyValue("NullDate") >>= _rData.m_aNullDate );
+
+ // remember the formatter
+ _rData.m_xFormatter = i_rNumberFormatter;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ void lcl_initColumnDataValue_nothrow( const Reference<XComponentContext>& i_rContext, FormattedColumnValue_Data& i_rData,
+ const Reference< XRowSet >& i_rRowSet, const Reference< XPropertySet >& i_rColumn )
+ {
+ OSL_PRECOND( i_rRowSet.is(), "lcl_initColumnDataValue_nothrow: no row set!" );
+ if ( !i_rRowSet.is() )
+ return;
+
+ Reference< XNumberFormatter > xNumberFormatter;
+ try
+ {
+ // get the number formats supplier of the connection of the form
+ Reference< XConnection > xConnection( getConnection( i_rRowSet ), UNO_SET_THROW );
+ Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection, true, i_rContext ), UNO_SET_THROW );
+
+ // create a number formatter for it
+ xNumberFormatter.set( NumberFormatter::create( i_rContext ), UNO_QUERY_THROW );
+ xNumberFormatter->attachNumberFormatsSupplier( xSupplier );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ lcl_initColumnDataValue_nothrow( i_rData, xNumberFormatter, i_rColumn );
+ }
+ }
+
+ FormattedColumnValue::FormattedColumnValue( const Reference< XComponentContext >& _rxContext,
+ const Reference< XRowSet >& _rxRowSet, const Reference< XPropertySet >& i_rColumn )
+ :m_pData( new FormattedColumnValue_Data )
+ {
+ lcl_initColumnDataValue_nothrow( _rxContext, *m_pData, _rxRowSet, i_rColumn );
+ }
+
+
+ FormattedColumnValue::FormattedColumnValue( const Reference< XNumberFormatter >& i_rNumberFormatter,
+ const Reference< XPropertySet >& _rxColumn )
+ :m_pData( new FormattedColumnValue_Data )
+ {
+ lcl_initColumnDataValue_nothrow( *m_pData, i_rNumberFormatter, _rxColumn );
+ }
+
+
+ FormattedColumnValue::~FormattedColumnValue()
+ {
+ lcl_clear_nothrow( *m_pData );
+ }
+
+ sal_Int16 FormattedColumnValue::getKeyType() const
+ {
+ return m_pData->m_nKeyType;
+ }
+
+
+ const Reference< XColumn >& FormattedColumnValue::getColumn() const
+ {
+ return m_pData->m_xColumn;
+ }
+
+ bool FormattedColumnValue::setFormattedValue( const OUString& _rFormattedStringValue ) const
+ {
+ OSL_PRECOND( m_pData->m_xColumnUpdate.is(), "FormattedColumnValue::setFormattedValue: no column!" );
+ if ( !m_pData->m_xColumnUpdate.is() )
+ return false;
+
+ try
+ {
+ if ( m_pData->m_bNumericField )
+ {
+ ::dbtools::DBTypeConversion::setValue( m_pData->m_xColumnUpdate, m_pData->m_xFormatter, m_pData->m_aNullDate,
+ _rFormattedStringValue, m_pData->m_nFormatKey, ::sal::static_int_cast< sal_Int16 >( m_pData->m_nFieldType ),
+ m_pData->m_nKeyType );
+ }
+ else
+ {
+ m_pData->m_xColumnUpdate->updateString( _rFormattedStringValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ return false;
+ }
+ return true;
+ }
+
+
+ OUString FormattedColumnValue::getFormattedValue() const
+ {
+ OSL_PRECOND( m_pData->m_xColumn.is(), "FormattedColumnValue::setFormattedValue: no column!" );
+
+ OUString sStringValue;
+ if ( m_pData->m_xColumn.is() )
+ {
+ if ( m_pData->m_bNumericField )
+ {
+ sStringValue = DBTypeConversion::getFormattedValue(
+ m_pData->m_xColumn, m_pData->m_xFormatter, m_pData->m_aNullDate, m_pData->m_nFormatKey, m_pData->m_nKeyType
+ );
+ }
+ else
+ {
+ sStringValue = m_pData->m_xColumn->getString();
+ }
+ }
+ return sStringValue;
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/parameters.cxx b/connectivity/source/commontools/parameters.cxx
new file mode 100644
index 000000000..c18fc2831
--- /dev/null
+++ b/connectivity/source/commontools/parameters.cxx
@@ -0,0 +1,1216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/parameters.hxx>
+
+#include <com/sun/star/form/DatabaseParameterEvent.hpp>
+#include <com/sun/star/form/XDatabaseParameterListener.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/ParametersRequest.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <connectivity/filtermanager.hxx>
+#include <TConnection.hxx>
+
+#include <tools/diagnose_ex.h>
+
+#include <ParameterCont.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+namespace dbtools
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::container;
+
+ using namespace ::comphelper;
+ using namespace ::connectivity;
+
+ ParameterManager::ParameterManager( ::osl::Mutex& _rMutex, const Reference< XComponentContext >& _rxContext )
+ :m_rMutex ( _rMutex )
+ ,m_aParameterListeners( _rMutex )
+ ,m_xContext ( _rxContext )
+ ,m_nInnerCount ( 0 )
+ ,m_bUpToDate ( false )
+ {
+ OSL_ENSURE( m_xContext.is(), "ParameterManager::ParameterManager: no service factory!" );
+ }
+
+
+ void ParameterManager::initialize( const Reference< XPropertySet >& _rxComponent, const Reference< XAggregation >& _rxComponentAggregate )
+ {
+ OSL_ENSURE( !m_xComponent.get().is(), "ParameterManager::initialize: already initialized!" );
+
+ m_xComponent = _rxComponent;
+ m_xAggregatedRowSet = _rxComponentAggregate;
+ if ( m_xAggregatedRowSet.is() )
+ m_xAggregatedRowSet->queryAggregation( cppu::UnoType<decltype(m_xInnerParamUpdate)>::get() ) >>= m_xInnerParamUpdate;
+ OSL_ENSURE( m_xComponent.get().is() && m_xInnerParamUpdate.is(), "ParameterManager::initialize: invalid arguments!" );
+ if ( !m_xComponent.get().is() || !m_xInnerParamUpdate.is() )
+ return;
+ }
+
+
+ void ParameterManager::dispose( )
+ {
+ clearAllParameterInformation();
+
+ m_xComposer.clear();
+ m_xParentComposer.clear();
+ //m_xComponent.clear();
+ m_xInnerParamUpdate.clear();
+ m_xAggregatedRowSet.clear();
+ }
+
+
+ void ParameterManager::clearAllParameterInformation()
+ {
+ m_xInnerParamColumns.clear();
+ if ( m_pOuterParameters.is() )
+ m_pOuterParameters->dispose();
+ m_pOuterParameters = nullptr;
+ m_nInnerCount = 0;
+ ParameterInformation().swap(m_aParameterInformation);
+ m_aMasterFields.clear();
+ m_aDetailFields.clear();
+ m_sIdentifierQuoteString.clear();
+ m_sSpecialCharacters.clear();
+ m_xConnectionMetadata.clear();
+ std::vector< bool >().swap(m_aParametersVisited);
+ m_bUpToDate = false;
+ }
+
+
+ void ParameterManager::setAllParametersNull()
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::setAllParametersNull: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ for ( sal_Int32 i = 1; i <= m_nInnerCount; ++i )
+ m_xInnerParamUpdate->setNull( i, DataType::VARCHAR );
+ }
+
+
+ bool ParameterManager::initializeComposerByComponent( const Reference< XPropertySet >& _rxComponent )
+ {
+ OSL_PRECOND( _rxComponent.is(), "ParameterManager::initializeComposerByComponent: invalid !" );
+
+ m_xComposer.clear();
+ m_xInnerParamColumns.clear();
+ m_nInnerCount = 0;
+
+ // create and fill a composer
+ try
+ {
+ // get a query composer for the 's settings
+ m_xComposer.reset( getCurrentSettingsComposer( _rxComponent, m_xContext, nullptr ), SharedQueryComposer::TakeOwnership );
+
+ // see if the composer found parameters
+ Reference< XParametersSupplier > xParamSupp( m_xComposer, UNO_QUERY );
+ if ( xParamSupp.is() )
+ m_xInnerParamColumns = xParamSupp->getParameters();
+
+ if ( m_xInnerParamColumns.is() )
+ m_nInnerCount = m_xInnerParamColumns->getCount();
+ }
+ catch( const SQLException& )
+ {
+ }
+
+ return m_xInnerParamColumns.is();
+ }
+
+
+ void ParameterManager::collectInnerParameters( bool _bSecondRun )
+ {
+ OSL_PRECOND( m_xInnerParamColumns.is(), "ParameterManager::collectInnerParameters: missing some internal data!" );
+ if ( !m_xInnerParamColumns.is() )
+ return;
+
+ // strip previous index information
+ if ( _bSecondRun )
+ {
+ for (auto & paramInfo : m_aParameterInformation)
+ {
+ paramInfo.second.aInnerIndexes.clear();
+ }
+ }
+
+ // we need to map the parameter names (which is all we get from the 's
+ // MasterFields property) to indices, which are needed by the XParameters
+ // interface of the row set)
+ Reference<XPropertySet> xParam;
+ for ( sal_Int32 i = 0; i < m_nInnerCount; ++i )
+ {
+ try
+ {
+ xParam.clear();
+ m_xInnerParamColumns->getByIndex( i ) >>= xParam;
+
+ OUString sName;
+ xParam->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
+
+ // only append additional parameters when they are not already in the list
+ ParameterInformation::iterator aExistentPos = m_aParameterInformation.find( sName );
+ OSL_ENSURE( !_bSecondRun || ( aExistentPos != m_aParameterInformation.end() ),
+ "ParameterManager::collectInnerParameters: the parameter information should already exist in the second run!" );
+
+ if ( aExistentPos == m_aParameterInformation.end() )
+ {
+ aExistentPos = m_aParameterInformation.emplace(
+ sName, xParam ).first;
+ }
+ else
+ aExistentPos->second.xComposerColumn = xParam;
+
+ aExistentPos->second.aInnerIndexes.push_back( i );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::collectInnerParameters" );
+ }
+ }
+ }
+
+
+ OUString ParameterManager::createFilterConditionFromColumnLink(
+ const OUString &_rMasterColumn, const Reference < XPropertySet > &xDetailField, OUString &o_rNewParamName )
+ {
+ OUString sFilter;
+ // format is:
+ // <detail_column> = :<new_param_name>
+ {
+ OUString tblName;
+ xDetailField->getPropertyValue("TableName") >>= tblName;
+ if (!tblName.isEmpty())
+ sFilter = ::dbtools::quoteTableName( m_xConnectionMetadata, tblName, ::dbtools::EComposeRule::InDataManipulation ) + ".";
+ }
+ {
+ OUString colName;
+ xDetailField->getPropertyValue("RealName") >>= colName;
+ bool isFunction(false);
+ xDetailField->getPropertyValue("Function") >>= isFunction;
+ if (isFunction)
+ sFilter += colName;
+ else
+ sFilter += quoteName( m_sIdentifierQuoteString, colName );
+ }
+
+ // generate a parameter name which is not already used
+ o_rNewParamName = "link_from_";
+ o_rNewParamName += convertName2SQLName( _rMasterColumn, m_sSpecialCharacters );
+ while ( m_aParameterInformation.find( o_rNewParamName ) != m_aParameterInformation.end() )
+ {
+ o_rNewParamName += "_";
+ }
+
+ return sFilter + " =:" + o_rNewParamName;
+ }
+
+
+ void ParameterManager::classifyLinks( const Reference< XNameAccess >& _rxParentColumns,
+ const Reference< XNameAccess >& _rxColumns,
+ std::vector< OUString >& _out_rAdditionalFilterComponents,
+ std::vector< OUString >& _out_rAdditionalHavingComponents )
+ {
+ OSL_PRECOND( m_aMasterFields.size() == m_aDetailFields.size(),
+ "ParameterManager::classifyLinks: master and detail fields should have the same length!" );
+ OSL_ENSURE( _rxColumns.is(), "ParameterManager::classifyLinks: invalid columns!" );
+
+ if ( !_rxColumns.is() )
+ return;
+
+ // we may need to strip any links which are invalid, so here go the containers
+ // for temporarily holding the new pairs
+ std::vector< OUString > aStrippedMasterFields;
+ std::vector< OUString > aStrippedDetailFields;
+
+ bool bNeedExchangeLinks = false;
+
+ // classify the links
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+ auto pDetailFieldsEnd = m_aDetailFields.end();
+ for ( ; pDetailFields != pDetailFieldsEnd; ++pDetailFields, ++pMasterFields )
+ {
+ if ( pMasterFields->isEmpty() || pDetailFields->isEmpty() )
+ continue;
+
+ // if not even the master part of the relationship exists in the parent, the
+ // link is invalid as a whole #i63674#
+ if ( !_rxParentColumns->hasByName( *pMasterFields ) )
+ {
+ bNeedExchangeLinks = true;
+ continue;
+ }
+
+ bool bValidLink = true;
+
+ // is there an inner parameter with this name? That is, a parameter which is already part of
+ // the very original statement (not the one we create ourselves, with the additional parameters)
+ ParameterInformation::iterator aPos = m_aParameterInformation.find( *pDetailFields );
+ if ( aPos != m_aParameterInformation.end() )
+ { // there is an inner parameter with this name
+ aPos->second.eType = ParameterClassification::LinkedByParamName;
+ aStrippedDetailFields.push_back( *pDetailFields );
+ }
+ else
+ {
+ // does the detail name denote a column?
+ if ( _rxColumns->hasByName( *pDetailFields ) )
+ {
+ Reference< XPropertySet > xDetailField(_rxColumns->getByName( *pDetailFields ), UNO_QUERY);
+ assert(xDetailField.is());
+
+ OUString sNewParamName;
+ const OUString sFilterCondition = createFilterConditionFromColumnLink( *pMasterFields, xDetailField, sNewParamName );
+ OSL_PRECOND( !sNewParamName.isEmpty(), "ParameterManager::classifyLinks: createFilterConditionFromColumnLink returned nonsense!" );
+
+ // remember meta information about this new parameter
+ std::pair< ParameterInformation::iterator, bool > aInsertionPos =
+ m_aParameterInformation.emplace(
+ sNewParamName, ParameterMetaData( nullptr )
+ );
+ OSL_ENSURE( aInsertionPos.second, "ParameterManager::classifyLinks: there already was a parameter with this name!" );
+ aInsertionPos.first->second.eType = ParameterClassification::LinkedByColumnName;
+
+ // remember the filter component
+ if (isAggregateColumn(xDetailField))
+ _out_rAdditionalHavingComponents.push_back( sFilterCondition );
+ else
+ _out_rAdditionalFilterComponents.push_back( sFilterCondition );
+
+ // remember the new "detail field" for this link
+ aStrippedDetailFields.push_back( sNewParamName );
+ bNeedExchangeLinks = true;
+ }
+ else
+ {
+ // the detail field neither denotes a column name, nor a parameter name
+ bValidLink = false;
+ bNeedExchangeLinks = true;
+ }
+ }
+
+ if ( bValidLink )
+ aStrippedMasterFields.push_back( *pMasterFields );
+ }
+ SAL_WARN_IF( aStrippedMasterFields.size() != aStrippedDetailFields.size(),
+ "connectivity.commontools",
+ "ParameterManager::classifyLinks: inconsistency in new link pairs!" );
+
+ if ( bNeedExchangeLinks )
+ {
+ m_aMasterFields.swap(aStrippedMasterFields);
+ m_aDetailFields.swap(aStrippedDetailFields);
+ }
+ }
+
+
+ void ParameterManager::analyzeFieldLinks( FilterManager& _rFilterManager, bool& /* [out] */ _rColumnsInLinkDetails )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::analyzeFieldLinks: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ _rColumnsInLinkDetails = false;
+ try
+ {
+ // the links as determined by the properties
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Someone already released my component!");
+ if ( xProp.is() )
+ {
+ Sequence<OUString> aTmp;
+ if (xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MASTERFIELDS) ) >>= aTmp)
+ comphelper::sequenceToContainer(m_aMasterFields, aTmp);
+ if (xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DETAILFIELDS) ) >>= aTmp)
+ comphelper::sequenceToContainer(m_aDetailFields, aTmp);
+ }
+
+ {
+ // normalize to equal length
+ sal_Int32 nMasterLength = m_aMasterFields.size();
+ sal_Int32 nDetailLength = m_aDetailFields.size();
+
+ if ( nMasterLength > nDetailLength )
+ m_aMasterFields.resize( nDetailLength );
+ else if ( nDetailLength > nMasterLength )
+ m_aDetailFields.resize( nMasterLength );
+ }
+
+ Reference< XNameAccess > xColumns;
+ if ( !getColumns( xColumns, true ) )
+ // already asserted in getColumns
+ return;
+
+ Reference< XNameAccess > xParentColumns;
+ if ( !getParentColumns( xParentColumns, true ) )
+ return;
+
+ // classify the links - depending on what the detail fields in each link pair denotes
+ std::vector< OUString > aAdditionalFilterComponents;
+ std::vector< OUString > aAdditionalHavingComponents;
+ classifyLinks( xParentColumns, xColumns, aAdditionalFilterComponents, aAdditionalHavingComponents );
+
+ // did we find links where the detail field refers to a detail column (instead of a parameter name)?
+ if ( !aAdditionalFilterComponents.empty() )
+ {
+ // build a conjunction of all the filter components
+ OUStringBuffer sAdditionalFilter;
+ for (auto const& elem : aAdditionalFilterComponents)
+ {
+ if ( !sAdditionalFilter.isEmpty() )
+ sAdditionalFilter.append(" AND ");
+
+ sAdditionalFilter.append("( ");
+ sAdditionalFilter.append(elem);
+ sAdditionalFilter.append(" )");
+ }
+
+ // now set this filter at the filter manager
+ _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkFilter, sAdditionalFilter.makeStringAndClear() );
+
+ _rColumnsInLinkDetails = true;
+ }
+
+ if ( !aAdditionalHavingComponents.empty() )
+ {
+ // build a conjunction of all the filter components
+ OUStringBuffer sAdditionalHaving;
+ for (auto const& elem : aAdditionalHavingComponents)
+ {
+ if ( !sAdditionalHaving.isEmpty() )
+ sAdditionalHaving.append(" AND ");
+
+ sAdditionalHaving.append("( ");
+ sAdditionalHaving.append(elem);
+ sAdditionalHaving.append(" )");
+ }
+
+ // now set this having clause at the filter manager
+ _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkHaving, sAdditionalHaving.makeStringAndClear() );
+
+ _rColumnsInLinkDetails = true;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::analyzeFieldLinks" );
+ }
+ }
+
+
+ void ParameterManager::createOuterParameters()
+ {
+ OSL_PRECOND( !m_pOuterParameters.is(), "ParameterManager::createOuterParameters: outer parameters not initialized!" );
+ OSL_PRECOND( m_xInnerParamUpdate.is(), "ParameterManager::createOuterParameters: no write access to the inner parameters!" );
+ if ( !m_xInnerParamUpdate.is() )
+ return;
+
+ m_pOuterParameters = new param::ParameterWrapperContainer;
+
+#if OSL_DEBUG_LEVEL > 0
+ sal_Int32 nSmallestIndexLinkedByColumnName = -1;
+ sal_Int32 nLargestIndexNotLinkedByColumnName = -1;
+#endif
+ for (auto & aParam : m_aParameterInformation)
+ {
+#if OSL_DEBUG_LEVEL > 0
+ if ( aParam.second.aInnerIndexes.size() )
+ {
+ if ( aParam.second.eType == ParameterClassification::LinkedByColumnName )
+ {
+ if ( nSmallestIndexLinkedByColumnName == -1 )
+ nSmallestIndexLinkedByColumnName = aParam.second.aInnerIndexes[ 0 ];
+ }
+ else
+ {
+ nLargestIndexNotLinkedByColumnName = aParam.second.aInnerIndexes[ aParam.second.aInnerIndexes.size() - 1 ];
+ }
+ }
+#endif
+ if ( aParam.second.eType != ParameterClassification::FilledExternally )
+ continue;
+
+ // check which of the parameters have already been visited (e.g. filled via XParameters)
+ size_t nAlreadyVisited = 0;
+ for (auto & aIndex : aParam.second.aInnerIndexes)
+ {
+ if ( ( m_aParametersVisited.size() > o3tl::make_unsigned(aIndex) ) && m_aParametersVisited[ aIndex ] )
+ { // exclude this index
+ aIndex = -1;
+ ++nAlreadyVisited;
+ }
+ }
+ if ( nAlreadyVisited == aParam.second.aInnerIndexes.size() )
+ continue;
+
+ // need a wrapper for this... the "inner parameters" as supplied by a result set don't have a "Value"
+ // property, but the parameter listeners expect such a property. So we need an object "aggregating"
+ // xParam and supplying an additional property ("Value")
+ // (it's no real aggregation of course...)
+ m_pOuterParameters->push_back( new param::ParameterWrapper( aParam.second.xComposerColumn, m_xInnerParamUpdate, std::vector(aParam.second.aInnerIndexes) ) );
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE( ( nSmallestIndexLinkedByColumnName == -1 ) || ( nLargestIndexNotLinkedByColumnName == -1 ) ||
+ ( nSmallestIndexLinkedByColumnName > nLargestIndexNotLinkedByColumnName ),
+ "ParameterManager::createOuterParameters: inconsistency!" );
+
+ // for the master-detail links, where the detail field denoted a column name, we created an additional ("artificial")
+ // filter, and *appended* it to all other (potentially) existing filters of the row set. This means that the indexes
+ // for the parameters resulting from the artificial filter should be larger than any other parameter index, and this
+ // is what the assertion checks.
+ // If the assertion fails, then we would need another handling for the "parameters visited" flags, since they're based
+ // on parameter indexes *without* the artificial filter (because this filter is not visible from the outside).
+#endif
+ }
+
+
+ void ParameterManager::updateParameterInfo( FilterManager& _rFilterManager )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::updateParameterInfo: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ clearAllParameterInformation();
+ cacheConnectionInfo();
+
+ // check whether the is based on a statement/query which requires parameters
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ if ( xProp.is() )
+ {
+ if ( !initializeComposerByComponent( xProp ) )
+ { // okay, nothing to do
+ m_bUpToDate = true;
+ return;
+ } // if ( !initializeComposerByComponent( m_xComponent ) )
+ }
+ SAL_WARN_IF( !m_xInnerParamColumns.is(),
+ "connectivity.commontools",
+ "ParameterManager::updateParameterInfo: initializeComposerByComponent did nonsense (1)!" );
+
+ // collect all parameters which are defined by the "inner parameters"
+ collectInnerParameters( false );
+
+ // analyze the master-detail relationships
+ bool bColumnsInLinkDetails = false;
+ analyzeFieldLinks( _rFilterManager, bColumnsInLinkDetails );
+
+ if ( bColumnsInLinkDetails )
+ {
+ // okay, in this case, analyzeFieldLinks modified the "real" filter at the RowSet, to contain
+ // an additional restriction (which we created ourself)
+ // So we need to update all information about our inner parameter columns
+ Reference< XPropertySet > xDirectRowSetProps;
+ m_xAggregatedRowSet->queryAggregation( cppu::UnoType<decltype(xDirectRowSetProps)>::get() ) >>= xDirectRowSetProps;
+ OSL_VERIFY( initializeComposerByComponent( xDirectRowSetProps ) );
+ collectInnerParameters( true );
+ }
+
+ if ( !m_nInnerCount )
+ { // no parameters at all
+ m_bUpToDate = true;
+ return;
+ }
+
+ // for what now remains as outer parameters, create the wrappers for the single
+ // parameter columns
+ createOuterParameters();
+
+ m_bUpToDate = true;
+ }
+
+
+ void ParameterManager::fillLinkedParameters( const Reference< XNameAccess >& _rxParentColumns )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::fillLinkedParameters: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+ OSL_PRECOND( m_xInnerParamColumns.is(), "ParameterManager::fillLinkedParameters: no inner parameters found!" );
+ OSL_ENSURE ( _rxParentColumns.is(), "ParameterManager::fillLinkedParameters: invalid parent columns!" );
+
+ try
+ {
+ // the master and detail field( name)s of the
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+
+ sal_Int32 nMasterLen = m_aMasterFields.size();
+
+ // loop through all master fields. For each of them, get the respective column from the
+ // parent , and forward its current value as parameter value to the (inner) row set
+ for ( sal_Int32 i = 0; i < nMasterLen; ++i, ++pMasterFields, ++pDetailFields )
+ {
+ // does the name denote a valid column in the parent?
+ if ( !_rxParentColumns->hasByName( *pMasterFields ) )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: invalid master names should have been stripped long before!" );
+ continue;
+ }
+
+ // do we, for this name, know where to place the values?
+ ParameterInformation::const_iterator aParamInfo = m_aParameterInformation.find( *pDetailFields );
+ if ( ( aParamInfo == m_aParameterInformation.end() )
+ || ( aParamInfo->second.aInnerIndexes.empty() )
+ )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: nothing known about this detail field!" );
+ continue;
+ }
+
+ // the concrete master field
+ Reference< XPropertySet > xMasterField(_rxParentColumns->getByName( *pMasterFields ),UNO_QUERY);
+
+ // the positions where we have to fill in values for the current parameter name
+ for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
+ {
+ // the concrete detail field
+ Reference< XPropertySet > xDetailField(m_xInnerParamColumns->getByIndex(aPosition),UNO_QUERY);
+ OSL_ENSURE( xDetailField.is(), "ParameterManager::fillLinkedParameters: invalid detail field!" );
+ if ( !xDetailField.is() )
+ continue;
+
+ // type and scale of the parameter field
+ sal_Int32 nParamType = DataType::VARCHAR;
+ OSL_VERIFY( xDetailField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE) ) >>= nParamType );
+
+ sal_Int32 nScale = 0;
+ if ( xDetailField->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE) ) )
+ OSL_VERIFY( xDetailField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE) ) >>= nScale );
+
+ // transfer the param value
+ try
+ {
+ m_xInnerParamUpdate->setObjectWithInfo(
+ aPosition + 1, // parameters are based at 1
+ xMasterField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE) ),
+ nParamType,
+ nScale
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: master-detail parameter number " <<
+ sal_Int32( aPosition + 1 ) << " could not be filled!" );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+
+
+ bool ParameterManager::completeParameters( const Reference< XInteractionHandler >& _rxCompletionHandler, const Reference< XConnection >& _rxConnection )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::completeParameters: not initialized, or already disposed!" );
+ OSL_ENSURE ( _rxCompletionHandler.is(), "ParameterManager::completeParameters: invalid interaction handler!" );
+
+ // two continuations (Ok and Cancel)
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ rtl::Reference<OParameterContinuation> pParams = new OParameterContinuation;
+
+ // the request
+ ParametersRequest aRequest;
+ aRequest.Parameters = m_pOuterParameters.get();
+ aRequest.Connection = _rxConnection;
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest( Any( aRequest ) );
+
+ // some knittings
+ pRequest->addContinuation( pAbort );
+ pRequest->addContinuation( pParams );
+
+ // execute the request
+ try
+ {
+ _rxCompletionHandler->handle( pRequest );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while calling the handler" );
+ }
+
+ if ( !pParams->wasSelected() )
+ // canceled by the user (i.e. (s)he canceled the dialog)
+ return false;
+
+ try
+ {
+ // transfer the values from the continuation object to the parameter columns
+ const Sequence< PropertyValue >& aFinalValues = pParams->getValues();
+ const PropertyValue* pFinalValues = aFinalValues.getConstArray();
+ for ( sal_Int32 i = 0; i < aFinalValues.getLength(); ++i, ++pFinalValues )
+ {
+ Reference< XPropertySet > xParamColumn(aRequest.Parameters->getByIndex( i ),UNO_QUERY);
+ if ( xParamColumn.is() )
+ {
+ #ifdef DBG_UTIL
+ OUString sName;
+ xParamColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
+ OSL_ENSURE( sName == pFinalValues->Name, "ParameterManager::completeParameters: inconsistent parameter names!" );
+ #endif
+ xParamColumn->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE), pFinalValues->Value );
+ // the property sets are wrapper classes, translating the Value property into a call to
+ // the appropriate XParameters interface
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while propagating the values" );
+ }
+ return true;
+ }
+
+
+ bool ParameterManager::consultParameterListeners( ::osl::ResettableMutexGuard& _rClearForNotifies )
+ {
+ bool bCanceled = false;
+
+ sal_Int32 nParamsLeft = m_pOuterParameters->getParameters().size();
+ // TODO: shouldn't we subtract all the parameters which were already visited?
+ if ( nParamsLeft )
+ {
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aParameterListeners );
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ DatabaseParameterEvent aEvent( xProp, m_pOuterParameters );
+
+ _rClearForNotifies.clear();
+ while ( aIter.hasMoreElements() && !bCanceled )
+ bCanceled = !aIter.next()->approveParameter( aEvent );
+ _rClearForNotifies.reset();
+ }
+
+ return !bCanceled;
+ }
+
+
+ bool ParameterManager::fillParameterValues( const Reference< XInteractionHandler >& _rxCompletionHandler, ::osl::ResettableMutexGuard& _rClearForNotifies )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::fillParameterValues: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return true;
+
+ if ( m_nInnerCount == 0 )
+ // no parameters at all
+ return true;
+
+ // fill the parameters from the master-detail relationship
+ Reference< XNameAccess > xParentColumns;
+ if ( getParentColumns( xParentColumns, false ) && xParentColumns->hasElements() && !m_aMasterFields.empty() )
+ fillLinkedParameters( xParentColumns );
+
+ // let the user (via the interaction handler) fill all remaining parameters
+ Reference< XConnection > xConnection;
+ getConnection( xConnection );
+
+ if ( _rxCompletionHandler.is() )
+ return completeParameters( _rxCompletionHandler, xConnection );
+
+ return consultParameterListeners( _rClearForNotifies );
+ }
+
+
+ void ParameterManager::getConnection( Reference< XConnection >& /* [out] */ _rxConnection )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::getConnection: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ _rxConnection.clear();
+ try
+ {
+ Reference< XPropertySet > xProp = m_xComponent;
+ OSL_ENSURE(xProp.is(),"Some already released my component!");
+ if ( xProp.is() )
+ xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ACTIVE_CONNECTION) ) >>= _rxConnection;
+ }
+ catch( const Exception& )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::getConnection: could not retrieve the connection of the !" );
+ }
+ }
+
+
+ void ParameterManager::cacheConnectionInfo()
+ {
+ try
+ {
+ Reference< XConnection > xConnection;
+ getConnection( xConnection );
+ Reference< XDatabaseMetaData > xMeta;
+ if ( xConnection.is() )
+ xMeta = xConnection->getMetaData();
+ if ( xMeta.is() )
+ {
+ m_xConnectionMetadata = xMeta;
+ m_sIdentifierQuoteString = xMeta->getIdentifierQuoteString();
+ m_sSpecialCharacters = xMeta->getExtraNameCharacters();
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::cacheConnectionInfo: caught an exception" );
+ }
+ }
+
+
+ bool ParameterManager::getColumns( Reference< XNameAccess >& /* [out] */ _rxColumns, bool _bFromComposer )
+ {
+ _rxColumns.clear();
+
+ Reference< XColumnsSupplier > xColumnSupp;
+ if ( _bFromComposer )
+ xColumnSupp.set(m_xComposer, css::uno::UNO_QUERY);
+ else
+ xColumnSupp.set( m_xComponent.get(),UNO_QUERY);
+ if ( xColumnSupp.is() )
+ _rxColumns = xColumnSupp->getColumns();
+ OSL_ENSURE( _rxColumns.is(), "ParameterManager::getColumns: could not retrieve the columns for the detail !" );
+
+ return _rxColumns.is();
+ }
+
+
+ bool ParameterManager::getParentColumns( Reference< XNameAccess >& /* [out] */ _out_rxParentColumns, bool _bFromComposer )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::getParentColumns: not initialized, or already disposed!" );
+
+ _out_rxParentColumns.clear();
+ try
+ {
+ // get the parent of the component we're working for
+ Reference< XChild > xAsChild( m_xComponent.get(), UNO_QUERY_THROW );
+ Reference< XPropertySet > xParent( xAsChild->getParent(), UNO_QUERY );
+ if ( !xParent.is() )
+ return false;
+
+ // the columns supplier: either from a composer, or directly from the
+ Reference< XColumnsSupplier > xParentColSupp;
+ if ( _bFromComposer )
+ {
+ // re-create the parent composer all the time. Else, we'd have to bother with
+ // being a listener at its properties, its loaded state, and event the parent-relationship.
+ m_xParentComposer.reset(
+ getCurrentSettingsComposer( xParent, m_xContext, nullptr ),
+ SharedQueryComposer::TakeOwnership
+ );
+ xParentColSupp.set(m_xParentComposer, css::uno::UNO_QUERY);
+ }
+ else
+ xParentColSupp.set(xParent, css::uno::UNO_QUERY);
+
+ // get the columns of the parent
+ if ( xParentColSupp.is() )
+ _out_rxParentColumns = xParentColSupp->getColumns();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::getParentColumns" );
+ }
+ return _out_rxParentColumns.is();
+ }
+
+
+ void ParameterManager::addParameterListener( const Reference< XDatabaseParameterListener >& _rxListener )
+ {
+ if ( _rxListener.is() )
+ m_aParameterListeners.addInterface( _rxListener );
+ }
+
+
+ void ParameterManager::removeParameterListener( const Reference< XDatabaseParameterListener >& _rxListener )
+ {
+ m_aParameterListeners.removeInterface( _rxListener );
+ }
+
+
+ void ParameterManager::resetParameterValues( )
+ {
+ OSL_PRECOND( isAlive(), "ParameterManager::resetParameterValues: not initialized, or already disposed!" );
+ if ( !isAlive() )
+ return;
+
+ if ( !m_nInnerCount )
+ // no parameters at all
+ return;
+
+ try
+ {
+ Reference< XNameAccess > xColumns;
+ if ( !getColumns( xColumns, false ) )
+ // already asserted in getColumns
+ return;
+
+ Reference< XNameAccess > xParentColumns;
+ if ( !getParentColumns( xParentColumns, false ) )
+ return;
+
+ // loop through all links pairs
+ auto pMasterFields = m_aMasterFields.begin();
+ auto pDetailFields = m_aDetailFields.begin();
+
+ Reference< XPropertySet > xMasterField;
+ Reference< XPropertySet > xDetailField;
+
+ // now really ....
+ auto pDetailFieldsEnd = m_aDetailFields.end();
+ for ( ; pDetailFields != pDetailFieldsEnd; ++pDetailFields, ++pMasterFields )
+ {
+ if ( !xParentColumns->hasByName( *pMasterFields ) )
+ {
+ // if this name is unknown in the parent columns, then we don't have a source
+ // for copying the value to the detail columns
+ SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: this should have been stripped long before!" );
+ continue;
+ }
+
+ // for all inner parameters which are bound to the name as specified by the
+ // slave element of the link, propagate the value from the master column to this
+ // parameter column
+ ParameterInformation::const_iterator aParamInfo = m_aParameterInformation.find( *pDetailFields );
+ if ( ( aParamInfo == m_aParameterInformation.end() )
+ || ( aParamInfo->second.aInnerIndexes.empty() )
+ )
+ {
+ SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: nothing known about this detail field!" );
+ continue;
+ }
+
+ xParentColumns->getByName( *pMasterFields ) >>= xMasterField;
+ if ( !xMasterField.is() )
+ continue;
+
+ for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
+ {
+ Reference< XPropertySet > xInnerParameter;
+ m_xInnerParamColumns->getByIndex(aPosition) >>= xInnerParameter;
+ if ( !xInnerParameter.is() )
+ continue;
+
+ OUString sParamColumnRealName;
+ xInnerParameter->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME) ) >>= sParamColumnRealName;
+ if ( xColumns->hasByName( sParamColumnRealName ) )
+ { // our own columns have a column which's name equals the real name of the param column
+ // -> transfer the value property
+ xColumns->getByName( sParamColumnRealName ) >>= xDetailField;
+ if ( xDetailField.is() )
+ xDetailField->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE), xMasterField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE) ) );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::resetParameterValues" );
+ }
+
+ }
+
+
+ void ParameterManager::externalParameterVisited( sal_Int32 _nIndex )
+ {
+ if ( m_aParametersVisited.size() < o3tl::make_unsigned(_nIndex) )
+ {
+ m_aParametersVisited.reserve( _nIndex );
+ for ( sal_Int32 i = m_aParametersVisited.size(); i < _nIndex; ++i )
+ m_aParametersVisited.push_back( false );
+ }
+ m_aParametersVisited[ _nIndex - 1 ] = true;
+ }
+
+ void ParameterManager::setNull( sal_Int32 _nIndex, sal_Int32 sqlType )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setNull(_nIndex, sqlType);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObjectNull( sal_Int32 _nIndex, sal_Int32 sqlType, const OUString& typeName )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObjectNull(_nIndex, sqlType, typeName);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBoolean( sal_Int32 _nIndex, bool x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBoolean(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setByte( sal_Int32 _nIndex, sal_Int8 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setByte(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setShort( sal_Int32 _nIndex, sal_Int16 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setShort(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setInt( sal_Int32 _nIndex, sal_Int32 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setInt(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setLong( sal_Int32 _nIndex, sal_Int64 x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setLong(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setFloat( sal_Int32 _nIndex, float x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setFloat(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setDouble( sal_Int32 _nIndex, double x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setDouble(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setString( sal_Int32 _nIndex, const OUString& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setString(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBytes( sal_Int32 _nIndex, const css::uno::Sequence< sal_Int8 >& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBytes(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setDate( sal_Int32 _nIndex, const css::util::Date& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setDate(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setTime( sal_Int32 _nIndex, const css::util::Time& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setTime(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setTimestamp( sal_Int32 _nIndex, const css::util::DateTime& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setTimestamp(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBinaryStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBinaryStream(_nIndex, x, length);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setCharacterStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setCharacterStream(_nIndex, x, length);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObject( sal_Int32 _nIndex, const css::uno::Any& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObject(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setObjectWithInfo( sal_Int32 _nIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setObjectWithInfo(_nIndex, x, targetSqlType, scale);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setRef( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XRef>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setRef(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setBlob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XBlob>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setBlob(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setClob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XClob>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setClob(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::setArray( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XArray>& x )
+ {
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
+ if (!m_xInnerParamUpdate.is())
+ return;
+ m_xInnerParamUpdate->setArray(_nIndex, x);
+ externalParameterVisited(_nIndex);
+ }
+
+
+ void ParameterManager::clearParameters( )
+ {
+ if ( m_xInnerParamUpdate.is() )
+ m_xInnerParamUpdate->clearParameters( );
+ }
+
+ void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues )
+ {
+ m_aValues = _rValues;
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/paramwrapper.cxx b/connectivity/source/commontools/paramwrapper.cxx
new file mode 100644
index 000000000..820e2ae9e
--- /dev/null
+++ b/connectivity/source/commontools/paramwrapper.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 <connectivity/paramwrapper.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetException.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <o3tl/safeint.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/enumhelper.hxx>
+
+#define PROPERTY_ID_VALUE 1000
+
+
+namespace dbtools::param
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XParameters;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::XWeak;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XFastPropertySet;
+ using ::com::sun::star::beans::XMultiPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::lang::WrappedTargetException;
+ using ::com::sun::star::lang::IndexOutOfBoundsException;
+ using ::com::sun::star::container::XEnumeration;
+ using ::com::sun::star::sdb::XSingleSelectQueryAnalyzer;
+ using ::com::sun::star::sdb::XParametersSupplier;
+ using ::com::sun::star::lang::DisposedException;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+ namespace DataType = ::com::sun::star::sdbc::DataType;
+
+ ParameterWrapper::ParameterWrapper( const Reference< XPropertySet >& _rxColumn )
+ :PropertyBase( m_aBHelper )
+ ,m_xDelegator( _rxColumn )
+ {
+ if ( m_xDelegator.is() )
+ m_xDelegatorPSI = m_xDelegator->getPropertySetInfo();
+ if ( !m_xDelegatorPSI.is() )
+ throw RuntimeException();
+ }
+
+
+ ParameterWrapper::ParameterWrapper( const Reference< XPropertySet >& _rxColumn,
+ const Reference< XParameters >& _rxAllParameters, std::vector< sal_Int32 >&& _rIndexes )
+ :PropertyBase( m_aBHelper )
+ ,m_aIndexes( std::move(_rIndexes) )
+ ,m_xDelegator( _rxColumn )
+ ,m_xValueDestination( _rxAllParameters )
+ {
+ if ( m_xDelegator.is() )
+ m_xDelegatorPSI = m_xDelegator->getPropertySetInfo();
+ if ( !m_xDelegatorPSI.is() )
+ throw RuntimeException();
+
+ OSL_ENSURE( !m_aIndexes.empty(), "ParameterWrapper::ParameterWrapper: sure about the indexes?" );
+ }
+
+
+ ParameterWrapper::~ParameterWrapper()
+ {
+ }
+
+
+ IMPLEMENT_FORWARD_REFCOUNT( ParameterWrapper, UnoBase )
+
+ css::uno::Any ParameterWrapper::queryInterface(css::uno::Type const & aType)
+ {
+ css::uno::Any a(UnoBase::queryInterface(aType));
+ if (!a.hasValue()) {
+ a = PropertyBase::queryInterface(aType);
+ if (!a.hasValue()
+ && aType == cppu::UnoType<css::lang::XTypeProvider>::get())
+ {
+ a <<= css::uno::Reference<css::lang::XTypeProvider>(this);
+ }
+ }
+ return a;
+ }
+
+
+ Sequence< Type > SAL_CALL ParameterWrapper::getTypes( )
+ {
+ return Sequence< Type > {
+ cppu::UnoType<XWeak>::get(),
+ cppu::UnoType<XTypeProvider>::get(),
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get()
+ };
+ }
+
+
+ IMPLEMENT_GET_IMPLEMENTATION_ID( ParameterWrapper )
+
+
+ OUString ParameterWrapper::impl_getPseudoAggregatePropertyName( sal_Int32 _nHandle ) const
+ {
+ Reference< XPropertySetInfo > xInfo = const_cast<ParameterWrapper*>( this )->getPropertySetInfo();
+ const css::uno::Sequence<Property> aProperties = xInfo->getProperties();
+ for ( const Property& rProperty : aProperties )
+ {
+ if ( rProperty.Handle == _nHandle )
+ return rProperty.Name;
+ }
+
+ OSL_FAIL( "ParameterWrapper::impl_getPseudoAggregatePropertyName: invalid argument!" );
+ return OUString();
+ }
+
+
+ Reference< XPropertySetInfo > ParameterWrapper::getPropertySetInfo()
+ {
+ return createPropertySetInfo( getInfoHelper() );
+ }
+
+
+ ::cppu::IPropertyArrayHelper& ParameterWrapper::getInfoHelper()
+ {
+ if (!m_pInfoHelper)
+ {
+ Sequence< Property > aProperties;
+ try
+ {
+ aProperties = m_xDelegatorPSI->getProperties();
+ sal_Int32 nProperties( aProperties.getLength() );
+ aProperties.realloc( nProperties + 1 );
+ aProperties.getArray()[ nProperties ] = Property(
+ "Value",
+ PROPERTY_ID_VALUE,
+ ::cppu::UnoType< Any >::get(),
+ PropertyAttribute::TRANSIENT | PropertyAttribute::MAYBEVOID
+ );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ m_pInfoHelper.reset( new ::cppu::OPropertyArrayHelper( aProperties, false ) );
+ }
+ return *m_pInfoHelper;
+ }
+
+
+ sal_Bool ParameterWrapper::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
+ {
+ OSL_ENSURE( PROPERTY_ID_VALUE == nHandle, "ParameterWrapper::convertFastPropertyValue: the only non-readonly prop should be our PROPERTY_VALUE!" );
+
+ // we're lazy here ...
+ rOldValue = m_aValue.makeAny();
+ rConvertedValue = rValue;
+ return true; // assume "modified" ...
+ }
+
+
+ void ParameterWrapper::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+ {
+ if ( nHandle == PROPERTY_ID_VALUE )
+ {
+ try
+ {
+ // TODO : aParamType & nScale can be obtained within the constructor...
+ sal_Int32 nParamType = DataType::VARCHAR;
+ OSL_VERIFY( m_xDelegator->getPropertyValue("Type") >>= nParamType );
+
+ sal_Int32 nScale = 0;
+ if ( m_xDelegatorPSI->hasPropertyByName("Scale") )
+ OSL_VERIFY( m_xDelegator->getPropertyValue("Scale") >>= nScale );
+
+ if ( m_xValueDestination.is() )
+ {
+ for ( const auto& rIndex : m_aIndexes )
+ {
+ m_xValueDestination->setObjectWithInfo( rIndex + 1, rValue, nParamType, nScale );
+ // (the index of the parameters is one-based)
+ }
+ }
+
+ m_aValue = rValue;
+ }
+ catch( SQLException& e )
+ {
+ WrappedTargetException aExceptionWrapper;
+ aExceptionWrapper.Context = e.Context;
+ aExceptionWrapper.Message = e.Message;
+ aExceptionWrapper.TargetException <<= e;
+ throw aExceptionWrapper;
+ }
+ }
+ else
+ {
+ OUString aName = impl_getPseudoAggregatePropertyName( nHandle );
+ m_xDelegator->setPropertyValue( aName, rValue );
+ }
+ }
+
+
+ void ParameterWrapper::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+ {
+ if ( nHandle == PROPERTY_ID_VALUE )
+ {
+ rValue = m_aValue.makeAny();
+ }
+ else
+ {
+ OUString aName = impl_getPseudoAggregatePropertyName( nHandle );
+ rValue = m_xDelegator->getPropertyValue( aName );
+ }
+ }
+
+
+ void ParameterWrapper::dispose()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_aValue.setNull();
+ m_aIndexes.resize(0);
+ m_xDelegator.clear();
+ m_xDelegatorPSI.clear();
+ m_xValueDestination.clear();
+
+ m_aBHelper.bDisposed = true;
+ }
+
+ ParameterWrapperContainer::ParameterWrapperContainer()
+ :ParameterWrapperContainer_Base( m_aMutex )
+ {
+ }
+
+
+ ParameterWrapperContainer::ParameterWrapperContainer( const Reference< XSingleSelectQueryAnalyzer >& _rxComposer )
+ :ParameterWrapperContainer_Base( m_aMutex )
+ {
+ Reference< XParametersSupplier > xSuppParams( _rxComposer, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xParameters( xSuppParams->getParameters(), css::uno::UNO_SET_THROW );
+ sal_Int32 nParamCount( xParameters->getCount() );
+ m_aParameters.reserve( nParamCount );
+ for ( sal_Int32 i=0; i<nParamCount; ++i )
+ {
+ m_aParameters.push_back( new ParameterWrapper( Reference< XPropertySet >( xParameters->getByIndex( i ), UNO_QUERY_THROW ) ) );
+ }
+ }
+
+
+ ParameterWrapperContainer::~ParameterWrapperContainer()
+ {
+ }
+
+
+ Type SAL_CALL ParameterWrapperContainer::getElementType()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return cppu::UnoType<XPropertySet>::get();
+ }
+
+
+ sal_Bool SAL_CALL ParameterWrapperContainer::hasElements()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return !m_aParameters.empty();
+ }
+
+
+ sal_Int32 SAL_CALL ParameterWrapperContainer::getCount()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+ return m_aParameters.size();
+ }
+
+
+ Any SAL_CALL ParameterWrapperContainer::getByIndex( sal_Int32 _nIndex )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ if ( ( _nIndex < 0 ) || ( o3tl::make_unsigned(_nIndex) >= m_aParameters.size() ) )
+ throw IndexOutOfBoundsException();
+
+ return Any( Reference< XPropertySet >( m_aParameters[ _nIndex ] ) );
+ }
+
+
+ Reference< XEnumeration > ParameterWrapperContainer::createEnumeration()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ return new ::comphelper::OEnumerationByIndex( static_cast< XIndexAccess* >( this ) );
+ }
+
+
+ void ParameterWrapperContainer::impl_checkDisposed_throw()
+ {
+ if ( rBHelper.bDisposed )
+ throw DisposedException( OUString(), *this );
+ }
+
+
+ void SAL_CALL ParameterWrapperContainer::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ impl_checkDisposed_throw();
+
+ for (const auto& rxParam : m_aParameters)
+ {
+ rxParam->dispose();
+ }
+
+ Parameters().swap(m_aParameters);
+ }
+
+
+} // namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/predicateinput.cxx b/connectivity/source/commontools/predicateinput.cxx
new file mode 100644
index 000000000..047f9ccc7
--- /dev/null
+++ b/connectivity/source/commontools/predicateinput.cxx
@@ -0,0 +1,421 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/predicateinput.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/i18n/LocaleData.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <osl/diagnose.h>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/PColumn.hxx>
+#include <comphelper/numbers.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <memory>
+#include <string_view>
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::util::XNumberFormatsSupplier;
+ using ::com::sun::star::util::NumberFormatter;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::lang::Locale;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::i18n::LocaleData;
+ using ::com::sun::star::i18n::LocaleDataItem;
+ using ::com::sun::star::uno::Any;
+
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::connectivity;
+
+ using ::connectivity::OSQLParseNode;
+
+
+ static sal_Unicode lcl_getSeparatorChar(
+ std::u16string_view _rSeparator, sal_Unicode _nFallback )
+ {
+ OSL_ENSURE( !_rSeparator.empty(), "::lcl_getSeparatorChar: invalid separator string!" );
+
+ sal_Unicode nReturn( _nFallback );
+ if ( !_rSeparator.empty() )
+ nReturn = _rSeparator[0];
+ return nReturn;
+ }
+
+ bool OPredicateInputController::getSeparatorChars( const Locale& _rLocale, sal_Unicode& _rDecSep, sal_Unicode& _rThdSep ) const
+ {
+ _rDecSep = '.';
+ _rThdSep = ',';
+ try
+ {
+ LocaleDataItem aLocaleData;
+ if ( m_xLocaleData.is() )
+ {
+ aLocaleData = m_xLocaleData->getLocaleItem( _rLocale );
+ _rDecSep = lcl_getSeparatorChar( aLocaleData.decimalSeparator, _rDecSep );
+ _rThdSep = lcl_getSeparatorChar( aLocaleData.thousandSeparator, _rThdSep );
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::getSeparatorChars" );
+ }
+ return false;
+ }
+
+
+ OPredicateInputController::OPredicateInputController(
+ const Reference< XComponentContext >& rxContext, const Reference< XConnection >& _rxConnection, const IParseContext* _pParseContext )
+ : m_xConnection( _rxConnection )
+ ,m_aParser( rxContext, _pParseContext )
+ {
+ try
+ {
+ // create a number formatter / number formats supplier pair
+ OSL_ENSURE( rxContext.is(), "OPredicateInputController::OPredicateInputController: need a service factory!" );
+ if ( rxContext.is() )
+ {
+ m_xFormatter.set( NumberFormatter::create(rxContext), UNO_QUERY_THROW );
+ }
+
+ Reference< XNumberFormatsSupplier > xNumberFormats = ::dbtools::getNumberFormats( m_xConnection, true );
+ if ( !xNumberFormats.is() )
+ ::comphelper::disposeComponent( m_xFormatter );
+ else
+ m_xFormatter->attachNumberFormatsSupplier( xNumberFormats );
+
+ // create the locale data
+ if ( rxContext.is() )
+ {
+ m_xLocaleData = LocaleData::create( rxContext );
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::OPredicateInputController" );
+ }
+ }
+
+
+ std::unique_ptr<OSQLParseNode> OPredicateInputController::implPredicateTree(OUString& _rErrorMessage, const OUString& _rStatement, const Reference< XPropertySet > & _rxField) const
+ {
+ std::unique_ptr<OSQLParseNode> pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, _rStatement, m_xFormatter, _rxField );
+ if ( !pReturn )
+ { // is it a text field ?
+ sal_Int32 nType = DataType::OTHER;
+ _rxField->getPropertyValue("Type") >>= nType;
+
+ if ( ( DataType::CHAR == nType )
+ || ( DataType::VARCHAR == nType )
+ || ( DataType::LONGVARCHAR == nType )
+ || ( DataType::CLOB == nType )
+ )
+ { // yes -> force a quoted text and try again
+ OUString sQuoted( _rStatement );
+ if ( !sQuoted.isEmpty()
+ && ( !sQuoted.startsWith("'")
+ || !sQuoted.endsWith("'")
+ )
+ )
+ {
+ static const char sSingleQuote[] = "'";
+
+ sal_Int32 nIndex = -1;
+ sal_Int32 nTemp = 0;
+ while ( -1 != ( nIndex = sQuoted.indexOf( '\'',nTemp ) ) )
+ {
+ sQuoted = sQuoted.replaceAt( nIndex, 1, u"''" );
+ nTemp = nIndex+2;
+ }
+
+ sQuoted = sSingleQuote + sQuoted + sSingleQuote;
+ }
+ pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, sQuoted, m_xFormatter, _rxField );
+ }
+
+ // one more fallback: for numeric fields, and value strings containing a decimal/thousands separator
+ // problem which is to be solved with this:
+ // * a system locale "german"
+ // * a column formatted with an english number format
+ // => the output is german (as we use the system locale for this), i.e. "3,4"
+ // => the input does not recognize the german text, as predicateTree uses the number format
+ // of the column to determine the main locale - the locale on the context is only a fallback
+ if ( ( DataType::FLOAT == nType )
+ || ( DataType::REAL == nType )
+ || ( DataType::DOUBLE == nType )
+ || ( DataType::NUMERIC == nType )
+ || ( DataType::DECIMAL == nType )
+ )
+ {
+ const IParseContext& rParseContext = m_aParser.getContext();
+ // get the separators for the locale of our parse context
+ sal_Unicode nCtxDecSep;
+ sal_Unicode nCtxThdSep;
+ getSeparatorChars( rParseContext.getPreferredLocale(), nCtxDecSep, nCtxThdSep );
+
+ // determine the locale of the column we're building a predicate string for
+ sal_Unicode nFmtDecSep( nCtxDecSep );
+ sal_Unicode nFmtThdSep( nCtxThdSep );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( _rxField->getPropertySetInfo() );
+ if ( xPSI.is() && xPSI->hasPropertyByName("FormatKey") )
+ {
+ sal_Int32 nFormatKey = 0;
+ _rxField->getPropertyValue("FormatKey") >>= nFormatKey;
+ if ( nFormatKey && m_xFormatter.is() )
+ {
+ Locale aFormatLocale;
+ ::comphelper::getNumberFormatProperty(
+ m_xFormatter,
+ nFormatKey,
+ "Locale"
+ ) >>= aFormatLocale;
+
+ // valid locale
+ if ( !aFormatLocale.Language.isEmpty() )
+ {
+ getSeparatorChars( aFormatLocale, nFmtDecSep, nCtxThdSep );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OPredicateInputController::implPredicateTree: caught an exception while dealing with the formats!" );
+ }
+
+ bool bDecDiffers = ( nCtxDecSep != nFmtDecSep );
+ bool bFmtDiffers = ( nCtxThdSep != nFmtThdSep );
+ if ( bDecDiffers || bFmtDiffers )
+ { // okay, at least one differs
+ // "translate" the value into the "format locale"
+ OUString sTranslated( _rStatement );
+ const sal_Unicode nIntermediate( '_' );
+ sTranslated = sTranslated.replace( nCtxDecSep, nIntermediate );
+ sTranslated = sTranslated.replace( nCtxThdSep, nFmtThdSep );
+ sTranslated = sTranslated.replace( nIntermediate, nFmtDecSep );
+
+ pReturn = const_cast< OSQLParser& >( m_aParser ).predicateTree( _rErrorMessage, sTranslated, m_xFormatter, _rxField );
+ }
+ }
+ }
+ return pReturn;
+ }
+
+
+ bool OPredicateInputController::normalizePredicateString(
+ OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField, OUString* _pErrorMessage ) const
+ {
+ OSL_ENSURE( m_xConnection.is() && m_xFormatter.is() && _rxField.is(),
+ "OPredicateInputController::normalizePredicateString: invalid state or params!" );
+
+ bool bSuccess = false;
+ if ( m_xConnection.is() && m_xFormatter.is() && _rxField.is() )
+ {
+ // parse the string
+ OUString sError;
+ OUString sTransformedText( _rPredicateValue );
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, sTransformedText, _rxField );
+ if ( _pErrorMessage ) *_pErrorMessage = sError;
+
+ if ( pParseNode )
+ {
+ const IParseContext& rParseContext = m_aParser.getContext();
+ sal_Unicode nDecSeparator, nThousandSeparator;
+ getSeparatorChars( rParseContext.getPreferredLocale(), nDecSeparator, nThousandSeparator );
+
+ // translate it back into a string
+ sTransformedText.clear();
+ pParseNode->parseNodeToPredicateStr(
+ sTransformedText, m_xConnection, m_xFormatter, _rxField, OUString(),
+ rParseContext.getPreferredLocale(), OUString(nDecSeparator), &rParseContext
+ );
+ _rPredicateValue = sTransformedText;
+
+ bSuccess = true;
+ }
+ }
+
+ return bSuccess;
+ }
+
+
+ OUString OPredicateInputController::getPredicateValueStr(
+ const OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField ) const
+ {
+ OSL_ENSURE( _rxField.is(), "OPredicateInputController::getPredicateValue: invalid params!" );
+ OUString sReturn;
+ if ( _rxField.is() )
+ {
+ // The following is mostly stolen from the former implementation in the parameter dialog
+ // (dbaccess/source/ui/dlg/paramdialog.cxx). I do not fully understand this...
+
+ OUString sError;
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, _rxField );
+
+ implParseNode(std::move(pParseNode), true) >>= sReturn;
+ }
+
+ return sReturn;
+ }
+
+ OUString OPredicateInputController::getPredicateValueStr(
+ const OUString& _sField, const OUString& _rPredicateValue ) const
+ {
+ OUString sReturn = _rPredicateValue;
+ OUString sError;
+ sal_Int32 nIndex = 0;
+ OUString sField = _sField.getToken(0, '(', nIndex);
+ if(nIndex == -1)
+ sField = _sField;
+ sal_Int32 nType = ::connectivity::OSQLParser::getFunctionReturnType(sField,&m_aParser.getContext());
+ if ( nType == DataType::OTHER || sField.isEmpty() )
+ {
+ // first try the international version
+ OUString sSql = "SELECT * FROM x WHERE " + sField + _rPredicateValue;
+ const_cast< OSQLParser& >( m_aParser ).parseTree( sError, sSql, true );
+ nType = DataType::DOUBLE;
+ }
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ rtl::Reference<parse::OParseColumn> pColumn = new parse::OParseColumn( sField,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
+ OUString(),
+ OUString(),
+ OUString());
+ Reference<XPropertySet> xColumn = pColumn;
+ pColumn->setFunction(true);
+ pColumn->setRealName(sField);
+
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, xColumn );
+ if(pParseNode)
+ {
+ implParseNode(std::move(pParseNode), true) >>= sReturn;
+ }
+ return sReturn;
+ }
+
+ Any OPredicateInputController::getPredicateValue(
+ const OUString& _rPredicateValue, const Reference< XPropertySet > & _rxField ) const
+ {
+ OSL_ENSURE( _rxField.is(), "OPredicateInputController::getPredicateValue: invalid params!" );
+
+ if ( _rxField.is() )
+ {
+ // The following is mostly stolen from the former implementation in the parameter dialog
+ // (dbaccess/source/ui/dlg/paramdialog.cxx). I do not fully understand this...
+
+ OUString sError;
+ std::unique_ptr<OSQLParseNode> pParseNode = implPredicateTree( sError, _rPredicateValue, _rxField );
+
+ return implParseNode(std::move(pParseNode), false);
+ }
+
+ return Any();
+ }
+
+ Any OPredicateInputController::implParseNode(std::unique_ptr<OSQLParseNode> pParseNode, bool _bForStatementUse) const
+ {
+ if ( ! pParseNode )
+ return Any();
+ else
+ {
+ OUString sReturn;
+ OSQLParseNode* pOdbcSpec = pParseNode->getByRule( OSQLParseNode::odbc_fct_spec );
+ if ( pOdbcSpec )
+ {
+ if ( _bForStatementUse )
+ {
+ OSQLParseNode* pFuncSpecParent = pOdbcSpec->getParent();
+ OSL_ENSURE( pFuncSpecParent, "OPredicateInputController::getPredicateValue: an ODBC func spec node without parent?" );
+ if ( pFuncSpecParent )
+ pFuncSpecParent->parseNodeToStr(sReturn, m_xConnection, &m_aParser.getContext());
+ }
+ else
+ {
+ OSQLParseNode* pValueNode = pOdbcSpec->getChild(1);
+ if ( SQLNodeType::String == pValueNode->getNodeType() )
+ sReturn = pValueNode->getTokenValue();
+ else
+ pValueNode->parseNodeToStr(sReturn, m_xConnection, &m_aParser.getContext());
+ }
+ }
+ else
+ {
+ if (pParseNode->getKnownRuleID() == OSQLParseNode::test_for_null )
+ {
+ assert(pParseNode->count() == 2);
+ return Any();
+ }
+ // LEM this seems overly permissive as test...
+ else if (pParseNode->count() >= 3)
+ {
+ OSQLParseNode* pValueNode = pParseNode->getChild(2);
+ assert(pValueNode && "OPredicateInputController::getPredicateValue: invalid node child!");
+ if ( !_bForStatementUse )
+ {
+ if ( SQLNodeType::String == pValueNode->getNodeType() )
+ sReturn = pValueNode->getTokenValue();
+ else
+ pValueNode->parseNodeToStr(
+ sReturn, m_xConnection, &m_aParser.getContext()
+ );
+ }
+ else
+ pValueNode->parseNodeToStr(
+ sReturn, m_xConnection, &m_aParser.getContext()
+ );
+ }
+ else
+ {
+ OSL_FAIL( "OPredicateInputController::getPredicateValue: unknown/invalid structure (noodbc)!" );
+ return Any();
+ }
+ }
+ return Any(sReturn);
+ }
+ }
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/propertyids.cxx b/connectivity/source/commontools/propertyids.cxx
new file mode 100644
index 000000000..90c6beeed
--- /dev/null
+++ b/connectivity/source/commontools/propertyids.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 <propertyids.hxx>
+
+namespace dbtools
+{
+ OPropertyMap::OPropertyMap()
+ {
+ // MSVC complains about ambiguous operator=
+ m_aPropertyMap.insert({
+ {PROPERTY_ID_QUERYTIMEOUT, "QueryTimeOut"},
+ {PROPERTY_ID_MAXFIELDSIZE, "MaxFieldSize"},
+ {PROPERTY_ID_MAXROWS, "MaxRows"},
+ {PROPERTY_ID_CURSORNAME, "CursorName"},
+ {PROPERTY_ID_RESULTSETCONCURRENCY, "ResultSetConcurrency"},
+
+ {PROPERTY_ID_RESULTSETTYPE, "ResultSetType"},
+ {PROPERTY_ID_FETCHDIRECTION, "FetchDirection"},
+ {PROPERTY_ID_FETCHSIZE, "FetchSize"},
+ {PROPERTY_ID_ESCAPEPROCESSING, "EscapeProcessing"},
+ {PROPERTY_ID_USEBOOKMARKS, "UseBookmarks"},
+ // Column
+ {PROPERTY_ID_NAME, "Name"},
+ {PROPERTY_ID_TYPE, "Type"},
+ {PROPERTY_ID_TYPENAME, "TypeName"},
+ {PROPERTY_ID_PRECISION, "Precision"},
+ {PROPERTY_ID_SCALE, "Scale"},
+ {PROPERTY_ID_ISNULLABLE, "IsNullable"},
+ {PROPERTY_ID_ISAUTOINCREMENT, "IsAutoIncrement"},
+ {PROPERTY_ID_ISROWVERSION, "IsRowVersion"},
+ {PROPERTY_ID_DESCRIPTION, "Description"},
+ {PROPERTY_ID_DEFAULTVALUE, "DefaultValue"},
+
+ {PROPERTY_ID_REFERENCEDTABLE, "ReferencedTable"},
+ {PROPERTY_ID_UPDATERULE, "UpdateRule"},
+ {PROPERTY_ID_DELETERULE, "DeleteRule"},
+ {PROPERTY_ID_CATALOG, "Catalog"},
+ {PROPERTY_ID_ISUNIQUE, "IsUnique"},
+ {PROPERTY_ID_ISPRIMARYKEYINDEX, "IsPrimaryKeyIndex"},
+ {PROPERTY_ID_ISCLUSTERED, "IsClustered"},
+ {PROPERTY_ID_ISASCENDING, "IsAscending"},
+ {PROPERTY_ID_SCHEMANAME, "SchemaName"},
+ {PROPERTY_ID_CATALOGNAME, "CatalogName"},
+
+ {PROPERTY_ID_COMMAND, "Command"},
+ {PROPERTY_ID_CHECKOPTION, "CheckOption"},
+ {PROPERTY_ID_PASSWORD, "Password"},
+ {PROPERTY_ID_RELATEDCOLUMN, "RelatedColumn"},
+
+ {PROPERTY_ID_FUNCTION, "Function"},
+ {PROPERTY_ID_AGGREGATEFUNCTION, "AggregateFunction"},
+ {PROPERTY_ID_TABLENAME, "TableName"},
+ {PROPERTY_ID_REALNAME, "RealName"},
+ {PROPERTY_ID_DBASEPRECISIONCHANGED,"DbasePrecisionChanged"},
+ {PROPERTY_ID_ISCURRENCY, "IsCurrency"},
+ {PROPERTY_ID_ISBOOKMARKABLE, "IsBookmarkable"},
+ {PROPERTY_ID_HY010, "HY010"}, // error messages
+ {PROPERTY_ID_DELIMITER, "/"},
+ {PROPERTY_ID_FORMATKEY, "FormatKey"},
+ {PROPERTY_ID_LOCALE, "Locale"},
+ {PROPERTY_ID_AUTOINCREMENTCREATION, "AutoIncrementCreation"},
+ {PROPERTY_ID_PRIVILEGES, "Privileges"},
+ {PROPERTY_ID_HAVINGCLAUSE, "HavingClause"},
+ {PROPERTY_ID_ISSIGNED, "IsSigned"},
+ {PROPERTY_ID_ISSEARCHABLE, "IsSearchable"},
+ {PROPERTY_ID_LABEL, "Label"},
+ {PROPERTY_ID_APPLYFILTER, "ApplyFilter"},
+ {PROPERTY_ID_FILTER, "Filter"},
+ {PROPERTY_ID_MASTERFIELDS, "MasterFields"},
+ {PROPERTY_ID_DETAILFIELDS, "DetailFields"},
+ {PROPERTY_ID_FIELDTYPE, "FieldType"},
+ {PROPERTY_ID_VALUE, "Value"},
+ {PROPERTY_ID_ACTIVE_CONNECTION, "ActiveConnection"},
+ } );
+ }
+
+ const OUString& OPropertyMap::getNameByIndex(sal_Int32 _nIndex) const
+ {
+ std::map<sal_Int32, OUString>::const_iterator aIter = m_aPropertyMap.find(_nIndex);
+ return aIter->second;
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/sqlerror.cxx b/connectivity/source/commontools/sqlerror.cxx
new file mode 100644
index 000000000..28565fb46
--- /dev/null
+++ b/connectivity/source/commontools/sqlerror.cxx
@@ -0,0 +1,295 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <memory>
+#include <connectivity/sqlerror.hxx>
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <unotools/resmgr.hxx>
+#include <osl/diagnose.h>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <string.h>
+
+namespace connectivity
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::sdbc::SQLException;
+ using ::com::sun::star::uno::Type;
+
+ class SQLError_Impl
+ {
+ public:
+ explicit SQLError_Impl();
+
+ // versions of the public SQLError methods which are just delegated to this impl-class
+ static const OUString& getMessagePrefix();
+ OUString getErrorMessage( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const;
+ static ErrorCode getErrorCode( const ErrorCondition _eCondition );
+ void raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ void raiseException( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ void raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const Type& _rExceptionType, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ SQLException getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+
+ private:
+ /// returns the basic error message associated with the given error condition, without any parameter replacements
+ OUString impl_getErrorMessage( ErrorCondition _eCondition ) const;
+
+ /// returns the SQLState associated with the given error condition
+ static OUString
+ impl_getSQLState( ErrorCondition _eCondition );
+
+ /// returns an SQLException describing the given error condition
+ SQLException
+ impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 );
+ private:
+ std::locale m_aResources;
+ };
+
+ SQLError_Impl::SQLError_Impl()
+ : m_aResources(Translate::Create("cnr"))
+ {
+ }
+
+ const OUString& SQLError_Impl::getMessagePrefix()
+ {
+ static const OUString s_sMessagePrefix( "[OOoBase]" );
+ return s_sMessagePrefix;
+ }
+
+ namespace
+ {
+
+ /** substitutes a given placeholder in the given message with the given value
+ */
+ void lcl_substitutePlaceholder(OUString& _rMessage, const char* _pPlaceholder, const std::optional<OUString>& rParamValue)
+ {
+ size_t nPlaceholderLen( strlen( _pPlaceholder ) );
+ sal_Int32 nIndex = _rMessage.indexOfAsciiL( _pPlaceholder, nPlaceholderLen );
+
+ bool bHasPlaceholder = ( nIndex != -1 );
+ bool bWantsPlaceholder = rParamValue.has_value();
+ OSL_ENSURE( bHasPlaceholder == bWantsPlaceholder, "lcl_substitutePlaceholder: placeholder where none is expected, or no placeholder where one is needed!" );
+
+ if ( bHasPlaceholder && bWantsPlaceholder )
+ _rMessage = _rMessage.replaceAt( nIndex, nPlaceholderLen, *rParamValue );
+ }
+
+ TranslateId lcl_getResourceErrorID(const ErrorCondition _eCondition)
+ {
+ switch (_eCondition)
+ {
+ case css::sdb::ErrorCondition::ROW_SET_OPERATION_VETOED:
+ return STR_ROW_SET_OPERATION_VETOED;
+ case css::sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES:
+ return STR_PARSER_CYCLIC_SUB_QUERIES;
+ case css::sdb::ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES:
+ return STR_DB_OBJECT_NAME_WITH_SLASHES;
+ case css::sdb::ErrorCondition::DB_INVALID_SQL_NAME:
+ return STR_DB_INVALID_SQL_NAME;
+ case css::sdb::ErrorCondition::DB_QUERY_NAME_WITH_QUOTES:
+ return STR_DB_QUERY_NAME_WITH_QUOTES;
+ case css::sdb::ErrorCondition::DB_OBJECT_NAME_IS_USED:
+ return STR_DB_OBJECT_NAME_IS_USED;
+ case css::sdb::ErrorCondition::DB_NOT_CONNECTED:
+ return STR_DB_NOT_CONNECTED;
+ case css::sdb::ErrorCondition::AB_ADDRESSBOOK_NOT_FOUND:
+ return STR_AB_ADDRESSBOOK_NOT_FOUND;
+ case css::sdb::ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED:
+ return STR_DATA_CANNOT_SELECT_UNFILTERED;
+ }
+ return {};
+ }
+
+ OUString lcl_getResourceState(const ErrorCondition _eCondition)
+ {
+ switch (_eCondition)
+ {
+ case css::sdb::ErrorCondition::DB_NOT_CONNECTED:
+ return STR_DB_NOT_CONNECTED_STATE;
+ case css::sdb::ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED:
+ return STR_DATA_CANNOT_SELECT_UNFILTERED_STATE;
+ }
+ return OUString();
+ }
+ }
+
+ OUString SQLError_Impl::getErrorMessage( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ OUString sErrorMessage( impl_getErrorMessage( _eCondition ) );
+
+ lcl_substitutePlaceholder( sErrorMessage, "$1$", _rParamValue1 );
+ lcl_substitutePlaceholder( sErrorMessage, "$2$", _rParamValue2 );
+ lcl_substitutePlaceholder( sErrorMessage, "$3$", _rParamValue3 );
+
+ return sErrorMessage;
+ }
+
+
+ ErrorCode SQLError_Impl::getErrorCode( const ErrorCondition _eCondition )
+ {
+ return 0 - ::sal::static_int_cast< ErrorCode, ErrorCondition >( _eCondition );
+ }
+
+
+ void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ raiseTypedException(
+ _eCondition,
+ _rxContext,
+ ::cppu::UnoType< SQLException >::get(),
+ _rParamValue1,
+ _rParamValue2,
+ _rParamValue3
+ );
+ }
+
+
+ void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ raiseTypedException(
+ _eCondition,
+ nullptr,
+ ::cppu::UnoType< SQLException >::get(),
+ _rParamValue1,
+ _rParamValue2,
+ _rParamValue3
+ );
+ }
+
+ void SQLError_Impl::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const Type& _rExceptionType, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ if ( !::cppu::UnoType< SQLException >::get().isAssignableFrom( _rExceptionType ) )
+ throw std::bad_cast();
+
+ // default-construct an exception of the desired type
+ Any aException( nullptr, _rExceptionType );
+
+ // fill it
+ SQLException* pException = static_cast< SQLException* >( aException.pData );
+ *pException = impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+
+ // throw it
+ ::cppu::throwException( aException );
+ }
+
+ SQLException SQLError_Impl::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ return impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+ SQLException SQLError_Impl::impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 )
+ {
+ return SQLException(
+ getErrorMessage( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 ),
+ _rxContext,
+ impl_getSQLState( _eCondition ),
+ getErrorCode( _eCondition ),
+ Any()
+ );
+ }
+
+ OUString SQLError_Impl::impl_getErrorMessage( ErrorCondition _eCondition ) const
+ {
+ OUString sResMessage(Translate::get(lcl_getResourceErrorID(_eCondition), m_aResources));
+ OSL_ENSURE( !sResMessage.isEmpty(), "SQLError_Impl::impl_getErrorMessage: illegal error condition, or invalid resource!" );
+ return getMessagePrefix() + " " + sResMessage;
+ }
+
+ OUString SQLError_Impl::impl_getSQLState( ErrorCondition _eCondition )
+ {
+ static constexpr OUStringLiteral DEFAULT_STATE = u"S1000";
+ OUString sState = lcl_getResourceState(_eCondition);
+ if (sState.isEmpty())
+ sState = DEFAULT_STATE;
+ return sState;
+ }
+
+ SQLError::SQLError()
+ :m_pImpl( std::make_shared<SQLError_Impl>() )
+ {
+ }
+
+
+ SQLError::~SQLError()
+ {
+ }
+
+
+ const OUString& SQLError::getMessagePrefix()
+ {
+ return SQLError_Impl::getMessagePrefix();
+ }
+
+
+ OUString SQLError::getErrorMessage( const ErrorCondition _eCondition ) const
+ {
+ return m_pImpl->getErrorMessage( _eCondition, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ ErrorCode SQLError::getErrorCode( const ErrorCondition _eCondition )
+ {
+ return SQLError_Impl::getErrorCode( _eCondition );
+ }
+
+
+ void SQLError::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ m_pImpl->raiseException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+
+ void SQLError::raiseException( const ErrorCondition _eCondition ) const
+ {
+ m_pImpl->raiseException( _eCondition, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ void SQLError::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const Type& _rExceptionType ) const
+ {
+ m_pImpl->raiseTypedException( _eCondition, _rxContext, _rExceptionType, std::optional<OUString>(), std::optional<OUString>(), std::optional<OUString>() );
+ }
+
+
+ SQLException SQLError::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
+ const std::optional<OUString>& _rParamValue1, const std::optional<OUString>& _rParamValue2, const std::optional<OUString>& _rParamValue3 ) const
+ {
+ return m_pImpl->getSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
+ }
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/statementcomposer.cxx b/connectivity/source/commontools/statementcomposer.cxx
new file mode 100644
index 000000000..27c1c05f1
--- /dev/null
+++ b/connectivity/source/commontools/statementcomposer.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/statementcomposer.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <unotools/sharedunocomponent.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/property.hxx>
+
+
+namespace dbtools
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdb::XSingleSelectQueryComposer;
+ using ::com::sun::star::lang::NullPointerException;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::sdb::XQueriesSupplier;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+ using ::com::sun::star::sdbc::SQLException;
+
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+
+ struct StatementComposer_Data
+ {
+ const Reference< XConnection > xConnection;
+ Reference< XSingleSelectQueryComposer > xComposer;
+ OUString sCommand;
+ OUString sFilter;
+ OUString sHavingClause;
+ OUString sOrder;
+ sal_Int32 nCommandType;
+ bool bEscapeProcessing;
+ bool bComposerDirty;
+ bool bDisposeComposer;
+
+ explicit StatementComposer_Data( const Reference< XConnection >& _rxConnection )
+ :xConnection( _rxConnection )
+ ,nCommandType( CommandType::COMMAND )
+ ,bEscapeProcessing( true )
+ ,bComposerDirty( true )
+ ,bDisposeComposer( true )
+ {
+ if ( !_rxConnection.is() )
+ throw NullPointerException();
+ }
+ };
+
+
+ namespace
+ {
+
+ void lcl_resetComposer( StatementComposer_Data& _rData )
+ {
+ if ( _rData.bDisposeComposer && _rData.xComposer.is() )
+ {
+ try
+ {
+ Reference< XComponent > xComposerComponent( _rData.xComposer, UNO_QUERY_THROW );
+ xComposerComponent->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+ }
+ _rData.xComposer.clear();
+ }
+
+
+ bool lcl_ensureUpToDateComposer_nothrow( StatementComposer_Data& _rData )
+ {
+ if ( !_rData.bComposerDirty )
+ return _rData.xComposer.is();
+ lcl_resetComposer( _rData );
+
+ try
+ {
+ OUString sStatement;
+ switch ( _rData.nCommandType )
+ {
+ case CommandType::COMMAND:
+ if ( _rData.bEscapeProcessing )
+ sStatement = _rData.sCommand;
+ // (in case of no escape processing we assume a not parseable statement)
+ break;
+
+ case CommandType::TABLE:
+ {
+ if ( _rData.sCommand.isEmpty() )
+ break;
+
+ sStatement = "SELECT * FROM ";
+
+ OUString sCatalog, sSchema, sTable;
+ qualifiedNameComponents( _rData.xConnection->getMetaData(), _rData.sCommand, sCatalog, sSchema, sTable, EComposeRule::InDataManipulation );
+
+ sStatement += composeTableNameForSelect( _rData.xConnection, sCatalog, sSchema, sTable );
+ }
+ break;
+
+ case CommandType::QUERY:
+ {
+ // ask the connection for the query
+ Reference< XQueriesSupplier > xSupplyQueries( _rData.xConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xQueries( xSupplyQueries->getQueries(), css::uno::UNO_SET_THROW );
+
+ if ( !xQueries->hasByName( _rData.sCommand ) )
+ break;
+
+ Reference< XPropertySet > xQuery( xQueries->getByName( _rData.sCommand ), UNO_QUERY_THROW );
+
+ // a native query ?
+ bool bQueryEscapeProcessing = false;
+ xQuery->getPropertyValue("EscapeProcessing") >>= bQueryEscapeProcessing;
+ if ( !bQueryEscapeProcessing )
+ break;
+
+ // the command used by the query
+ xQuery->getPropertyValue("Command") >>= sStatement;
+ if ( sStatement.isEmpty() )
+ break;
+
+ // use a composer to build a statement from the query filter/order props
+ Reference< XMultiServiceFactory > xFactory( _rData.xConnection, UNO_QUERY_THROW );
+ ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer;
+ xComposer.set(
+ xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
+ UNO_QUERY_THROW
+ );
+
+ // the "basic" statement
+ xComposer->setElementaryQuery( sStatement );
+
+ // the sort order
+ static const OUStringLiteral sPropOrder( u"Order" );
+ if ( ::comphelper::hasProperty( sPropOrder, xQuery ) )
+ {
+ OUString sOrder;
+ OSL_VERIFY( xQuery->getPropertyValue( sPropOrder ) >>= sOrder );
+ xComposer->setOrder( sOrder );
+ }
+
+ // the filter
+ bool bApplyFilter = true;
+ static const OUStringLiteral sPropApply( u"ApplyFilter" );
+ if ( ::comphelper::hasProperty( sPropApply, xQuery ) )
+ {
+ OSL_VERIFY( xQuery->getPropertyValue( sPropApply ) >>= bApplyFilter );
+ }
+
+ if ( bApplyFilter )
+ {
+ OUString sFilter;
+ OSL_VERIFY( xQuery->getPropertyValue("Filter") >>= sFilter );
+ xComposer->setFilter( sFilter );
+ OSL_VERIFY( xQuery->getPropertyValue("HavingClause") >>= sFilter );
+ xComposer->setHavingClause( sFilter );
+ }
+
+ // the composed statement
+ sStatement = xComposer->getQuery();
+ }
+ break;
+
+ default:
+ OSL_FAIL("lcl_ensureUpToDateComposer_nothrow: no table, no query, no statement - what else ?!");
+ break;
+ }
+
+ if ( !sStatement.isEmpty() )
+ {
+ // create a composer
+ Reference< XMultiServiceFactory > xFactory( _rData.xConnection, UNO_QUERY_THROW );
+ Reference< XSingleSelectQueryComposer > xComposer( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"),
+ UNO_QUERY_THROW );
+ xComposer->setElementaryQuery( sStatement );
+
+ // append sort/filter
+ xComposer->setOrder( _rData.sOrder );
+ xComposer->setFilter( _rData.sFilter );
+ xComposer->setHavingClause( _rData.sHavingClause );
+
+ sStatement = xComposer->getQuery();
+
+ _rData.xComposer = xComposer;
+ _rData.bComposerDirty = false;
+ }
+ }
+ catch( const SQLException& )
+ {
+ // allowed to leave here
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
+ }
+
+ return _rData.xComposer.is();
+ }
+ }
+
+ StatementComposer::StatementComposer( const Reference< XConnection >& _rxConnection,
+ const OUString& _rCommand, const sal_Int32 _nCommandType, const bool _bEscapeProcessing )
+ :m_pData( new StatementComposer_Data( _rxConnection ) )
+ {
+ OSL_PRECOND( _rxConnection.is(), "StatementComposer::StatementComposer: illegal connection!" );
+ m_pData->sCommand = _rCommand;
+ m_pData->nCommandType = _nCommandType;
+ m_pData->bEscapeProcessing = _bEscapeProcessing;
+ }
+
+
+ StatementComposer::~StatementComposer()
+ {
+ lcl_resetComposer( *m_pData );
+ }
+
+
+ void StatementComposer::setDisposeComposer( bool _bDoDispose )
+ {
+ m_pData->bDisposeComposer = _bDoDispose;
+ }
+
+
+ void StatementComposer::setFilter( const OUString& _rFilter )
+ {
+ m_pData->sFilter = _rFilter;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ void StatementComposer::setHavingClause( const OUString& _rHavingClause )
+ {
+ m_pData->sHavingClause = _rHavingClause;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ void StatementComposer::setOrder( const OUString& _rOrder )
+ {
+ m_pData->sOrder = _rOrder;
+ m_pData->bComposerDirty = true;
+ }
+
+
+ Reference< XSingleSelectQueryComposer > const & StatementComposer::getComposer()
+ {
+ lcl_ensureUpToDateComposer_nothrow( *m_pData );
+ return m_pData->xComposer;
+ }
+
+
+ OUString StatementComposer::getQuery()
+ {
+ if ( lcl_ensureUpToDateComposer_nothrow( *m_pData ) )
+ {
+ return m_pData->xComposer->getQuery();
+ }
+
+ return OUString();
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/commontools/warningscontainer.cxx b/connectivity/source/commontools/warningscontainer.cxx
new file mode 100644
index 000000000..ba7825612
--- /dev/null
+++ b/connectivity/source/commontools/warningscontainer.cxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/warningscontainer.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+
+
+namespace dbtools
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+
+ static void lcl_concatWarnings( Any& _rChainLeft, const Any& _rChainRight )
+ {
+ if ( !_rChainLeft.hasValue() )
+ _rChainLeft = _rChainRight;
+ else
+ {
+ // to travel the chain by reference (and not by value), we need the getValue...
+ // looks like a hack, but the meaning of getValue is documented, and it's the only chance for reference-traveling...
+
+ OSL_ENSURE( SQLExceptionInfo( _rChainLeft ).isValid(),
+ "lcl_concatWarnings: invalid warnings chain (this will crash)!" );
+
+ const SQLException* pChainTravel = o3tl::doAccess<SQLException>( _rChainLeft );
+ SQLExceptionIteratorHelper aReferenceIterHelper( *pChainTravel );
+ while ( aReferenceIterHelper.hasMoreElements() )
+ pChainTravel = aReferenceIterHelper.next();
+
+ // reached the end of the chain, and pChainTravel points to the last element
+ const_cast< SQLException* >( pChainTravel )->NextException = _rChainRight;
+ }
+ }
+
+
+ void WarningsContainer::appendWarning(const SQLException& _rWarning)
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rWarning ) );
+ }
+
+
+ void WarningsContainer::appendWarning( const SQLContext& _rContext )
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rContext ));
+ }
+
+
+ void WarningsContainer::appendWarning(const SQLWarning& _rWarning)
+ {
+ lcl_concatWarnings( m_aOwnWarnings, Any( _rWarning ) );
+ }
+
+
+ Any WarningsContainer::getWarnings( ) const
+ {
+ Any aAllWarnings;
+ if ( m_xExternalWarnings.is() )
+ aAllWarnings = m_xExternalWarnings->getWarnings();
+
+ if ( m_aOwnWarnings.hasValue() )
+ lcl_concatWarnings( aAllWarnings, m_aOwnWarnings );
+
+ return aAllWarnings;
+ }
+
+
+ void WarningsContainer::clearWarnings( )
+ {
+ if ( m_xExternalWarnings.is() )
+ m_xExternalWarnings->clearWarnings();
+ m_aOwnWarnings.clear();
+ }
+
+
+ void WarningsContainer::appendWarning( const OUString& _rWarning, const char* _pAsciiSQLState, const Reference< XInterface >& _rxContext )
+ {
+ appendWarning( SQLWarning( _rWarning, _rxContext, OUString::createFromAscii( _pAsciiSQLState ), 0, Any() ) );
+ }
+
+
+} // namespace dbtools
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZConnectionPool.cxx b/connectivity/source/cpool/ZConnectionPool.cxx
new file mode 100644
index 000000000..23e6dda1d
--- /dev/null
+++ b/connectivity/source/cpool/ZConnectionPool.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "ZConnectionPool.hxx"
+#include <com/sun/star/lang/XComponent.hpp>
+#include "ZPooledConnection.hxx"
+#include "ZPoolCollection.hxx"
+#include <connectivity/ConnectionWrapper.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace connectivity;
+
+#include <algorithm>
+
+void SAL_CALL OPoolTimer::onShot()
+{
+ m_pPool->invalidatePooledConnections();
+}
+
+constexpr OUStringLiteral TIMEOUT_NODENAME = u"Timeout";
+
+OConnectionPool::OConnectionPool(const Reference< XDriver >& _xDriver,
+ const Reference< XInterface >& _xDriverNode,
+ const Reference< css::reflection::XProxyFactory >& _rxProxyFactory)
+ :m_xDriver(_xDriver)
+ ,m_xDriverNode(_xDriverNode)
+ ,m_xProxyFactory(_rxProxyFactory)
+ ,m_nTimeOut(10)
+ ,m_nALiveCount(10)
+{
+ OSL_ENSURE(m_xDriverNode.is(),"NO valid Driver node set!");
+ Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+
+ Reference<XPropertySet> xProp(m_xDriverNode,UNO_QUERY);
+ if(xProp.is())
+ xProp->addPropertyChangeListener(TIMEOUT_NODENAME,this);
+
+ OPoolCollection::getNodeValue(TIMEOUT_NODENAME, m_xDriverNode) >>= m_nALiveCount;
+ calculateTimeOuts();
+
+ m_xInvalidator = new OPoolTimer(this,::salhelper::TTimeValue(m_nTimeOut,0));
+ m_xInvalidator->start();
+}
+
+OConnectionPool::~OConnectionPool()
+{
+ clear(false);
+}
+
+namespace {
+
+struct TRemoveEventListenerFunctor
+{
+ OConnectionPool* m_pConnectionPool;
+ bool m_bDispose;
+
+ TRemoveEventListenerFunctor(OConnectionPool* _pConnectionPool, bool _bDispose)
+ : m_pConnectionPool(_pConnectionPool)
+ ,m_bDispose(_bDispose)
+ {
+ OSL_ENSURE(m_pConnectionPool,"No connection pool!");
+ }
+
+ void dispose(const Reference<XInterface>& _xComponent)
+ {
+ Reference< XComponent > xComponent(_xComponent, UNO_QUERY);
+
+ if ( xComponent.is() )
+ {
+ xComponent->removeEventListener(m_pConnectionPool);
+ if ( m_bDispose )
+ xComponent->dispose();
+ }
+ }
+
+ void operator()(const TPooledConnections::value_type& _aValue)
+ {
+ dispose(_aValue);
+ }
+
+ void operator()(const TActiveConnectionMap::value_type& _aValue)
+ {
+ dispose(_aValue.first);
+ }
+};
+
+struct TConnectionPoolFunctor
+{
+ OConnectionPool* m_pConnectionPool;
+
+ explicit TConnectionPoolFunctor(OConnectionPool* _pConnectionPool)
+ : m_pConnectionPool(_pConnectionPool)
+ {
+ OSL_ENSURE(m_pConnectionPool,"No connection pool!");
+ }
+ void operator()(const TConnectionMap::value_type& _aValue)
+ {
+ std::for_each(_aValue.second.aConnections.begin(),_aValue.second.aConnections.end(),TRemoveEventListenerFunctor(m_pConnectionPool,true));
+ }
+};
+
+}
+
+void OConnectionPool::clear(bool _bDispose)
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if(m_xInvalidator->isTicking())
+ m_xInvalidator->stop();
+
+ std::for_each(m_aPool.begin(),m_aPool.end(),TConnectionPoolFunctor(this));
+ m_aPool.clear();
+
+ std::for_each(m_aActiveConnections.begin(),m_aActiveConnections.end(),TRemoveEventListenerFunctor(this,_bDispose));
+ m_aActiveConnections.clear();
+
+ Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->removeEventListener(this);
+ Reference< XPropertySet > xProp(m_xDriverNode, UNO_QUERY);
+ if (xProp.is())
+ xProp->removePropertyChangeListener(TIMEOUT_NODENAME, this);
+
+ m_xDriverNode.clear();
+ m_xDriver.clear();
+}
+
+Reference< XConnection > OConnectionPool::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ Reference<XConnection> xConnection;
+
+ // create a unique id and look for it in our map
+ Sequence< PropertyValue > aInfo(_rInfo);
+ TConnectionMap::key_type nId;
+ OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer);
+ TConnectionMap::iterator aIter = m_aPool.find(nId);
+
+ if ( m_aPool.end() != aIter )
+ xConnection = getPooledConnection(aIter);
+
+ if ( !xConnection.is() )
+ xConnection = createNewConnection(_rURL,_rInfo);
+
+ return xConnection;
+}
+
+void SAL_CALL OConnectionPool::disposing( const css::lang::EventObject& Source )
+{
+ Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
+ if(xConnection.is())
+ {
+ MutexGuard aGuard(m_aMutex);
+ TActiveConnectionMap::iterator aIter = m_aActiveConnections.find(xConnection);
+ OSL_ENSURE(aIter != m_aActiveConnections.end(),"OConnectionPool::disposing: Connection wasn't in pool");
+ if(aIter != m_aActiveConnections.end())
+ { // move the pooled connection back to the pool
+ aIter->second.aPos->second.nALiveCount = m_nALiveCount;
+ aIter->second.aPos->second.aConnections.push_back(aIter->second.xPooledConnection);
+ m_aActiveConnections.erase(aIter);
+ }
+ }
+ else
+ {
+ m_xDriverNode.clear();
+ }
+}
+
+Reference< XConnection> OConnectionPool::createNewConnection(const OUString& _rURL,const Sequence< PropertyValue >& _rInfo)
+{
+ // create new pooled connection
+ Reference< XPooledConnection > xPooledConnection = new ::connectivity::OPooledConnection(m_xDriver->connect(_rURL,_rInfo),m_xProxyFactory);
+ // get the new connection from the pooled connection
+ Reference<XConnection> xConnection = xPooledConnection->getConnection();
+ if(xConnection.is())
+ {
+ // add our own as dispose listener to know when we should put the connection back to the pool
+ Reference< XComponent > xComponent(xConnection, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+
+ // save some information to find the right pool later on
+ Sequence< PropertyValue > aInfo(_rInfo);
+ TConnectionMap::key_type nId;
+ OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer);
+ TConnectionPool aPack;
+
+ // insert the new connection and struct into the active connection map
+ aPack.nALiveCount = m_nALiveCount;
+ TActiveConnectionInfo aActiveInfo;
+ aActiveInfo.aPos = m_aPool.emplace(nId,aPack).first;
+ aActiveInfo.xPooledConnection = xPooledConnection;
+ m_aActiveConnections.emplace(xConnection,aActiveInfo);
+
+ if(m_xInvalidator->isExpired())
+ m_xInvalidator->start();
+ }
+
+ return xConnection;
+}
+
+void OConnectionPool::invalidatePooledConnections()
+{
+ MutexGuard aGuard(m_aMutex);
+ TConnectionMap::iterator aIter = m_aPool.begin();
+ for (; aIter != m_aPool.end(); )
+ {
+ if(!(--(aIter->second.nALiveCount))) // connections are invalid
+ {
+ std::for_each(aIter->second.aConnections.begin(),aIter->second.aConnections.end(),TRemoveEventListenerFunctor(this,true));
+
+ aIter->second.aConnections.clear();
+
+ // look if the iterator aIter is still present in the active connection map
+ bool isPresent = std::any_of(m_aActiveConnections.begin(), m_aActiveConnections.end(),
+ [&aIter](const TActiveConnectionMap::value_type& rEntry) { return rEntry.second.aPos == aIter; });
+ if(!isPresent)
+ {// he isn't so we can delete him
+ aIter = m_aPool.erase(aIter);
+ }
+ else
+ ++aIter;
+ }
+ else
+ ++aIter;
+ }
+ if(!m_aPool.empty())
+ m_xInvalidator->start();
+}
+
+Reference< XConnection> OConnectionPool::getPooledConnection(TConnectionMap::iterator const & _rIter)
+{
+ Reference<XConnection> xConnection;
+
+ if(!_rIter->second.aConnections.empty())
+ {
+ Reference< XPooledConnection > xPooledConnection = _rIter->second.aConnections.back();
+ _rIter->second.aConnections.pop_back();
+
+ OSL_ENSURE(xPooledConnection.is(),"Can not be null here!");
+ xConnection = xPooledConnection->getConnection();
+ Reference< XComponent > xComponent(xConnection, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(this);
+
+ TActiveConnectionInfo aActiveInfo;
+ aActiveInfo.aPos = _rIter;
+ aActiveInfo.xPooledConnection = xPooledConnection;
+ m_aActiveConnections[xConnection] = aActiveInfo;
+ }
+ return xConnection;
+}
+
+void SAL_CALL OConnectionPool::propertyChange( const PropertyChangeEvent& evt )
+{
+ if(TIMEOUT_NODENAME == evt.PropertyName)
+ {
+ OPoolCollection::getNodeValue(TIMEOUT_NODENAME, m_xDriverNode) >>= m_nALiveCount;
+ calculateTimeOuts();
+ }
+}
+
+void OConnectionPool::calculateTimeOuts()
+{
+ sal_Int32 nTimeOutCorrection = 10;
+ if(m_nALiveCount < 100)
+ nTimeOutCorrection = 20;
+
+ m_nTimeOut = m_nALiveCount / nTimeOutCorrection;
+ m_nALiveCount = m_nALiveCount / m_nTimeOut;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZConnectionPool.hxx b/connectivity/source/cpool/ZConnectionPool.hxx
new file mode 100644
index 000000000..e83d22849
--- /dev/null
+++ b/connectivity/source/cpool/ZConnectionPool.hxx
@@ -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 .
+ */
+#pragma once
+#include <sal/config.h>
+
+#include <map>
+#include <vector>
+
+#include <com/sun/star/sdbc/XPooledConnection.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <osl/mutex.hxx>
+#include <salhelper/timer.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/digest.h>
+
+namespace connectivity
+{
+ class OConnectionPool;
+
+ /// OPoolTimer - Invalidates the connection pool
+
+ class OPoolTimer : public ::salhelper::Timer
+ {
+ OConnectionPool* m_pPool;
+ public:
+ OPoolTimer(OConnectionPool* _pPool,const ::salhelper::TTimeValue& Time)
+ : ::salhelper::Timer(Time)
+ ,m_pPool(_pPool)
+ {}
+ protected:
+ virtual void SAL_CALL onShot() override;
+ };
+
+
+ // OConnectionPool - the one-instance service for PooledConnections
+ // manages the active connections and the connections in the pool
+
+ // typedef for the internal structure
+ typedef std::vector< css::uno::Reference< css::sdbc::XPooledConnection> > TPooledConnections;
+
+ // contains the currently pooled connections
+ struct TConnectionPool
+ {
+ TPooledConnections aConnections;
+ sal_Int32 nALiveCount; // will be decremented every time a time says to, when will reach zero the pool will be deleted
+ };
+
+ struct TDigestHolder
+ {
+ sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
+ TDigestHolder()
+ {
+ m_pBuffer[0] = 0;
+ }
+
+ };
+
+ // typedef TDigestHolder
+
+ struct TDigestLess
+ {
+ bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
+ {
+ sal_uInt32 i;
+ for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
+ ;
+ return i < RTL_DIGEST_LENGTH_SHA1;
+ }
+ };
+
+ typedef std::map< TDigestHolder,TConnectionPool,TDigestLess> TConnectionMap;
+
+ // contains additional information about an activeconnection which is needed to put it back to the pool
+ struct TActiveConnectionInfo
+ {
+ TConnectionMap::iterator aPos;
+ css::uno::Reference< css::sdbc::XPooledConnection> xPooledConnection;
+ };
+
+ typedef std::map< css::uno::Reference< css::sdbc::XConnection>,
+ TActiveConnectionInfo> TActiveConnectionMap;
+
+ class OConnectionPool : public ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener>
+ {
+ TConnectionMap m_aPool; // the pooled connections
+ TActiveConnectionMap m_aActiveConnections; // the currently active connections
+
+ ::osl::Mutex m_aMutex;
+ ::rtl::Reference<OPoolTimer> m_xInvalidator; // invalidates the conntection pool when shot
+
+ css::uno::Reference< css::sdbc::XDriver > m_xDriver; // the one and only driver for this connectionpool
+ css::uno::Reference< css::uno::XInterface > m_xDriverNode; // config node entry
+ css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory;
+ sal_Int32 m_nTimeOut;
+ sal_Int32 m_nALiveCount;
+
+ private:
+ css::uno::Reference< css::sdbc::XConnection> createNewConnection(const OUString& _rURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rInfo);
+ css::uno::Reference< css::sdbc::XConnection> getPooledConnection(TConnectionMap::iterator const & _rIter);
+ // calculate the timeout and the corresponding ALiveCount
+ void calculateTimeOuts();
+
+ protected:
+ // the dtor will be called from the last instance (last release call)
+ virtual ~OConnectionPool() override;
+ public:
+ OConnectionPool(const css::uno::Reference< css::sdbc::XDriver >& _xDriver,
+ const css::uno::Reference< css::uno::XInterface >& _xDriverNode,
+ const css::uno::Reference< css::reflection::XProxyFactory >& _rxProxyFactory);
+
+ // delete all refs
+ void clear(bool _bDispose);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XConnection > getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info );
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ void invalidatePooledConnections();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZConnectionWrapper.cxx b/connectivity/source/cpool/ZConnectionWrapper.cxx
new file mode 100644
index 000000000..dd4519859
--- /dev/null
+++ b/connectivity/source/cpool/ZConnectionWrapper.cxx
@@ -0,0 +1,241 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ZConnectionWrapper.hxx"
+
+using namespace connectivity;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+
+OConnectionWeakWrapper::OConnectionWeakWrapper(Reference< XAggregation >& _xConnection)
+ : OConnectionWeakWrapper_BASE(m_aMutex)
+{
+ setDelegation(_xConnection,m_refCount);
+ OSL_ENSURE(m_xConnection.is(),"OConnectionWeakWrapper: Connection must be valid!");
+}
+
+OConnectionWeakWrapper::~OConnectionWeakWrapper()
+{
+ if ( !OConnectionWeakWrapper_BASE::rBHelper.bDisposed )
+ {
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(OConnectionWeakWrapper, "com.sun.star.sdbc.drivers.OConnectionWeakWrapper", "com.sun.star.sdbc.Connection")
+
+
+Reference< XStatement > SAL_CALL OConnectionWeakWrapper::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->createStatement();
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnectionWeakWrapper::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->prepareStatement(sql);
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnectionWeakWrapper::prepareCall( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->prepareCall(sql);
+}
+
+OUString SAL_CALL OConnectionWeakWrapper::nativeSQL( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->nativeSQL(sql);
+}
+
+void SAL_CALL OConnectionWeakWrapper::setAutoCommit( sal_Bool autoCommit )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+ m_xConnection->setAutoCommit(autoCommit);
+}
+
+sal_Bool SAL_CALL OConnectionWeakWrapper::getAutoCommit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getAutoCommit();
+}
+
+void SAL_CALL OConnectionWeakWrapper::commit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->commit();
+}
+
+void SAL_CALL OConnectionWeakWrapper::rollback( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->rollback();
+}
+
+sal_Bool SAL_CALL OConnectionWeakWrapper::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return m_xConnection->isClosed();
+}
+
+Reference< XDatabaseMetaData > SAL_CALL OConnectionWeakWrapper::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getMetaData();
+}
+
+void SAL_CALL OConnectionWeakWrapper::setReadOnly( sal_Bool readOnly )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->setReadOnly(readOnly);
+}
+
+sal_Bool SAL_CALL OConnectionWeakWrapper::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->isReadOnly();
+}
+
+void SAL_CALL OConnectionWeakWrapper::setCatalog( const OUString& catalog )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->setCatalog(catalog);
+}
+
+OUString SAL_CALL OConnectionWeakWrapper::getCatalog( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getCatalog();
+}
+
+void SAL_CALL OConnectionWeakWrapper::setTransactionIsolation( sal_Int32 level )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->setTransactionIsolation(level);
+}
+
+sal_Int32 SAL_CALL OConnectionWeakWrapper::getTransactionIsolation( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getTransactionIsolation();
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OConnectionWeakWrapper::getTypeMap( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ return m_xConnection->getTypeMap();
+}
+
+void SAL_CALL OConnectionWeakWrapper::setTypeMap( const Reference< css::container::XNameAccess >& typeMap )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+
+ m_xConnection->setTypeMap(typeMap);
+}
+
+// XCloseable
+void SAL_CALL OConnectionWeakWrapper::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+void OConnectionWeakWrapper::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OConnectionWeakWrapper_BASE::disposing();
+ OConnectionWrapper::disposing();
+}
+
+// css::lang::XUnoTunnel
+IMPLEMENT_FORWARD_REFCOUNT( OConnectionWeakWrapper, OConnectionWeakWrapper_BASE )
+
+css::uno::Any SAL_CALL OConnectionWeakWrapper::queryInterface( const css::uno::Type& _rType )
+{
+ css::uno::Any aReturn = OConnectionWeakWrapper_BASE::queryInterface( _rType );
+ if ( !aReturn.hasValue() )
+ aReturn = OConnectionWrapper::queryInterface( _rType );
+ return aReturn;
+}
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2(OConnectionWeakWrapper,OConnectionWeakWrapper_BASE,OConnectionWrapper)
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZConnectionWrapper.hxx b/connectivity/source/cpool/ZConnectionWrapper.hxx
new file mode 100644
index 000000000..e4b945fa9
--- /dev/null
+++ b/connectivity/source/cpool/ZConnectionWrapper.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/uno3.hxx>
+#include <connectivity/ConnectionWrapper.hxx>
+
+namespace connectivity
+{
+
+
+ // OConnectionWeakWrapper - wraps all methods to the real connection from the driver
+ // but when disposed it doesn't dispose the real connection
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection > OConnectionWeakWrapper_BASE;
+
+ class OConnectionWeakWrapper : public ::cppu::BaseMutex
+ , public OConnectionWeakWrapper_BASE
+ , public OConnectionWrapper
+ {
+ protected:
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ virtual ~OConnectionWeakWrapper() override;
+ public:
+ explicit OConnectionWeakWrapper(css::uno::Reference< css::uno::XAggregation >& _xConnection);
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ DECLARE_XTYPEPROVIDER()
+ DECLARE_XINTERFACE( )
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZDriverWrapper.cxx b/connectivity/source/cpool/ZDriverWrapper.cxx
new file mode 100644
index 000000000..811f103bc
--- /dev/null
+++ b/connectivity/source/cpool/ZDriverWrapper.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ZDriverWrapper.hxx"
+#include "ZConnectionPool.hxx"
+#include <osl/diagnose.h>
+
+
+namespace connectivity
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::beans;
+
+ ODriverWrapper::ODriverWrapper( Reference< XAggregation >& _rxAggregateDriver, OConnectionPool* _pPool )
+ :m_pConnectionPool(_pPool)
+ {
+ OSL_ENSURE(_rxAggregateDriver.is(), "ODriverWrapper::ODriverWrapper: invalid aggregate!");
+ OSL_ENSURE(m_pConnectionPool.is(), "ODriverWrapper::ODriverWrapper: invalid connection pool!");
+
+ osl_atomic_increment( &m_refCount );
+ if (_rxAggregateDriver.is())
+ {
+ // transfer the (one and only) real ref to the aggregate to our member
+ m_xDriverAggregate = _rxAggregateDriver;
+ _rxAggregateDriver = nullptr;
+
+ // a second "real" reference
+ m_xDriver.set(m_xDriverAggregate, UNO_QUERY);
+ OSL_ENSURE(m_xDriver.is(), "ODriverWrapper::ODriverWrapper: invalid aggregate (no XDriver)!");
+
+ // set ourself as delegator
+ m_xDriverAggregate->setDelegator( static_cast< XWeak* >( this ) );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ ODriverWrapper::~ODriverWrapper()
+ {
+ if (m_xDriverAggregate.is())
+ m_xDriverAggregate->setDelegator(nullptr);
+ }
+
+
+ Any SAL_CALL ODriverWrapper::queryInterface( const Type& _rType )
+ {
+ Any aReturn = ODriverWrapper_BASE::queryInterface(_rType);
+ return aReturn.hasValue() ? aReturn : (m_xDriverAggregate.is() ? m_xDriverAggregate->queryAggregation(_rType) : aReturn);
+ }
+
+
+ Reference< XConnection > SAL_CALL ODriverWrapper::connect( const OUString& url, const Sequence< PropertyValue >& info )
+ {
+ Reference< XConnection > xConnection;
+ if (m_pConnectionPool.is())
+ // route this through the pool
+ xConnection = m_pConnectionPool->getConnectionWithInfo( url, info );
+ else if (m_xDriver.is())
+ xConnection = m_xDriver->connect( url, info );
+
+ return xConnection;
+ }
+
+
+ sal_Bool SAL_CALL ODriverWrapper::acceptsURL( const OUString& url )
+ {
+ return m_xDriver.is() && m_xDriver->acceptsURL(url);
+ }
+
+
+ Sequence< DriverPropertyInfo > SAL_CALL ODriverWrapper::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& info )
+ {
+ Sequence< DriverPropertyInfo > aInfo;
+ if (m_xDriver.is())
+ aInfo = m_xDriver->getPropertyInfo(url, info);
+ return aInfo;
+ }
+
+
+ sal_Int32 SAL_CALL ODriverWrapper::getMajorVersion( )
+ {
+ return m_xDriver.is() ? m_xDriver->getMajorVersion() : 0;
+ }
+
+
+ sal_Int32 SAL_CALL ODriverWrapper::getMinorVersion( )
+ {
+ return m_xDriver.is() ? m_xDriver->getMinorVersion() : 0;
+ }
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZDriverWrapper.hxx b/connectivity/source/cpool/ZDriverWrapper.hxx
new file mode 100644
index 000000000..b08cfc3ad
--- /dev/null
+++ b/connectivity/source/cpool/ZDriverWrapper.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+#include <com/sun/star/uno/XAggregation.hpp>
+
+
+namespace connectivity
+{
+
+
+ class OConnectionPool;
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XDriver > ODriverWrapper_BASE;
+
+ class ODriverWrapper final : public ODriverWrapper_BASE
+ {
+ css::uno::Reference< css::uno::XAggregation >
+ m_xDriverAggregate;
+ css::uno::Reference< css::sdbc::XDriver >
+ m_xDriver;
+ rtl::Reference<OConnectionPool>
+ m_pConnectionPool;
+
+ public:
+ /** creates a new wrapper for a driver
+ @param _rxAggregateDriver
+ the driver to aggregate. The object will be reset to <NULL/> when returning from the ctor.
+ */
+ ODriverWrapper(
+ css::uno::Reference< css::uno::XAggregation >& _rxAggregateDriver,
+ OConnectionPool* _pPool
+ );
+
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+
+ private:
+ /// dtor
+ virtual ~ODriverWrapper() override;
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+ };
+
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZPoolCollection.cxx b/connectivity/source/cpool/ZPoolCollection.cxx
new file mode 100644
index 000000000..ba17e6fea
--- /dev/null
+++ b/connectivity/source/cpool/ZPoolCollection.cxx
@@ -0,0 +1,468 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ZPoolCollection.hxx"
+#include "ZDriverWrapper.hxx"
+#include "ZConnectionPool.hxx"
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::reflection;
+using namespace ::osl;
+using namespace connectivity;
+
+
+static OUString getConnectionPoolNodeName()
+{
+ return "org.openoffice.Office.DataAccess/ConnectionPool";
+}
+
+static OUString getEnablePoolingNodeName()
+{
+ return "EnablePooling";
+}
+
+static OUString getDriverNameNodeName()
+{
+ return "DriverName";
+}
+
+static OUString getDriverSettingsNodeName()
+{
+ return "DriverSettings";
+}
+
+static OUString getEnableNodeName()
+{
+ return "Enable";
+}
+
+
+OPoolCollection::OPoolCollection(const Reference< XComponentContext >& _rxContext)
+ :m_xContext(_rxContext)
+{
+ // bootstrap all objects supporting the .sdb.Driver service
+ m_xManager = DriverManager::create( m_xContext );
+
+ m_xProxyFactory = ProxyFactory::create( m_xContext );
+
+ Reference<XPropertySet> xProp(getConfigPoolRoot(),UNO_QUERY);
+ if ( xProp.is() )
+ xProp->addPropertyChangeListener(getEnablePoolingNodeName(),this);
+ // attach as desktop listener to know when we have to release our pools
+ osl_atomic_increment( &m_refCount );
+ {
+
+ m_xDesktop = css::frame::Desktop::create( m_xContext );
+ m_xDesktop->addTerminateListener(this);
+
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+OPoolCollection::~OPoolCollection()
+{
+ clearConnectionPools(false);
+}
+
+Reference< XConnection > SAL_CALL OPoolCollection::getConnection( const OUString& _rURL )
+{
+ return getConnectionWithInfo(_rURL,Sequence< PropertyValue >());
+}
+
+Reference< XConnection > SAL_CALL OPoolCollection::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo )
+{
+ MutexGuard aGuard(m_aMutex);
+ Reference< XConnection > xConnection;
+ Reference< XDriver > xDriver;
+ Reference< XInterface > xDriverNode;
+ OUString sImplName;
+ if(isPoolingEnabledByUrl(_rURL,xDriver,sImplName,xDriverNode) && xDriver.is())
+ {
+ OConnectionPool* pConnectionPool = getConnectionPool(sImplName,xDriver,xDriverNode);
+
+ if(pConnectionPool)
+ xConnection = pConnectionPool->getConnectionWithInfo(_rURL,_rInfo);
+ }
+ else if(xDriver.is())
+ xConnection = xDriver->connect(_rURL,_rInfo);
+
+ return xConnection;
+}
+
+void SAL_CALL OPoolCollection::setLoginTimeout( sal_Int32 seconds )
+{
+ MutexGuard aGuard(m_aMutex);
+ m_xManager->setLoginTimeout(seconds);
+}
+
+sal_Int32 SAL_CALL OPoolCollection::getLoginTimeout( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_xManager->getLoginTimeout();
+}
+
+OUString SAL_CALL OPoolCollection::getImplementationName( )
+{
+ return "com.sun.star.sdbc.OConnectionPool";
+}
+
+sal_Bool SAL_CALL OPoolCollection::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Sequence< OUString > SAL_CALL OPoolCollection::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.ConnectionPool" };
+}
+
+Reference< XDriver > SAL_CALL OPoolCollection::getDriverByURL( const OUString& _rURL )
+{
+ // returns the original driver when no connection pooling is enabled else it returns the proxy
+ MutexGuard aGuard(m_aMutex);
+
+ Reference< XDriver > xDriver;
+ Reference< XInterface > xDriverNode;
+ OUString sImplName;
+ if(isPoolingEnabledByUrl(_rURL,xDriver,sImplName,xDriverNode))
+ {
+ Reference< XDriver > xExistentProxy;
+ // look if we already have a proxy for this driver
+ for (const auto& [rxDriver, rxDriverRef] : m_aDriverProxies)
+ {
+ // hold the proxy alive as long as we're in this loop round
+ xExistentProxy = rxDriverRef;
+
+ if (xExistentProxy.is() && (rxDriver.get() == xDriver.get()))
+ // already created a proxy for this
+ break;
+ }
+ if (xExistentProxy.is())
+ {
+ xDriver = xExistentProxy;
+ }
+ else
+ { // create a new proxy for the driver
+ // this allows us to control the connections created by it
+ Reference< XAggregation > xDriverProxy = m_xProxyFactory->createProxy(xDriver);
+ OSL_ENSURE(xDriverProxy.is(), "OConnectionPool::getDriverByURL: invalid proxy returned by the proxy factory!");
+
+ OConnectionPool* pConnectionPool = getConnectionPool(sImplName,xDriver,xDriverNode);
+ xDriver = new ODriverWrapper(xDriverProxy, pConnectionPool);
+ }
+ }
+
+ return xDriver;
+}
+
+bool OPoolCollection::isDriverPoolingEnabled(std::u16string_view _sDriverImplName,
+ Reference< XInterface >& _rxDriverNode)
+{
+ bool bEnabled = false;
+ Reference<XInterface> xConnectionPoolRoot = getConfigPoolRoot();
+ // then look for which of them settings are stored in the configuration
+ Reference< XNameAccess > xDirectAccess(openNode(getDriverSettingsNodeName(),xConnectionPoolRoot),UNO_QUERY);
+
+ if(xDirectAccess.is())
+ {
+ Sequence< OUString > aDriverKeys = xDirectAccess->getElementNames();
+ const OUString* pDriverKeys = aDriverKeys.getConstArray();
+ const OUString* pDriverKeysEnd = pDriverKeys + aDriverKeys.getLength();
+ for (;pDriverKeys != pDriverKeysEnd; ++pDriverKeys)
+ {
+ // the name of the driver in this round
+ if(_sDriverImplName == *pDriverKeys)
+ {
+ _rxDriverNode = openNode(*pDriverKeys,xDirectAccess);
+ if(_rxDriverNode.is())
+ getNodeValue(getEnableNodeName(),_rxDriverNode) >>= bEnabled;
+ break;
+ }
+ }
+ }
+ return bEnabled;
+}
+
+bool OPoolCollection::isPoolingEnabled()
+{
+ // the config node where all pooling relevant info are stored under
+ Reference<XInterface> xConnectionPoolRoot = getConfigPoolRoot();
+
+ // the global "enabled" flag
+ bool bEnabled = false;
+ if(xConnectionPoolRoot.is())
+ getNodeValue(getEnablePoolingNodeName(),xConnectionPoolRoot) >>= bEnabled;
+ return bEnabled;
+}
+
+Reference<XInterface> const & OPoolCollection::getConfigPoolRoot()
+{
+ if(!m_xConfigNode.is())
+ m_xConfigNode = createWithProvider(
+ css::configuration::theDefaultProvider::get(m_xContext),
+ getConnectionPoolNodeName());
+ return m_xConfigNode;
+}
+
+bool OPoolCollection::isPoolingEnabledByUrl(const OUString& _sUrl,
+ Reference< XDriver >& _rxDriver,
+ OUString& _rsImplName,
+ Reference< XInterface >& _rxDriverNode)
+{
+ bool bEnabled = false;
+ _rxDriver = m_xManager->getDriverByURL(_sUrl);
+ if (_rxDriver.is() && isPoolingEnabled())
+ {
+ Reference< XServiceInfo > xServiceInfo(_rxDriver,UNO_QUERY);
+ OSL_ENSURE(xServiceInfo.is(),"Each driver should have a XServiceInfo interface!");
+
+ if(xServiceInfo.is())
+ {
+ // look for the implementation name of the driver
+ _rsImplName = xServiceInfo->getImplementationName();
+ bEnabled = isDriverPoolingEnabled(_rsImplName,_rxDriverNode);
+ }
+ }
+ return bEnabled;
+}
+
+void OPoolCollection::clearConnectionPools(bool _bDispose)
+{
+ for(auto& rEntry : m_aPools)
+ {
+ rEntry.second->clear(_bDispose);
+ }
+ m_aPools.clear();
+}
+
+OConnectionPool* OPoolCollection::getConnectionPool(const OUString& _sImplName,
+ const Reference< XDriver >& _xDriver,
+ const Reference< XInterface >& _xDriverNode)
+{
+ OConnectionPool *pRet = nullptr;
+ OConnectionPools::const_iterator aFind = m_aPools.find(_sImplName);
+ if (aFind != m_aPools.end())
+ pRet = aFind->second.get();
+ else if (_xDriver.is() && _xDriverNode.is())
+ {
+ Reference<XPropertySet> xProp(_xDriverNode,UNO_QUERY);
+ if(xProp.is())
+ xProp->addPropertyChangeListener(getEnableNodeName(),this);
+ rtl::Reference<OConnectionPool> pConnectionPool = new OConnectionPool(_xDriver,_xDriverNode,m_xProxyFactory);
+ m_aPools.emplace(_sImplName,pConnectionPool);
+ pRet = pConnectionPool.get();
+ }
+
+ OSL_ENSURE(pRet, "Could not query DriverManager from ConnectionPool!");
+
+ return pRet;
+}
+
+Reference< XInterface > OPoolCollection::createWithProvider(const Reference< XMultiServiceFactory >& _rxConfProvider,
+ const OUString& _rPath)
+{
+ OSL_ASSERT(_rxConfProvider.is());
+ Sequence< Any > args{ Any(NamedValue( "nodepath", Any(_rPath))) };
+ Reference< XInterface > xInterface(
+ _rxConfProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ args));
+ OSL_ENSURE(
+ xInterface.is(),
+ "::createWithProvider: could not create the node access!");
+ return xInterface;
+}
+
+Reference<XInterface> OPoolCollection::openNode(const OUString& _rPath,const Reference<XInterface>& _xTreeNode) noexcept
+{
+ Reference< XHierarchicalNameAccess > xHierarchyAccess(_xTreeNode, UNO_QUERY);
+ Reference< XNameAccess > xDirectAccess(_xTreeNode, UNO_QUERY);
+ Reference< XInterface > xNode;
+
+ try
+ {
+ if (xDirectAccess.is() && xDirectAccess->hasByName(_rPath))
+ {
+ xNode.set(xDirectAccess->getByName(_rPath), css::uno::UNO_QUERY);
+ SAL_WARN_IF(
+ !xNode.is(), "connectivity.cpool",
+ "OConfigurationNode::openNode: could not open the node!");
+ }
+ else if (xHierarchyAccess.is())
+ {
+ xNode.set(
+ xHierarchyAccess->getByHierarchicalName(_rPath),
+ css::uno::UNO_QUERY);
+ SAL_WARN_IF(
+ !xNode.is(), "connectivity.cpool",
+ "OConfigurationNode::openNode: could not open the node!");
+ }
+
+ }
+ catch(const NoSuchElementException&)
+ {
+ SAL_WARN("connectivity.cpool", "::openNode: there is no element named " <<
+ _rPath << "!");
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.cpool", "OConfigurationNode::openNode: caught an exception while retrieving the node");
+ }
+ return xNode;
+}
+
+Any OPoolCollection::getNodeValue(const OUString& _rPath,const Reference<XInterface>& _xTreeNode) noexcept
+{
+ Reference< XHierarchicalNameAccess > xHierarchyAccess(_xTreeNode, UNO_QUERY);
+ Reference< XNameAccess > xDirectAccess(_xTreeNode, UNO_QUERY);
+ Any aReturn;
+ try
+ {
+ if (xDirectAccess.is() && xDirectAccess->hasByName(_rPath) )
+ {
+ aReturn = xDirectAccess->getByName(_rPath);
+ }
+ else if (xHierarchyAccess.is())
+ {
+ aReturn = xHierarchyAccess->getByHierarchicalName(_rPath);
+ }
+ }
+ catch(const NoSuchElementException&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.cpool", "" );
+ }
+ return aReturn;
+}
+
+void SAL_CALL OPoolCollection::queryTermination( const EventObject& /*Event*/ )
+{
+}
+
+void SAL_CALL OPoolCollection::notifyTermination( const EventObject& /*Event*/ )
+{
+ clearDesktop();
+}
+
+void SAL_CALL OPoolCollection::disposing( const EventObject& Source )
+{
+ MutexGuard aGuard(m_aMutex);
+ if ( m_xDesktop == Source.Source )
+ {
+ clearDesktop();
+ }
+ else
+ {
+ try
+ {
+ Reference<XPropertySet> xProp(Source.Source,UNO_QUERY);
+ if(Source.Source == m_xConfigNode)
+ {
+ if ( xProp.is() )
+ xProp->removePropertyChangeListener(getEnablePoolingNodeName(),this);
+ m_xConfigNode.clear();
+ }
+ else if ( xProp.is() )
+ xProp->removePropertyChangeListener(getEnableNodeName(),this);
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("connectivity.cpool", "");
+ }
+ }
+}
+
+void SAL_CALL OPoolCollection::propertyChange( const css::beans::PropertyChangeEvent& evt )
+{
+ MutexGuard aGuard(m_aMutex);
+ if(evt.Source == m_xConfigNode)
+ {
+ bool bEnabled = true;
+ evt.NewValue >>= bEnabled;
+ if(!bEnabled )
+ {
+ m_aDriverProxies.clear();
+ m_aDriverProxies = MapDriver2DriverRef();
+ clearConnectionPools(false);
+ }
+ }
+ else if(evt.Source.is())
+ {
+ bool bEnabled = true;
+ evt.NewValue >>= bEnabled;
+ if(!bEnabled)
+ {
+ OUString sThisDriverName;
+ getNodeValue(getDriverNameNodeName(),evt.Source) >>= sThisDriverName;
+ // 1st release the driver
+ // look if we already have a proxy for this driver
+ MapDriver2DriverRef::iterator aLookup = m_aDriverProxies.begin();
+ while( aLookup != m_aDriverProxies.end())
+ {
+ MapDriver2DriverRef::iterator aFind = aLookup;
+ Reference<XServiceInfo> xInfo(aLookup->first,UNO_QUERY);
+ ++aLookup;
+ if(xInfo.is() && xInfo->getImplementationName() == sThisDriverName)
+ m_aDriverProxies.erase(aFind);
+ }
+
+ // 2nd clear the connectionpool
+ OConnectionPools::iterator aFind = m_aPools.find(sThisDriverName);
+ if(aFind != m_aPools.end())
+ {
+ aFind->second->clear(false);
+ m_aPools.erase(aFind);
+ }
+ }
+ }
+}
+
+void OPoolCollection::clearDesktop()
+{
+ clearConnectionPools(true);
+ if ( m_xDesktop.is() )
+ m_xDesktop->removeTerminateListener(this);
+ m_xDesktop.clear();
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_OPoolCollection_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new OPoolCollection(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZPoolCollection.hxx b/connectivity/source/cpool/ZPoolCollection.hxx
new file mode 100644
index 000000000..3fdade8a9
--- /dev/null
+++ b/connectivity/source/cpool/ZPoolCollection.hxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbc/XDriverManager2.hpp>
+#include <com/sun/star/sdbc/XConnectionPool.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/frame/XDesktop2.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+#include <osl/mutex.hxx>
+#include <rtl/ref.hxx>
+
+namespace connectivity
+{
+ class OConnectionPool;
+
+ // OPoolCollection - the one-instance service for PooledConnections
+ // manages the active connections and the connections in the pool
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XConnectionPool,
+ css::lang::XServiceInfo,
+ css::frame::XTerminateListener,
+ css::beans::XPropertyChangeListener
+ > OPoolCollection_Base;
+
+ /// OPoolCollection: control the whole connection pooling for oo
+ class OPoolCollection : public OPoolCollection_Base
+ {
+
+
+ typedef std::map<OUString, rtl::Reference<OConnectionPool>> OConnectionPools;
+
+ typedef std::map<
+ css::uno::Reference< css::sdbc::XDriver >,
+ css::uno::WeakReference< css::sdbc::XDriver >>
+ MapDriver2DriverRef;
+
+ MapDriver2DriverRef m_aDriverProxies;
+ ::osl::Mutex m_aMutex;
+ OConnectionPools m_aPools; // the driver pools
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::sdbc::XDriverManager2 > m_xManager;
+ css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory;
+ css::uno::Reference< css::uno::XInterface > m_xConfigNode; // config node for general connection pooling
+ css::uno::Reference< css::frame::XDesktop2> m_xDesktop;
+
+ public:
+ OPoolCollection(const OPoolCollection&) = delete;
+ int operator= (const OPoolCollection&) = delete;
+
+ explicit OPoolCollection(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ private:
+ // some configuration helper methods
+ css::uno::Reference< css::uno::XInterface > const & getConfigPoolRoot();
+ static css::uno::Reference< css::uno::XInterface > createWithProvider( const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxConfProvider,
+ const OUString& _rPath);
+ static css::uno::Reference< css::uno::XInterface > openNode( const OUString& _rPath,
+ const css::uno::Reference< css::uno::XInterface >& _xTreeNode) noexcept;
+ bool isPoolingEnabled();
+ bool isDriverPoolingEnabled(std::u16string_view _sDriverImplName,
+ css::uno::Reference< css::uno::XInterface >& _rxDriverNode);
+ bool isPoolingEnabledByUrl( const OUString& _sUrl,
+ css::uno::Reference< css::sdbc::XDriver >& _rxDriver,
+ OUString& _rsImplName,
+ css::uno::Reference< css::uno::XInterface >& _rxDriverNode);
+
+ OConnectionPool* getConnectionPool( const OUString& _sImplName,
+ const css::uno::Reference< css::sdbc::XDriver >& _xDriver,
+ const css::uno::Reference< css::uno::XInterface >& _rxDriverNode);
+ void clearConnectionPools(bool _bDispose);
+ void clearDesktop();
+ protected:
+ virtual ~OPoolCollection() override;
+ public:
+
+ static css::uno::Any getNodeValue( const OUString& _rPath,
+ const css::uno::Reference< css::uno::XInterface>& _xTreeNode)noexcept;
+
+ // XDriverManager
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& url ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override;
+ virtual sal_Int32 SAL_CALL getLoginTimeout( ) override;
+
+ //XDriverAccess
+ virtual css::uno::Reference< css::sdbc::XDriver > SAL_CALL getDriverByURL( const OUString& url ) override;
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override;
+ virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZPooledConnection.cxx b/connectivity/source/cpool/ZPooledConnection.cxx
new file mode 100644
index 000000000..42e8d6c02
--- /dev/null
+++ b/connectivity/source/cpool/ZPooledConnection.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ZPooledConnection.hxx"
+#include "ZConnectionWrapper.hxx"
+#include <comphelper/types.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::reflection;
+using namespace connectivity;
+using namespace ::osl;
+
+OPooledConnection::OPooledConnection(const Reference< XConnection >& _xConnection,
+ const Reference< css::reflection::XProxyFactory >& _rxProxyFactory)
+ : OPooledConnection_Base(m_aMutex)
+ ,m_xRealConnection(_xConnection)
+ ,m_xProxyFactory(_rxProxyFactory)
+{
+
+}
+
+// OComponentHelper
+void SAL_CALL OPooledConnection::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+ if (m_xComponent.is())
+ m_xComponent->removeEventListener(this);
+ m_xComponent.clear();
+ ::comphelper::disposeComponent(m_xRealConnection);
+}
+
+// XEventListener
+void SAL_CALL OPooledConnection::disposing( const EventObject& /*Source*/ )
+{
+m_xComponent.clear();
+}
+
+//XPooledConnection
+Reference< XConnection > OPooledConnection::getConnection()
+{
+ if(!m_xComponent.is() && m_xRealConnection.is())
+ {
+ Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(m_xRealConnection);
+ m_xComponent = new OConnectionWeakWrapper(xConProxy);
+ // register as event listener for the new connection
+ if (m_xComponent.is())
+ m_xComponent->addEventListener(this);
+ }
+ return Reference< XConnection >(m_xComponent,UNO_QUERY);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/ZPooledConnection.hxx b/connectivity/source/cpool/ZPooledConnection.hxx
new file mode 100644
index 000000000..79450ea08
--- /dev/null
+++ b/connectivity/source/cpool/ZPooledConnection.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/sdbc/XPooledConnection.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+
+
+namespace connectivity
+{
+
+ // OPooledConnection -
+ // allows to pool a real connection
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XPooledConnection
+ ,css::lang::XEventListener> OPooledConnection_Base;
+
+ class OPooledConnection : public ::cppu::BaseMutex
+ ,public OPooledConnection_Base
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xRealConnection; // the connection from driver
+ css::uno::Reference< css::lang::XComponent > m_xComponent; // the connection which wraps the real connection
+ css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory;
+ public:
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ OPooledConnection(const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const css::uno::Reference< css::reflection::XProxyFactory >& _rxProxyFactory);
+
+ //XPooledConnection
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/cpool/dbpool2.component b/connectivity/source/cpool/dbpool2.component
new file mode 100644
index 000000000..13f3bac38
--- /dev/null
+++ b/connectivity/source/cpool/dbpool2.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.sdbc.OConnectionPool"
+ constructor="connectivity_OPoolCollection_get_implementation">
+ <service name="com.sun.star.sdbc.ConnectionPool"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/dbtools/dbtools.component b/connectivity/source/dbtools/dbtools.component
new file mode 100644
index 000000000..76dadcc03
--- /dev/null
+++ b/connectivity/source/dbtools/dbtools.component
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="org.openoffice.comp.helper.DatabaseMetaDataResultSet"
+ constructor="connectivity_dbtools_ODatabaseMetaDataResultSet_get_implementation">
+ <service name="com.sun.star.sdbc.ResultSet"/>
+ </implementation>
+ <implementation name="org.openoffice.comp.helper.ParameterSubstitution"
+ constructor="connectivity_dbtools_ParameterSubstitution_get_implementation">
+ <service name="com.sun.star.sdb.ParameterSubstitution"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/drivers/ado/ACallableStatement.cxx b/connectivity/source/drivers/ado/ACallableStatement.cxx
new file mode 100644
index 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>
diff --git a/connectivity/source/inc/AutoRetrievingBase.hxx b/connectivity/source/inc/AutoRetrievingBase.hxx
new file mode 100644
index 000000000..a85b92c63
--- /dev/null
+++ b/connectivity/source/inc/AutoRetrievingBase.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS OAutoRetrievingBase
+ {
+ OUString m_sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
+ bool m_bAutoRetrievingEnabled; // set to when we should allow to query for generated values
+ protected:
+ OAutoRetrievingBase() : m_bAutoRetrievingEnabled(false) {}
+ virtual ~OAutoRetrievingBase(){}
+
+ void enableAutoRetrievingEnabled(bool _bAutoEnable) { m_bAutoRetrievingEnabled = _bAutoEnable; }
+ void setAutoRetrievingStatement(const OUString& _sStmt) { m_sGeneratedValueStatement = _sStmt; }
+ public:
+ bool isAutoRetrievingEnabled() const { return m_bAutoRetrievingEnabled; }
+
+ /** transform the statement to query for auto generated values
+ @param _sInsertStatement
+ The "INSERT" statement, is used to query for column and table names
+ @return
+ The transformed generated statement.
+ */
+ OUString getTransformedGeneratedStatement(const OUString& _sInsertStatement) const;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx b/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx
new file mode 100644
index 000000000..c469f0671
--- /dev/null
+++ b/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx
@@ -0,0 +1,270 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <vector>
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XCloseable,
+ css::lang::XInitialization,
+ css::lang::XServiceInfo,
+ css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE;
+
+ // typedef ORefVector<ORowSetValue> ORow;
+ // typedef ORefVector<ORow> ORows;
+
+ class OOO_DLLPUBLIC_DBTOOLS ODatabaseMetaDataResultSet :
+ public cppu::BaseMutex,
+ public ODatabaseMetaDataResultSet_BASE,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet>
+ {
+
+ public:
+ typedef std::vector<ORowSetValueDecoratorRef> ORow;
+ typedef std::vector<ORow> ORows;
+
+ enum MetaDataResultSetType
+ {
+ /// describes a result set as expected by XDatabaseMetaData::getCatalogs
+ eCatalogs = 0,
+ /// describes a result set as expected by XDatabaseMetaData::getSchemas
+ eSchemas = 1,
+ /// describes a result set as expected by XDatabaseMetaData::getColumnPrivileges
+ eColumnPrivileges = 2,
+ /// describes a result set as expected by XDatabaseMetaData::getColumns
+ eColumns = 3,
+ /// describes a result set as expected by XDatabaseMetaData::getTables
+ eTables = 4,
+ /// describes a result set as expected by XDatabaseMetaData::getTableTypes
+ eTableTypes = 5,
+ /// describes a result set as expected by XDatabaseMetaData::getProcedureColumns
+ eProcedureColumns = 6,
+ /// describes a result set as expected by XDatabaseMetaData::getProcedures
+ eProcedures = 7,
+ /// describes a result set as expected by XDatabaseMetaData::getExportedKeys
+ eExportedKeys = 8,
+ /// describes a result set as expected by XDatabaseMetaData::getImportedKeys
+ eImportedKeys = 9,
+ /// describes a result set as expected by XDatabaseMetaData::getPrimaryKeys
+ ePrimaryKeys = 10,
+ /// describes a result set as expected by XDatabaseMetaData::getIndexInfo
+ eIndexInfo = 11,
+ /// describes a result set as expected by XDatabaseMetaData::getTablePrivileges
+ eTablePrivileges = 12,
+ /// describes a result set as expected by XDatabaseMetaData::getCrossReference
+ eCrossReference = 13,
+ /// describes a result set as expected by XDatabaseMetaData::getTypeInfo
+ eTypeInfo = 14,
+ /// describes a result set as expected by XDatabaseMetaData::getBestRowIdentifier
+ eBestRowIdentifier = 15,
+ /// describes a result set as expected by XDatabaseMetaData::getVersionColumns
+ eVersionColumns = 16,
+ /// describes a result set as expected by XDatabaseMetaData::getUDTs
+ eUDTs = 17
+ };
+
+ private:
+ ORowSetValue m_aEmptyValue;
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ sal_Int32 m_nColPos;
+
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+
+ void construct();
+ /// @throws css::sdbc::SQLException
+ void checkIndex(sal_Int32 columnIndex );
+ void setType(MetaDataResultSetType _eType);
+
+ protected:
+ ORows m_aRows;
+ ORows::iterator m_aRowsIter;
+ bool m_bBOF;
+ bool m_bEOF;
+
+ virtual const ORowSetValue& getValue(sal_Int32 columnIndex);
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual ~ODatabaseMetaDataResultSet() override;
+ public:
+
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ /// default construction
+ ODatabaseMetaDataResultSet();
+ /// construction of a pre-defined result set type
+ ODatabaseMetaDataResultSet( MetaDataResultSetType _eType );
+
+ void setRows(ORows&& _rRows);
+
+ // XServiceInfo
+
+ protected:
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ void setCatalogsMap();
+ void setSchemasMap();
+ void setColumnPrivilegesMap();
+ void setColumnsMap();
+ void setTablesMap();
+ void setTableTypes();
+ void setProcedureColumnsMap();
+ void setProceduresMap();
+ void setExportedKeysMap();
+ void setImportedKeysMap();
+ void setPrimaryKeysMap();
+ void setIndexInfoMap();
+ void setTablePrivilegesMap();
+ void setCrossReferenceMap();
+ void setTypeInfoMap();
+ void setBestRowIdentifierMap();
+ void setVersionColumnsMap();
+ void setUDTsMap();
+ public:
+ // some methods to get already defined ORowSetValues
+ // this increase the reuse of ORowSetValues
+ /// return an empty ORowSetValueDecorator
+ static ORowSetValueDecoratorRef const & getEmptyValue();
+ /// return an ORowSetValueDecorator with 0 as value
+ static ORowSetValueDecoratorRef const & get0Value();
+ /// return an ORowSetValueDecorator with 1 as value
+ static ORowSetValueDecoratorRef const & get1Value();
+ /// return an ORowSetValueDecorator with ColumnSearch::BASIC as value
+ static ORowSetValueDecoratorRef const & getBasicValue();
+ /// return an ORowSetValueDecorator with string SELECT as value
+ static ORowSetValueDecoratorRef const & getSelectValue();
+ /// return an ORowSetValueDecorator with string INSERT as value
+ static ORowSetValueDecoratorRef const & getInsertValue();
+ /// return an ORowSetValueDecorator with string DELETE as value
+ static ORowSetValueDecoratorRef const & getDeleteValue();
+ /// return an ORowSetValueDecorator with string UPDATE as value
+ static ORowSetValueDecoratorRef const & getUpdateValue();
+ /// return an ORowSetValueDecorator with string CREATE as value
+ static ORowSetValueDecoratorRef const & getCreateValue();
+ /// return an ORowSetValueDecorator with string READ as value
+ static ORowSetValueDecoratorRef const & getReadValue();
+ /// return an ORowSetValueDecorator with string ALTER as value
+ static ORowSetValueDecoratorRef const & getAlterValue();
+ /// return an ORowSetValueDecorator with string DROP as value
+ static ORowSetValueDecoratorRef const & getDropValue();
+ /// return an ORowSetValueDecorator with string ' as value
+ static ORowSetValueDecoratorRef const & getQuoteValue();
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx b/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx
new file mode 100644
index 000000000..9de122672
--- /dev/null
+++ b/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <map>
+#include <vector>
+#include "OColumn.hxx"
+
+namespace connectivity
+{
+
+ //************ Class: ODatabaseMetaDataResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> ODatabaseMetaResultSetMetaData_BASE;
+
+ class ODatabaseMetaDataResultSetMetaData : public ODatabaseMetaResultSetMetaData_BASE
+ {
+ std::map<sal_Int32,connectivity::OColumn> m_mColumns;
+ std::map<sal_Int32,connectivity::OColumn>::const_iterator m_mColumnsIter;
+
+ protected:
+ virtual ~ODatabaseMetaDataResultSetMetaData() override;
+ public:
+ // a Constructor, that is needed for when returning the object is needed:
+ ODatabaseMetaDataResultSetMetaData( )
+ {
+ }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+
+ // methods to set the right column mapping
+ void setColumnPrivilegesMap();
+ void setColumnMap();
+ void setColumnsMap();
+ void setTableNameMap();
+ void setTablesMap();
+ void setProcedureColumnsMap();
+ void setPrimaryKeysMap();
+ void setIndexInfoMap();
+ void setTablePrivilegesMap();
+ void setCrossReferenceMap();
+ void setTypeInfoMap();
+ void setProcedureNameMap();
+ void setProceduresMap();
+ void setTableTypes();
+ void setBestRowIdentifierMap() { setVersionColumnsMap();}
+ void setVersionColumnsMap();
+ void setExportedKeysMap() { setCrossReferenceMap(); }
+ void setImportedKeysMap() { setCrossReferenceMap(); }
+ void setCatalogsMap();
+ void setSchemasMap();
+ void setUDTsMap();
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/OColumn.hxx b/connectivity/source/inc/OColumn.hxx
new file mode 100644
index 000000000..57addead1
--- /dev/null
+++ b/connectivity/source/inc/OColumn.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS OColumn
+ {
+ OUString m_TableName;
+ OUString m_ColumnName;
+ OUString m_ColumnLabel;
+
+ sal_Int32 m_Nullable;
+ sal_Int32 m_ColumnDisplaySize;
+ sal_Int32 m_Precision;
+ sal_Int32 m_Scale;
+ sal_Int32 m_ColumnType;
+
+ bool m_AutoIncrement;
+ bool m_CaseSensitive;
+ bool m_Searchable;
+ bool m_Currency;
+ bool m_Signed;
+ bool m_ReadOnly;
+ bool m_Writable;
+ bool m_DefinitelyWritable;
+
+ public:
+ OColumn()
+ : m_Nullable(0)
+ , m_ColumnDisplaySize(0)
+ , m_Precision(0)
+ , m_Scale(0)
+ , m_ColumnType(0)
+
+ , m_AutoIncrement(false)
+ , m_CaseSensitive(false)
+ , m_Searchable(true)
+ , m_Currency(false)
+ , m_Signed(false)
+ , m_ReadOnly(true)
+ , m_Writable(false)
+ , m_DefinitelyWritable(false)
+ {}
+
+ OColumn(const OUString &_aTableName,
+ const OUString &_aColumnName,
+ sal_Int32 _aNullable,
+ sal_Int32 _aColumnDisplaySize,
+ sal_Int32 _aPrecision,
+ sal_Int32 _aScale,
+ sal_Int32 _aColumnType)
+ : m_TableName(_aTableName),
+ m_ColumnName(_aColumnName),
+ m_ColumnLabel(),
+
+ m_Nullable(_aNullable),
+ m_ColumnDisplaySize(_aColumnDisplaySize),
+ m_Precision(_aPrecision),
+ m_Scale(_aScale),
+ m_ColumnType(_aColumnType),
+
+ m_AutoIncrement(false),
+ m_CaseSensitive(false),
+ m_Searchable(true),
+ m_Currency(false),
+ m_Signed(false),
+ m_ReadOnly(true),
+ m_Writable(false),
+ m_DefinitelyWritable(false)
+ {
+ if(m_ColumnLabel.isEmpty())
+ m_ColumnLabel = _aColumnName;
+ }
+
+ bool isAutoIncrement() const { return m_AutoIncrement; }
+ bool isCaseSensitive() const { return m_CaseSensitive; }
+ bool isSearchable() const { return m_Searchable; }
+ bool isCurrency() const { return m_Currency; }
+ bool isSigned() const { return m_Signed; }
+ bool isReadOnly() const { return m_ReadOnly; }
+ bool isWritable() const { return m_Writable; }
+ bool isDefinitelyWritable() const { return m_DefinitelyWritable; }
+
+ sal_Int32 isNullable() const { return m_Nullable; }
+ sal_Int32 getColumnDisplaySize() const { return m_ColumnDisplaySize; }
+ sal_Int32 getPrecision() const { return m_Precision; }
+ sal_Int32 getScale() const { return m_Scale; }
+ sal_Int32 getColumnType() const { return m_ColumnType; }
+
+ const OUString& getColumnLabel() const { return m_ColumnLabel; }
+ const OUString& getColumnName() const { return m_ColumnName; }
+ const OUString& getTableName() const { return m_TableName; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/OTypeInfo.hxx b/connectivity/source/inc/OTypeInfo.hxx
new file mode 100644
index 000000000..4e9cbdf05
--- /dev/null
+++ b/connectivity/source/inc/OTypeInfo.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/DataType.hpp>
+
+#include <rtl/ustring.hxx>
+
+namespace connectivity
+{
+ struct OTypeInfo
+ {
+ OUString aTypeName; // Name of the type in the database
+ OUString aLocalTypeName;
+
+ sal_Int32 nPrecision; // Length of the type
+
+ sal_Int16 nMaximumScale; // Decimal places
+
+ sal_Int16 nType; // Database type
+
+ OTypeInfo()
+ :nPrecision(0)
+ ,nMaximumScale(0)
+ ,nType( css::sdbc::DataType::OTHER)
+ {}
+
+ bool operator == (const OTypeInfo& lh) const { return lh.nType == nType; }
+ bool operator != (const OTypeInfo& lh) const { return lh.nType != nType; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ParameterSubstitution.hxx b/connectivity/source/inc/ParameterSubstitution.hxx
new file mode 100644
index 000000000..11ac90982
--- /dev/null
+++ b/connectivity/source/inc/ParameterSubstitution.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/util/XStringSubstitution.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weakref.hxx>
+
+namespace connectivity
+{
+ typedef ::cppu::WeakImplHelper< css::util::XStringSubstitution
+ ,css::lang::XServiceInfo
+ ,css::lang::XInitialization > ParameterSubstitution_BASE;
+ class ParameterSubstitution final : public ParameterSubstitution_BASE
+ {
+ ::osl::Mutex m_aMutex;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::WeakReference< css::sdbc::XConnection > m_xConnection;
+
+ ParameterSubstitution( const ParameterSubstitution& ) = delete;
+ ParameterSubstitution& operator=( const ParameterSubstitution& ) = delete;
+ public:
+ ParameterSubstitution(const css::uno::Reference< css::uno::XComponentContext >& _rxContext );
+ private:
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XStringSubstitution
+ virtual OUString SAL_CALL substituteVariables( const OUString& aText, sal_Bool bSubstRequired ) override;
+ virtual OUString SAL_CALL reSubstituteVariables( const OUString& aText ) override;
+ virtual OUString SAL_CALL getSubstituteVariableValue( const OUString& variable ) override;
+ };
+
+} // connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/RowFunctionParser.hxx b/connectivity/source/inc/RowFunctionParser.hxx
new file mode 100644
index 000000000..059544e51
--- /dev/null
+++ b/connectivity/source/inc/RowFunctionParser.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include "FDatabaseMetaDataResultSet.hxx"
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <memory>
+
+namespace connectivity
+{
+enum class ExpressionFunct
+{
+ Equation,
+ And,
+ Or
+};
+
+#define EXPRESSION_FLAG_SUMANGLE_MODE 1
+
+class OOO_DLLPUBLIC_DBTOOLS SAL_NO_VTABLE ExpressionNode
+{
+public:
+ virtual ~ExpressionNode() {}
+
+ /** Operator to calculate function value.
+
+ This method calculates the function value.
+ */
+ virtual ORowSetValueDecoratorRef
+ evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow) const = 0;
+
+ virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow) const = 0;
+};
+
+/** This exception is thrown, when the arithmetic expression
+ parser failed to parse a string.
+ */
+struct OOO_DLLPUBLIC_DBTOOLS ParseError
+{
+ ParseError(const char*) {}
+};
+
+class FunctionParser
+{
+public:
+ /** Parse a string
+
+ The following grammar is accepted by this method:
+ <code>
+
+ number_digit = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
+
+ number = number number_digit | number_digit
+
+ equal_function = '='
+ ternary_function = 'if'
+
+ string_reference = 'a-z,A-Z,0-9' ' '
+ modifier_reference = '$' '0-9' ' '
+
+ basic_expression =
+ number |
+ string_reference |
+ additive_expression equal_function additive_expression |
+ unary_function '(' number_digit ')'
+ ternary_function '(' additive_expression ',' additive_expression ',
+ ' additive_expression ')' | '(' additive_expression ')'
+
+ </code>
+
+ @param rFunction
+ The string to parse
+
+ @throws ParseError if an invalid expression is given.
+
+ @return the generated function object.
+ */
+
+ static std::shared_ptr<ExpressionNode> const& parseFunction(const OUString& _sFunction);
+
+private:
+ // disabled constructor/destructor, since this is
+ // supposed to be a singleton
+ FunctionParser() = delete;
+ FunctionParser(const FunctionParser&) = delete;
+ FunctionParser& operator=(const FunctionParser&) = delete;
+};
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TConnection.hxx b/connectivity/source/inc/TConnection.hxx
new file mode 100644
index 000000000..2dbe2ef6a
--- /dev/null
+++ b/connectivity/source/inc/TConnection.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/textenc.h>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <cppuhelper/compbase.hxx>
+#include "propertyids.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include "resource/sharedresources.hxx"
+
+namespace connectivity
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection,
+ css::sdbc::XWarningsSupplier,
+ css::lang::XServiceInfo,
+ css::lang::XUnoTunnel
+ > OMetaConnection_BASE;
+
+ class OOO_DLLPUBLIC_DBTOOLS OMetaConnection : public OMetaConnection_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+ css::uno::Sequence< css::beans::PropertyValue >
+ m_aConnectionInfo;
+ connectivity::OWeakRefArray m_aStatements; // vector containing a list
+ // of all the Statement objects
+ // for this Connection
+ OUString m_sURL;
+ rtl_TextEncoding m_nTextEncoding; // the encoding which is used for all text conversions
+ css::uno::WeakReference< css::sdbc::XDatabaseMetaData >
+ m_xMetaData;
+ SharedResources m_aResources;
+ public:
+
+ static ::dbtools::OPropertyMap& getPropMap();
+
+ OMetaConnection();
+
+ rtl_TextEncoding getTextEncoding() const { return m_nTextEncoding; }
+ const OUString& getURL() const { return m_sURL; }
+ void setURL(const OUString& _rsUrl) { m_sURL = _rsUrl; }
+ void throwGenericSQLException(TranslateId pErrorResourceId, const css::uno::Reference< css::uno::XInterface>& _xContext);
+ const SharedResources& getResources() const { return m_aResources;}
+
+ void setConnectionInfo(const css::uno::Sequence< css::beans::PropertyValue >& _aInfo) { m_aConnectionInfo = _aInfo; }
+ const css::uno::Sequence< css::beans::PropertyValue >&
+ getConnectionInfo() const { return m_aConnectionInfo; }
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ //XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TDatabaseMetaDataBase.hxx b/connectivity/source/inc/TDatabaseMetaDataBase.hxx
new file mode 100644
index 000000000..4d8c7715c
--- /dev/null
+++ b/connectivity/source/inc/TDatabaseMetaDataBase.hxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include "FDatabaseMetaDataResultSet.hxx"
+#include <functional>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS ODatabaseMetaDataBase :
+ public cppu::BaseMutex,
+ public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData2,
+ css::lang::XEventListener>
+ {
+ private:
+ css::uno::Sequence< css::beans::PropertyValue > m_aConnectionInfo;
+ ::connectivity::ODatabaseMetaDataResultSet::ORows m_aTypeInfoRows;
+
+ // cached database information
+ std::pair<bool,bool> m_isCatalogAtStart;
+ std::pair<bool,OUString> m_sCatalogSeparator;
+ std::pair<bool,OUString> m_sIdentifierQuoteString;
+ std::pair<bool,bool> m_supportsCatalogsInTableDefinitions;
+ std::pair<bool,bool> m_supportsSchemasInTableDefinitions;
+ std::pair<bool,bool> m_supportsCatalogsInDataManipulation;
+ std::pair<bool,bool> m_supportsSchemasInDataManipulation;
+ std::pair<bool,bool> m_supportsMixedCaseQuotedIdentifiers;
+ std::pair<bool,bool> m_supportsAlterTableWithAddColumn;
+ std::pair<bool,bool> m_supportsAlterTableWithDropColumn;
+ std::pair<bool,sal_Int32> m_MaxStatements;
+ std::pair<bool,sal_Int32> m_MaxTablesInSelect;
+ std::pair<bool,bool> m_storesMixedCaseQuotedIdentifiers;
+
+ template <typename T> T callImplMethod(std::pair<bool,T>& _rCache,const std::function<T(ODatabaseMetaDataBase *)>& _pImplMethod)
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !_rCache.first )
+ {
+ _rCache.second = _pImplMethod(this);
+ _rCache.first = true;
+ }
+ return _rCache.second;
+ }
+ protected:
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::lang::XEventListener> m_xListenerHelper; // forward the calls from the connection to me
+
+ virtual ~ODatabaseMetaDataBase() override;
+
+ protected:
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() = 0;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) = 0;
+ virtual bool impl_isCatalogAtStart_throw( ) = 0;
+ virtual OUString impl_getCatalogSeparator_throw( ) = 0;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) = 0;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) = 0;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) = 0;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) = 0;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) = 0;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) = 0;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) = 0;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) = 0;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) = 0;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) = 0;
+
+
+ public:
+
+ ODatabaseMetaDataBase(const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,const css::uno::Sequence< css::beans::PropertyValue >& _rInfo);
+
+ // XDatabaseMetaData2
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getConnectionInfo( ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // cached database information
+ virtual OUString SAL_CALL getIdentifierQuoteString( ) override;
+ virtual sal_Bool SAL_CALL isCatalogAtStart( ) override;
+ virtual OUString SAL_CALL getCatalogSeparator( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatements( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TKeyValue.hxx b/connectivity/source/inc/TKeyValue.hxx
new file mode 100644
index 000000000..49d41e014
--- /dev/null
+++ b/connectivity/source/inc/TKeyValue.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/FValue.hxx>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <osl/diagnose.h>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS OKeyValue final
+ {
+ std::vector<ORowSetValueDecoratorRef> m_aKeys;
+ sal_Int32 m_nValue;
+
+ OKeyValue(sal_Int32 nVal);
+ public:
+
+ ~OKeyValue();
+
+ static std::unique_ptr<OKeyValue> createKeyValue(sal_Int32 nVal);
+
+ void pushKey(const ORowSetValueDecoratorRef& _aValueRef)
+ {
+ m_aKeys.push_back(_aValueRef);
+ }
+
+ OUString getKeyString(std::vector<ORowSetValueDecoratorRef>::size_type i) const
+ {
+ OSL_ENSURE(m_aKeys.size() > i,"Wrong index for KEyValue");
+ return m_aKeys[i]->getValue().getString();
+ }
+ double getKeyDouble(std::vector<ORowSetValueDecoratorRef>::size_type i) const
+ {
+ OSL_ENSURE(m_aKeys.size() > i,"Wrong index for KEyValue");
+ return m_aKeys[i]->getValue().getDouble();
+ }
+
+ sal_Int32 getValue() const { return m_nValue; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TPrivilegesResultSet.hxx b/connectivity/source/inc/TPrivilegesResultSet.hxx
new file mode 100644
index 000000000..b7206b7de
--- /dev/null
+++ b/connectivity/source/inc/TPrivilegesResultSet.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "FDatabaseMetaDataResultSet.hxx"
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS OResultSetPrivileges :
+ public ODatabaseMetaDataResultSet
+ {
+ css::uno::Reference< css::sdbc::XResultSet> m_xTables;
+ css::uno::Reference< css::sdbc::XRow> m_xRow;
+ bool m_bResetValues;
+ protected:
+ virtual const ORowSetValue& getValue(sal_Int32 columnIndex) override;
+ public:
+ OResultSetPrivileges(const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _rxMeta
+ ,const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern);
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TResultSetHelper.hxx b/connectivity/source/inc/TResultSetHelper.hxx
new file mode 100644
index 000000000..cedea1027
--- /dev/null
+++ b/connectivity/source/inc/TResultSetHelper.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ class OOO_DLLPUBLIC_DBTOOLS SAL_NO_VTABLE IResultSetHelper
+ {
+ public:
+ enum Movement
+ {
+ NEXT = 0,
+ PRIOR,
+ FIRST,
+ LAST,
+ // Named like this to avoid conflict with a #define in the Windows system ODBC headers.
+ RELATIVE1,
+ ABSOLUTE1,
+ BOOKMARK,
+ };
+ public:
+ virtual bool move(Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) = 0;
+ virtual sal_Int32 getDriverPos() const = 0;
+ virtual bool isRowDeleted() const = 0;
+
+ protected:
+ ~IResultSetHelper() {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TSkipDeletedSet.hxx b/connectivity/source/inc/TSkipDeletedSet.hxx
new file mode 100644
index 000000000..efe142af5
--- /dev/null
+++ b/connectivity/source/inc/TSkipDeletedSet.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TResultSetHelper.hxx"
+#include <vector>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace connectivity
+{
+ /**
+ the class OSkipDeletedSet supports a general method to skip deleted rows
+ */
+ class OOO_DLLPUBLIC_DBTOOLS OSkipDeletedSet
+ {
+ std::vector<sal_Int32> m_aBookmarksPositions;// vector of iterators to position map, the order is the logical position
+ IResultSetHelper* m_pHelper; // used for moving in the resultset
+ bool m_bDeletedVisible;
+
+ bool moveAbsolute(sal_Int32 _nOffset,bool _bRetrieveData);
+ public:
+ OSkipDeletedSet(IResultSetHelper* _pHelper);
+ ~OSkipDeletedSet();
+
+ /**
+ skipDeleted moves the resultset to the position defined by the parameters
+ it guarantees that the row isn't deleted
+ @param
+ IResultSetHelper::Movement _eCursorPosition in which direction the resultset should be moved
+ sal_Int32 _nOffset the position relative to the movement
+ sal_Bool _bRetrieveData is true when the current row should be filled which data
+ @return
+ true when the movement was successful otherwise false
+ */
+ bool skipDeleted(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData);
+ /**
+ clear the map and the vector used in this class
+ */
+ void clear();
+ /**
+ getMappedPosition returns the mapped position of a logical position
+ @param
+ sal_Int32 _nBookmark the logical position
+
+ @return the mapped position
+ */
+ sal_Int32 getMappedPosition(sal_Int32 _nBookmark) const;
+ /**
+ insertNewPosition adds a new position to the map
+ @param
+ sal_Int32 _nPos the logical position
+ */
+ void insertNewPosition(sal_Int32 _nPos);
+ /**
+ deletePosition deletes this position from the map and decrement all following positions
+ @param
+ sal_Int32 _nPos the logical position
+ */
+ void deletePosition(sal_Int32 _nPos);
+ void SetDeletedVisible(bool _bDeletedVisible) { m_bDeletedVisible = _bDeletedVisible; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/TSortIndex.hxx b/connectivity/source/inc/TSortIndex.hxx
new file mode 100644
index 000000000..3ac339f7e
--- /dev/null
+++ b/connectivity/source/inc/TSortIndex.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/dbtoolsdllapi.hxx>
+#include "TKeyValue.hxx"
+
+namespace connectivity
+{
+ enum class OKeyType
+ {
+ NONE, // do not sort
+ Double, // numeric key
+ String // String Key
+ };
+
+ enum class TAscendingOrder
+ {
+ ASC = 1, // ascending
+ DESC = -1 // otherwise
+ };
+
+ class OKeySet;
+ class OKeyValue; // simple class which holds a sal_Int32 and a std::vector<ORowSetValueDecoratorRef>
+
+ /**
+ The class OSortIndex can be used to implement a sorted index.
+ This can depend on the fields which should be sorted.
+ */
+ class OOO_DLLPUBLIC_DBTOOLS OSortIndex
+ {
+ public:
+ typedef std::vector<std::pair<sal_Int32, std::unique_ptr<OKeyValue>>> TIntValuePairVector;
+ typedef std::vector<OKeyType> TKeyTypeVector;
+
+ private:
+ TIntValuePairVector m_aKeyValues;
+ TKeyTypeVector m_aKeyType;
+ std::vector<TAscendingOrder> m_aAscending;
+ bool m_bFrozen;
+
+ public:
+
+ OSortIndex( std::vector<OKeyType>&& _aKeyType,
+ std::vector<TAscendingOrder>&& _aAscending);
+ OSortIndex(OSortIndex const &) = delete; // MSVC2015 workaround
+ OSortIndex& operator=(OSortIndex const &) = delete; // MSVC2015 workaround
+
+ ~OSortIndex();
+
+ /**
+ AddKeyValue appends a new value.
+ @param
+ pKeyValue the keyvalue to be appended
+ ATTENTION: when the sortindex is already frozen the parameter will be deleted
+ */
+ void AddKeyValue(std::unique_ptr<OKeyValue> pKeyValue);
+
+ /**
+ Freeze freezes the sortindex so that new values could only be appended by their value
+ */
+ void Freeze();
+
+ /**
+ CreateKeySet creates the keyset which values could be used to travel in your table/result
+ The returned keyset is frozen.
+ */
+ ::rtl::Reference<OKeySet> CreateKeySet();
+
+ const std::vector<OKeyType>& getKeyType() const { return m_aKeyType; }
+ TAscendingOrder getAscending(std::vector<TAscendingOrder>::size_type _nPos) const { return m_aAscending[_nPos]; }
+
+ };
+
+ // MSVC hack to avoid multiply defined std::vector-related symbols:
+ class OKeySet_Base: public ORefVector<sal_Int32> {};
+
+ /**
+ The class OKeySet is a refcountable vector which also has a state.
+ This state gives information about if the keyset is fixed.
+ */
+ class OOO_DLLPUBLIC_DBTOOLS OKeySet : public OKeySet_Base
+ {
+ bool m_bFrozen;
+ public:
+ OKeySet()
+ : m_bFrozen(false){}
+
+ bool isFrozen() const { return m_bFrozen; }
+ void setFrozen() { m_bFrozen = true; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ACallableStatement.hxx b/connectivity/source/inc/ado/ACallableStatement.hxx
new file mode 100644
index 000000000..e58617b3b
--- /dev/null
+++ b/connectivity/source/inc/ado/ACallableStatement.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ado/APreparedStatement.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XOutParameters.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::ado
+{
+
+ //************ Class: java.sql.CallableStatement
+
+
+ class OCallableStatement : public OPreparedStatement,
+ public css::sdbc::XRow,
+ public css::sdbc::XOutParameters
+ {
+ OLEVariant m_aValue;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OCallableStatement( OConnection* _pConnection, const OUString& sql );
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XOutParameters
+ virtual void SAL_CALL registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ACatalog.hxx b/connectivity/source/inc/ado/ACatalog.hxx
new file mode 100644
index 000000000..fd09e9ad3
--- /dev/null
+++ b/connectivity/source/inc/ado/ACatalog.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+
+ class OCatalog : public connectivity::sdbcx::OCatalog
+ {
+ WpADOCatalog m_aCatalog;
+ OConnection* m_pConnection;
+
+ public:
+ virtual void refreshTables() override;
+ virtual void refreshViews() override;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override;
+
+ public:
+ OCatalog(_ADOCatalog* _pCatalog,OConnection* _pCon);
+ ~OCatalog() override;
+
+ OConnection* getConnection() const { return m_pConnection; }
+ sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); }
+ WpADOCatalog getCatalog() const { return m_aCatalog; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AColumn.hxx b/connectivity/source/inc/ado/AColumn.hxx
new file mode 100644
index 000000000..fdb0afc74
--- /dev/null
+++ b/connectivity/source/inc/ado/AColumn.hxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ typedef sdbcx::OColumn OColumn_ADO;
+ class OAdoColumn : public OColumn_ADO
+ {
+ WpADOColumn m_aColumn;
+ OConnection* m_pConnection;
+ OUString m_ReferencedColumn;
+ bool m_IsAscending;
+
+ void fillPropertyValues();
+ protected:
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ public:
+ OAdoColumn(bool _bCase,OConnection* _pConnection,_ADOColumn* _pColumn);
+ OAdoColumn(bool _bCase,OConnection* _pConnection);
+ // ODescriptor
+ virtual void construct() override;
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+
+ WpADOColumn getColumnImpl() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AColumns.hxx b/connectivity/source/inc/ado/AColumns.hxx
new file mode 100644
index 000000000..25decfa68
--- /dev/null
+++ b/connectivity/source/inc/ado/AColumns.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ class OColumns : public sdbcx::OCollection
+ {
+ protected:
+ WpADOColumns m_aCollection;
+ OConnection* m_pConnection;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OColumns( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOColumns& _rCollection,
+ bool _bCase,
+ OConnection* _pConnection) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pConnection(_pConnection)
+ {
+ }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AConnection.hxx b/connectivity/source/inc/ado/AConnection.hxx
new file mode 100644
index 000000000..c2c821003
--- /dev/null
+++ b/connectivity/source/inc/ado/AConnection.hxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <map>
+#include <string_view>
+#include <connectivity/CommonTools.hxx>
+#include <OTypeInfo.hxx>
+#include <TConnection.hxx>
+#include <ado/Awrapado.hxx>
+
+namespace connectivity::ado
+{
+ struct OExtendedTypeInfo
+ {
+ ::connectivity::OTypeInfo aSimpleType; // the general type info
+ DataTypeEnum eType;
+
+ OUString getDBName() const { return aSimpleType.aTypeName; }
+ };
+
+ class WpADOConnection;
+ class ODriver;
+ class OCatalog;
+ typedef std::multimap<DataTypeEnum, OExtendedTypeInfo*> OTypeInfoMap;
+ typedef connectivity::OMetaConnection OConnection_BASE;
+
+
+ class OConnection : public OConnection_BASE
+ {
+ protected:
+
+ // Data attributes
+
+ OTypeInfoMap m_aTypeInfo; // vector containing an entry
+ // for each row returned by
+ // DatabaseMetaData.getTypeInfo.
+ css::uno::WeakReference< css::sdbcx::XTablesSupplier> m_xCatalog;
+ ODriver* m_pDriver;
+ private:
+ WpADOConnection m_aAdoConnection;
+ OCatalog* m_pCatalog;
+ sal_Int32 m_nEngineType;
+ bool m_bClosed;
+ bool m_bAutocommit;
+
+ protected:
+ /// @throws css::sdbc::SQLException
+ void buildTypeInfo();
+ public:
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OConnection(ODriver* _pDriver);
+ // OConnection(const SQLHANDLE _pConnectionHandle);
+ ~OConnection() override;
+ void construct(std::u16string_view url,const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ //XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ WpADOConnection& getConnection() { return m_aAdoConnection; }
+ void setCatalog(const css::uno::WeakReference< css::sdbcx::XTablesSupplier>& _xCat) { m_xCatalog = _xCat; }
+ void setCatalog(OCatalog* _pCatalog) { m_pCatalog = _pCatalog; }
+
+ const OTypeInfoMap* getTypeInfo() const { return &m_aTypeInfo;}
+ OCatalog* getAdoCatalog() const
+ {
+ if ( m_xCatalog.get().is() )
+ return m_pCatalog;
+ return nullptr;
+ }
+
+ sal_Int32 getEngineType() const { return m_nEngineType; }
+ ODriver* getDriver() const { return m_pDriver; }
+
+ static const OExtendedTypeInfo* getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo,
+ DataTypeEnum _nType,
+ const OUString& _sTypeName,
+ sal_Int32 _nPrecision,
+ sal_Int32 _nScale,
+ bool& _brForceToType);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ADatabaseMetaData.hxx b/connectivity/source/inc/ado/ADatabaseMetaData.hxx
new file mode 100644
index 000000000..1661ca441
--- /dev/null
+++ b/connectivity/source/inc/ado/ADatabaseMetaData.hxx
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <TDatabaseMetaDataBase.hxx>
+#include <map>
+
+namespace connectivity::ado
+{
+ class WpADOConnection;
+ class OConnection;
+
+ //************ Class: ODatabaseMetaData
+
+
+ class ODatabaseMetaData : public ODatabaseMetaDataBase
+ {
+ struct LiteralInfo
+ {
+ OUString pwszLiteralValue;
+ sal_uInt32 cchMaxLen;
+ bool fSupported;
+ };
+
+ std::map<sal_uInt32,LiteralInfo> m_aLiteralInfo;
+ WpADOConnection& m_rADOConnection;
+ OConnection* m_pConnection;
+
+ void fillLiterals();
+ // get information out of rowset
+ sal_Int32 getMaxSize(sal_uInt32 _nId);
+ bool isCapable(sal_uInt32 _nId);
+ OUString getLiteral(sal_uInt32 _nProperty);
+
+ // get info out of properties
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getStringProperty(const OUString& _aProperty);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getInt32Property(const OUString& _aProperty);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool getBoolProperty(const OUString& _aProperty);
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+ public:
+
+ ODatabaseMetaData(OConnection* _pCon);
+
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx b/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx
new file mode 100644
index 000000000..dce697165
--- /dev/null
+++ b/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <ado/AStatement.hxx>
+
+namespace connectivity::ado
+{
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE;
+
+ class ODatabaseMetaDataResultSet : public cppu::BaseMutex,
+ public ODatabaseMetaDataResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet>
+ {
+ std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+
+ std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> > m_aValueRange;
+ std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> >::iterator m_aValueRangeIter;
+
+ std::map<sal_Int32, std::map< OUString,sal_Int32> > m_aStrValueRange;
+ std::map<sal_Int32, std::map< OUString,sal_Int32> >::iterator m_aStrValueRangeIter;
+
+ std::map<sal_Int32, std::map< sal_Int32,OUString> > m_aIntValueRange;
+ std::map<sal_Int32, std::map< sal_Int32,OUString> >::iterator m_aIntValueRangeIter;
+
+ ADORecordset* m_pRecordSet;
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ OLEVariant m_aValue;
+ sal_Int32 m_nRowPos;
+ bool m_bWasNull;
+ bool m_bEOF;
+ bool m_bOnFirstAfterOpen;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getResultSetConcurrency();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getResultSetType();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getFetchDirection();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static OUString getCursorName();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+
+
+ inline sal_Int32 mapColumn (sal_Int32 column);
+ /// @throws css::sdbc::SQLException
+ void checkRecordSet();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OLEVariant getValue(sal_Int32 columnIndex );
+
+ protected:
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ ODatabaseMetaDataResultSet( ADORecordset* _pRecordSet);
+ ~ODatabaseMetaDataResultSet() override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ const std::vector<sal_Int32>& getColumnMapping() { return m_aColMapping; }
+
+ void setCatalogsMap();
+ void setSchemasMap();
+ void setColumnPrivilegesMap();
+ void setColumnsMap();
+ void setTablesMap();
+ void setProcedureColumnsMap();
+ void setProceduresMap();
+ void setExportedKeysMap();
+ void setImportedKeysMap();
+ void setPrimaryKeysMap();
+ void setIndexInfoMap();
+ void setTablePrivilegesMap();
+ void setCrossReferenceMap();
+ void setTypeInfoMap(bool _bJetEngine);
+ };
+
+ inline sal_Int32 ODatabaseMetaDataResultSet::mapColumn (sal_Int32 column)
+ {
+ sal_Int32 map = column;
+
+ if (!m_aColMapping.empty())
+ {
+ // Validate column number
+ map = m_aColMapping[column];
+ }
+
+ return map;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx b/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx
new file mode 100644
index 000000000..abac49ba1
--- /dev/null
+++ b/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <vector>
+#include <ado/Awrapado.hxx>
+#include <ado/ADatabaseMetaDataResultSet.hxx>
+#include <OColumn.hxx>
+
+namespace connectivity::ado
+{
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> ODatabaseMetaResultSetMetaData_BASE;
+
+ class ODatabaseMetaDataResultSetMetaData : public ODatabaseMetaResultSetMetaData_BASE
+ {
+ friend class ODatabaseMetaDataResultSet;
+
+ const std::vector<sal_Int32> &m_vMapping; // when not every column is needed
+ std::map<sal_Int32,connectivity::OColumn> m_mColumns;
+ std::map<sal_Int32,connectivity::OColumn>::const_iterator m_mColumnsIter;
+
+ ADORecordset* m_pRecordSet;
+ sal_Int32 m_nColCount;
+
+ private:
+ ODatabaseMetaDataResultSetMetaData( const ODatabaseMetaDataResultSetMetaData& ); // never implemented
+ ODatabaseMetaDataResultSetMetaData& operator=( const ODatabaseMetaDataResultSetMetaData& ); // never implemented
+
+ protected:
+ void setColumnPrivilegesMap();
+ void setColumnsMap();
+ void setTablesMap();
+ void setProcedureColumnsMap();
+ void setPrimaryKeysMap();
+ void setIndexInfoMap();
+ void setTablePrivilegesMap();
+ void setCrossReferenceMap();
+ void setTypeInfoMap();
+ void setProceduresMap();
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ ODatabaseMetaDataResultSetMetaData( ADORecordset* _pRecordSet ,ODatabaseMetaDataResultSet* _pRes)
+ : m_vMapping(_pRes->getColumnMapping()),
+ m_pRecordSet(_pRecordSet),
+ m_nColCount(m_vMapping.size()-1)
+ {
+ if(m_pRecordSet)
+ m_pRecordSet->AddRef();
+ }
+ ~ODatabaseMetaDataResultSetMetaData() override;
+
+ /// Avoid ambiguous cast error from the compiler.
+ operator css::uno::Reference< css::sdbc::XResultSetMetaData > () noexcept
+ { return this; }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ADriver.hxx b/connectivity/source/inc/ado/ADriver.hxx
new file mode 100644
index 000000000..8542e03f6
--- /dev/null
+++ b/connectivity/source/inc/ado/ADriver.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <connectivity/CommonTools.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace connectivity::ado
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver,
+ css::sdbcx::XDataDefinitionSupplier,
+ css::lang::XServiceInfo
+ > ODriver_BASE;
+ class ODriver : public ODriver_BASE
+ {
+ ::osl::Mutex m_aMutex;
+
+ connectivity::OWeakRefArray m_xConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ // to put back all the inits with COINIT_MULTITHREADED if needed
+ int mnNbCallCoInitializeExForReinit;
+
+ public:
+ ODriver(const css::uno::Reference< css::uno::XComponentContext >& xContext);
+ ~ODriver() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ css::uno::Reference< css::uno::XComponentContext > getContext() const { return m_xContext; }
+
+ private:
+ void impl_checkURL_throw(const OUString& _sUrl);
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AGroup.hxx b/connectivity/source/inc/ado/AGroup.hxx
new file mode 100644
index 000000000..f46577d0f
--- /dev/null
+++ b/connectivity/source/inc/ado/AGroup.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VGroup.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ typedef sdbcx::OGroup OGroup_ADO;
+ class OCatalog;
+
+ class OAdoGroup : public OGroup_ADO
+ {
+ WpADOGroup m_aGroup;
+ OCatalog* m_pCatalog;
+
+ static sal_Int32 MapRight(RightsEnum _eNum);
+ static RightsEnum Map2Right(sal_Int32 _eNum);
+ static ObjectTypeEnum MapObjectType(sal_Int32 ObjType);
+ protected:
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue,sal_Int32 nHandle) const override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+
+ public:
+ virtual void refreshUsers() override;
+ public:
+ OAdoGroup(OCatalog* _pParent,bool _bCase, ADOGroup* _pGroup=nullptr);
+ OAdoGroup(OCatalog* _pParent,bool _bCase, const OUString& Name);
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+
+ WpADOGroup getImpl() const { return m_aGroup; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AGroups.hxx b/connectivity/source/inc/ado/AGroups.hxx
new file mode 100644
index 000000000..85817cec8
--- /dev/null
+++ b/connectivity/source/inc/ado/AGroups.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+namespace connectivity::ado
+{
+ class OGroups : public sdbcx::OCollection
+ {
+ WpADOGroups m_aCollection;
+ OCatalog* m_pCatalog;
+ protected:
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OGroups(OCatalog* _pParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOGroups& _rCollection,bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pCatalog(_pParent)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AIndex.hxx b/connectivity/source/inc/ado/AIndex.hxx
new file mode 100644
index 000000000..7bc54f788
--- /dev/null
+++ b/connectivity/source/inc/ado/AIndex.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VIndex.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ class OAdoIndex : public sdbcx::OIndex
+ {
+ WpADOIndex m_aIndex;
+ OConnection* m_pConnection;
+ protected:
+ void fillPropertyValues();
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+ public:
+ virtual void refreshColumns() override;
+ public:
+ OAdoIndex(bool _bCase, OConnection* _pConnection,ADOIndex* _pIndex);
+ OAdoIndex(bool _bCase, OConnection* _pConnection);
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+
+ WpADOIndex getImpl() const { return m_aIndex;}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AIndexes.hxx b/connectivity/source/inc/ado/AIndexes.hxx
new file mode 100644
index 000000000..48c2d1abe
--- /dev/null
+++ b/connectivity/source/inc/ado/AIndexes.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ class OIndexes : public sdbcx::OCollection
+ {
+ WpADOIndexes m_aCollection;
+ OConnection* m_pConnection;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OIndexes(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOIndexes& _rCollection,
+ bool _bCase,
+ OConnection* _pConnection)
+ : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ , m_aCollection(_rCollection)
+ , m_pConnection(_pConnection)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AKey.hxx b/connectivity/source/inc/ado/AKey.hxx
new file mode 100644
index 000000000..67e05b86d
--- /dev/null
+++ b/connectivity/source/inc/ado/AKey.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VKey.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ typedef sdbcx::OKey OKey_ADO;
+
+ class OConnection;
+ class OAdoKey : public OKey_ADO
+ {
+ WpADOKey m_aKey;
+ OConnection* m_pConnection;
+ protected:
+ void fillPropertyValues();
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+ public:
+ virtual void refreshColumns() override;
+ public:
+ OAdoKey(bool _bCase,OConnection* _pConnection,ADOKey* _pKey);
+ OAdoKey(bool _bCase,OConnection* _pConnection);
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+
+ WpADOKey getImpl() const { return m_aKey;}
+ // map the update/delete rules
+ static RuleEnum Map2Rule(sal_Int32 _eNum);
+ static sal_Int32 MapRule(const RuleEnum& _eNum);
+
+ // map the keytypes
+ static sal_Int32 MapKeyRule(const KeyTypeEnum& _eNum);
+ static KeyTypeEnum Map2KeyRule(sal_Int32 _eNum);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AKeys.hxx b/connectivity/source/inc/ado/AKeys.hxx
new file mode 100644
index 000000000..45e127e29
--- /dev/null
+++ b/connectivity/source/inc/ado/AKeys.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OConnection;
+ class OKeys : public sdbcx::OCollection
+ {
+ WpADOKeys m_aCollection;
+ OConnection* m_pConnection;
+
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OKeys(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOKeys& _rCollection,
+ bool _bCase,
+ OConnection* _pConnection) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pConnection(_pConnection)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/APreparedStatement.hxx b/connectivity/source/inc/ado/APreparedStatement.hxx
new file mode 100644
index 000000000..2ce394dbd
--- /dev/null
+++ b/connectivity/source/inc/ado/APreparedStatement.hxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ado/AStatement.hxx>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+// TODO: implement css::sdbc::XPreparedBatchExecution
+// (empty implementations removed on 2014-06-16)
+
+namespace connectivity
+{
+ class OSQLParseNode;
+ namespace ado
+ {
+
+ class OPreparedStatement : public OStatement_Base,
+ public css::sdbc::XPreparedStatement,
+ public css::sdbc::XParameters,
+ public css::sdbc::XResultSetMetaDataSupplier,
+ public css::lang::XServiceInfo
+
+ {
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setParameter(sal_Int32 parameterIndex, const DataTypeEnum& _eType, sal_Int32 _nSize,const OLEVariant& Val);
+ void replaceParameterNodeName( OSQLParseNode const * _pNode,
+ const OUString& _sDefaultName,
+ sal_Int32& _nParameterCount);
+ protected:
+
+ // Data attributes
+
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData;
+ ADOParameters* m_pParameters;
+
+ virtual ~OPreparedStatement() override;
+
+ public:
+ DECLARE_SERVICE_INFO();
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OPreparedStatement( OConnection* _pConnection, const OUString& sql);
+
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ using OStatement_Base::executeQuery;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ using OStatement_Base::executeUpdate;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ using OStatement_Base::execute;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AResultSet.hxx b/connectivity/source/inc/ado/AResultSet.hxx
new file mode 100644
index 000000000..58de2baeb
--- /dev/null
+++ b/connectivity/source/inc/ado/AResultSet.hxx
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <ado/AStatement.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::ado
+{
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows,
+ css::lang::XServiceInfo> OResultSet_BASE;
+
+ class OResultSet : public cppu::BaseMutex,
+ public OResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OResultSet>
+ {
+
+ ADORecordset* m_pRecordSet;
+ OStatement_Base* m_pStmt;
+ css::uno::Reference< css::uno::XInterface> m_xStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ std::vector<OLEVariant> m_aBookmarks;
+ OLEVariant m_aValue;
+ ADO_LONGPTR m_nRowPos;
+ bool m_bEOF;
+ bool m_bOnFirstAfterOpen;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetConcurrency() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetType() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getFetchDirection();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static OUString getCursorName();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+ void updateValue(sal_Int32 columnIndex,const OLEVariant& x);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OLEVariant getValue(sal_Int32 columnIndex );
+
+ protected:
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual ~OResultSet() override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OResultSet( ADORecordset* _pRecordSet,OStatement_Base* pStmt);
+ OResultSet( ADORecordset* _pRecordSet);
+
+ // late constructor
+ void construct();
+ void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;}
+
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AResultSetMetaData.hxx b/connectivity/source/inc/ado/AResultSetMetaData.hxx
new file mode 100644
index 000000000..1eeb22656
--- /dev/null
+++ b/connectivity/source/inc/ado/AResultSetMetaData.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <vector>
+#include <ado/Awrapado.hxx>
+#include <ado/AResultSet.hxx>
+#include <OColumn.hxx>
+
+namespace connectivity::ado
+{
+
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper<css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
+
+ class OResultSetMetaData : public OResultSetMetaData_BASE
+ {
+ friend class OResultSet;
+
+ ADORecordset* m_pRecordSet;
+ sal_Int32 m_nColCount;
+
+ sal_Int32 MapADOType2Jdbc(DataTypeEnum eType);
+ private:
+ OResultSetMetaData( const OResultSetMetaData& ); // never implemented
+ OResultSetMetaData& operator=( const OResultSetMetaData& ); // never implemented
+
+ protected:
+ virtual ~OResultSetMetaData() override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OResultSetMetaData( ADORecordset* _pRecordSet);
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AStatement.hxx b/connectivity/source/inc/ado/AStatement.hxx
new file mode 100644
index 000000000..625339917
--- /dev/null
+++ b/connectivity/source/inc/ado/AStatement.hxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <ado/AConnection.hxx>
+#include <string_view>
+#include <vector>
+#include <ado/Awrapado.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::ado
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable,
+ css::sdbc::XMultipleResults> OStatement_BASE;
+
+
+ //************ Class: java.sql.Statement
+
+ class OStatement_Base : public cppu::BaseMutex,
+ public OStatement_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base>
+
+ {
+ friend class OResultSet;
+
+ css::sdbc::SQLWarning m_aLastWarning;
+
+ protected:
+ std::vector< OUString> m_aBatchVector;
+
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+ // for this Statement
+
+ OConnection* m_pConnection;// The owning Connection object
+ WpADOCommand m_Command;
+ WpADORecordset m_RecordSet;
+ OLEVariant m_RecordsAffected;
+ OLEVariant m_Parameters;
+ std::vector<connectivity::OTypeInfo> m_aTypeInfo; // Hashtable containing an entry
+ // for each row returned by
+ // DatabaseMetaData.getTypeInfo.
+ ADO_LONGPTR m_nMaxRows;
+ sal_Int32 m_nFetchSize;
+ LockTypeEnum m_eLockType;
+ CursorTypeEnum m_eCursorType;
+
+ using OStatement_BASE::rBHelper;
+ private:
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getQueryTimeOut() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getMaxFieldSize();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getMaxRows() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetConcurrency() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetType() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getFetchDirection();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getCursorName() const;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setQueryTimeOut(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setMaxFieldSize(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setMaxRows(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setResultSetConcurrency(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setResultSetType(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setCursorName(std::u16string_view _par0);
+
+ protected:
+
+ void assignRecordSet( ADORecordset* _pRS );
+
+ /// @throws css::sdbc::SQLException
+ void reset ();
+ /// @throws css::sdbc::SQLException
+ void clearMyResultSet ();
+ /// @throws css::sdbc::SQLException
+ void setWarning (const css::sdbc::SQLWarning &ex);
+ /// @throws css::sdbc::SQLException
+ sal_Int32 getRowCount ();
+ sal_Int32 getPrecision ( sal_Int32 sqlType);
+
+ void disposeResultSet();
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ OStatement_Base(OConnection* _pConnection );
+
+ using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+ };
+
+ class OStatement : public OStatement_Base,
+ public css::sdbc::XBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OStatement( OConnection* _pConnection) : OStatement_Base( _pConnection){};
+ ~OStatement() override;
+
+ DECLARE_SERVICE_INFO();
+
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // XBatchExecution
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ATable.hxx b/connectivity/source/inc/ado/ATable.hxx
new file mode 100644
index 000000000..07a16ae6a
--- /dev/null
+++ b/connectivity/source/inc/ado/ATable.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/VTable.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+namespace connectivity::ado
+{
+ typedef connectivity::sdbcx::OTable OTable_TYPEDEF;
+ typedef connectivity::sdbcx::OTableDescriptor_BASE OTableDescriptor_BASE_TYPEDEF;
+
+ class OAdoTable : public OTable_TYPEDEF
+ {
+ WpADOTable m_aTable;
+ OCatalog* m_pCatalog;
+
+ protected:
+ void fillPropertyValues();
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+
+ public:
+ virtual void refreshColumns() override;
+ virtual void refreshKeys() override;
+ virtual void refreshIndexes() override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ public:
+ OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog,_ADOTable* _pTable);
+ OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog);
+
+
+ virtual OUString SAL_CALL getName() override;
+ OUString getSchema() const { return m_SchemaName; }
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() const override;
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void SAL_CALL alterColumnByIndex( sal_Int32 index, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ WpADOTable getImpl() const { return m_aTable;}
+ OCatalog* getCatalog() const { return m_pCatalog; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/ATables.hxx b/connectivity/source/inc/ado/ATables.hxx
new file mode 100644
index 000000000..4fff5b979
--- /dev/null
+++ b/connectivity/source/inc/ado/ATables.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+namespace connectivity::ado
+{
+ class OCatalog;
+ class OTables : public sdbcx::OCollection
+ {
+ WpADOTables m_aCollection;
+ OCatalog* m_pCatalog;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OTables(OCatalog* _pParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOTables& _rCollection,
+ bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pCatalog(_pParent)
+ {
+ OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid");
+ }
+ void appendNew(const OUString& _rsNewTable);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AUser.hxx b/connectivity/source/inc/ado/AUser.hxx
new file mode 100644
index 000000000..849c3a98a
--- /dev/null
+++ b/connectivity/source/inc/ado/AUser.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sdbcx/VUser.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+ class OCatalog;
+ typedef connectivity::sdbcx::OUser OUser_TYPEDEF;
+ typedef connectivity::sdbcx::OUser_BASE OUser_BASE_TYPEDEF;
+
+ class OAdoUser : public OUser_TYPEDEF
+ {
+ protected:
+ WpADOUser m_aUser;
+ OCatalog* m_pCatalog;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ virtual void refreshGroups() override;
+ public:
+ OAdoUser(OCatalog* _pParent,bool _bCase, ADOUser* _pUser=nullptr);
+ OAdoUser(OCatalog* _pParent,bool _bCase, const OUString& Name);
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+ // XUser
+ virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override;
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+
+ WpADOUser getImpl() const { return m_aUser;}
+ };
+
+ class OUserExtend;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;
+
+ class OUserExtend : public OAdoUser,
+ public OUserExtend_PROP
+ {
+ protected:
+ OUString m_Password;
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OUserExtend(OCatalog* _pParent,bool _bCase,ADOUser* _pUser=nullptr);
+ OUserExtend(OCatalog* _pParent,bool _bCase,const OUString& Name);
+
+ virtual void construct() override;
+ OUString getPassword() const { return m_Password;}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AUsers.hxx b/connectivity/source/inc/ado/AUsers.hxx
new file mode 100644
index 000000000..1ec0bd5ad
--- /dev/null
+++ b/connectivity/source/inc/ado/AUsers.hxx
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+namespace connectivity::ado
+{
+
+ class OUsers : public sdbcx::OCollection
+ {
+ WpADOUsers m_aCollection;
+ OCatalog* m_pCatalog;
+ public:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual void impl_refresh() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OUsers( OCatalog* _pParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const WpADOUsers& _rCollection,
+ bool _bCase)
+ :sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pCatalog(_pParent)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AView.hxx b/connectivity/source/inc/ado/AView.hxx
new file mode 100644
index 000000000..6f8d7a337
--- /dev/null
+++ b/connectivity/source/inc/ado/AView.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VView.hxx>
+#include <ado/Awrapadox.hxx>
+
+namespace connectivity::ado
+{
+
+ typedef sdbcx::OView OView_ADO;
+
+ class OAdoView : public OView_ADO
+ {
+ WpADOView m_aView;
+
+ protected:
+ // OPropertySetHelper
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ OAdoView(bool _bCase, ADOView* _pView=nullptr);
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static css::uno::Sequence< sal_Int8 > getUnoTunnelId();
+
+ WpADOView getImpl() const { return m_aView;}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/AViews.hxx b/connectivity/source/inc/ado/AViews.hxx
new file mode 100644
index 000000000..ef0c692fd
--- /dev/null
+++ b/connectivity/source/inc/ado/AViews.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <ado/Awrapadox.hxx>
+#include <ado/ACatalog.hxx>
+
+
+namespace connectivity::ado
+{
+
+ class OViews : public sdbcx::OCollection
+ {
+ WpADOViews m_aCollection;
+ OCatalog* m_pCatalog;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OViews(OCatalog* _pParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ WpADOViews const & _rCollection,bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector)
+ ,m_aCollection(_rCollection)
+ ,m_pCatalog(_pParent)
+ {
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/Aolevariant.hxx b/connectivity/source/inc/ado/Aolevariant.hxx
new file mode 100644
index 000000000..ba0653156
--- /dev/null
+++ b/connectivity/source/inc/ado/Aolevariant.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <oaidl.h>
+
+namespace com::sun::star::util
+{
+ struct Date;
+ struct Time;
+ struct DateTime;
+}
+
+namespace connectivity::ado
+{
+ class OLEVariant : public ::tagVARIANT
+ {
+ public:
+ OLEVariant();
+ OLEVariant(const VARIANT& varSrc);
+ OLEVariant(const OLEVariant& varSrc) ;
+ OLEVariant(bool x) ;
+ OLEVariant(sal_Bool) = delete;
+ OLEVariant(sal_Int8 n) ;
+ OLEVariant(sal_Int16 n) ;
+ OLEVariant(sal_Int32 n) ;
+ OLEVariant(sal_Int64 x) ;
+
+ OLEVariant(std::u16string_view us);
+ OLEVariant(const OUString& us)
+ : OLEVariant(std::u16string_view(us))
+ {
+ }
+ ~OLEVariant() ;
+ OLEVariant(const css::util::Date& x );
+ OLEVariant(const css::util::Time& x );
+ OLEVariant(const css::util::DateTime& x );
+ OLEVariant(float x);
+ OLEVariant(const double &x);
+ OLEVariant(IDispatch* pDispInterface);
+ OLEVariant(const css::uno::Sequence< sal_Int8 >& x);
+ OLEVariant& operator=(const OLEVariant& varSrc);
+ // Assign a const VARIANT& (::VariantCopy handles everything)
+
+ OLEVariant& operator=(const tagVARIANT& varSrc);
+ // Assign a const VARIANT* (::VariantCopy handles everything)
+
+ OLEVariant& operator=(const VARIANT* pSrc);
+ void setByte(sal_uInt8 n) ;
+ void setInt16(sal_Int16 n) ;
+ void setInt32(sal_Int32 n) ;
+ void setFloat(float f) ;
+ void setDouble(double d) ;
+ void setDate(DATE d) ;
+ void setChar(unsigned char a) ;
+ void setCurrency(double aCur) ;
+ void setBool(bool b) ;
+ void setString(std::u16string_view us);
+ void setNoArg() ;
+
+ void setIDispatch(IDispatch* pDispInterface);
+ void setNull() ;
+ void setEmpty() ;
+
+ void setUI1SAFEARRAYPtr(SAFEARRAY* pSafeAr);
+ void setArray(SAFEARRAY* pSafeArray, VARTYPE vtType);
+ bool isNull() const ;
+ bool isEmpty() const ;
+
+ VARTYPE getType() const ;
+ void ChangeType(VARTYPE vartype, const OLEVariant* pSrc);
+
+ OUString getString() const;
+ bool getBool() const;
+ IUnknown* getIUnknown() const;
+ IDispatch* getIDispatch() const;
+ sal_uInt8 getByte() const;
+ sal_Int16 getInt16() const;
+ sal_Int8 getInt8() const;
+ sal_Int32 getInt32() const;
+ sal_uInt32 getUInt32() const;
+ float getFloat() const;
+ double getDouble() const;
+ double getDateAsDouble() const;
+ CY getCurrency() const;
+ css::util::Date getDate() const;
+ css::util::Time getTime() const;
+ css::util::DateTime getDateTime() const;
+ css::uno::Sequence<sal_Int8> getByteSequence() const;
+ SAFEARRAY* getUI1SAFEARRAYPtr() const;
+ css::uno::Any makeAny() const;
+
+ static VARIANT_BOOL VariantBool(bool bEinBoolean);
+
+ private:
+ void CHS();
+
+ void set(double n);
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/Aolewrap.hxx b/connectivity/source/inc/ado/Aolewrap.hxx
new file mode 100644
index 000000000..9d402fcf2
--- /dev/null
+++ b/connectivity/source/inc/ado/Aolewrap.hxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <systools/win32/comtools.hxx>
+
+#include <map>
+#include <vector>
+
+#include "Aolevariant.hxx"
+
+namespace rtl
+{
+ class OUString;
+}
+namespace connectivity::ado
+{
+ // Template class WpOLEBase<class T>
+ // ==================================
+ //
+ // Objects of this class contain a pointer to an interface of the type T.
+
+ template<class T> class WpOLEBase
+ {
+ protected:
+ sal::systools::COMReference<T> pInterface;
+
+ public:
+ WpOLEBase(T* pInt = nullptr) : pInterface(pInt){}
+
+ WpOLEBase(const WpOLEBase<T>& aWrapper)
+ : pInterface( aWrapper.pInterface )
+ {
+ }
+
+ //inline
+ WpOLEBase<T>& operator=(const WpOLEBase<T>& rhs)
+ {
+ pInterface = rhs.pInterface;
+ return *this;
+ };
+
+ operator T*() const { return pInterface.get(); }
+ T** operator&() { return &pInterface; }
+ bool IsValid() const { return pInterface.is(); }
+ void set(T* p) { pInterface = p; }
+ void clear() { pInterface.clear(); }
+ };
+
+
+ // Template class WpOLECollection<class Ts, class WrapT>
+ // ===============================================================
+ //
+ // This class (derived from WpOLEBase<Ts>), abstracts away the properties
+ // common to DAO collections:
+ //
+ // They are accessed via an interface Ts (e.g. DAOFields) and can return
+ // Items of the type wrapped by WrapT (actually: with the interface, e.g.
+ // DAOField) via get_Item (here GetItem).
+ //
+ // This wrapper class exposes an object of the class WrapT.
+
+ template<class Ts, class WrapT> class WpOLECollection : public WpOLEBase<Ts>
+ {
+ public:
+ using WpOLEBase<Ts>::pInterface;
+ using WpOLEBase<Ts>::IsValid;
+ // Ctors, operator=
+ // They only call the superclass
+ WpOLECollection() = default;
+ WpOLECollection(const WpOLECollection& rhs) : WpOLEBase<Ts>(rhs) {}
+ WpOLECollection& operator=(const WpOLECollection& rhs)
+ {WpOLEBase<Ts>::operator=(rhs); return *this;};
+
+
+ void Refresh(){pInterface->Refresh();}
+
+ sal_Int32 GetItemCount() const
+ {
+ sal_Int32 nCount = 0;
+ return pInterface ? (SUCCEEDED(pInterface->get_Count(&nCount)) ? nCount : sal_Int32(0)) : sal_Int32(0);
+ }
+
+ WrapT GetItem(sal_Int32 index) const
+ {
+ OSL_ENSURE(index >= 0 && index<GetItemCount(),"Wrong index for field!");
+ WrapT aRet;
+ pInterface->get_Item(OLEVariant(index), &aRet);
+ return aRet;
+ }
+
+ WrapT GetItem(const OLEVariant& index) const
+ {
+ WrapT aRet;
+ pInterface->get_Item(index, &aRet);
+ return aRet;
+ }
+
+ WrapT GetItem(const OUString& sStr) const
+ {
+ WrapT aRet;
+ if (FAILED(pInterface->get_Item(OLEVariant(sStr), &aRet)))
+ {
+#if OSL_DEBUG_LEVEL > 0
+ OString sTemp("Unknown Item: " + OString(sStr.getStr(),sStr.getLength(),osl_getThreadTextEncoding()));
+ OSL_FAIL(sTemp.getStr());
+#endif
+ }
+ return aRet;
+ }
+ void fillElementNames(::std::vector< OUString>& _rVector)
+ {
+ if(IsValid())
+ {
+ Refresh();
+ sal_Int32 nCount = GetItemCount();
+ _rVector.reserve(nCount);
+ for(sal_Int32 i=0;i< nCount;++i)
+ {
+ WrapT aElement = GetItem(i);
+ if(aElement.IsValid())
+ _rVector.push_back(aElement.get_Name());
+ }
+ }
+ }
+ };
+
+ template<class Ts, class WrapT> class WpOLEAppendCollection:
+ public WpOLECollection<Ts,WrapT>
+ {
+
+ public:
+ // Ctors, operator=
+ // They only call the superclass
+ using WpOLEBase<Ts>::pInterface;
+ WpOLEAppendCollection() = default;
+ WpOLEAppendCollection(const WpOLEAppendCollection& rhs) : WpOLECollection<Ts, WrapT>(rhs) {}
+ WpOLEAppendCollection& operator=(const WpOLEAppendCollection& rhs)
+ {WpOLEBase<Ts>::operator=(rhs); return *this;};
+
+
+ bool Append(const WrapT& aWrapT)
+ {
+ return SUCCEEDED(pInterface->Append(OLEVariant(aWrapT)));
+ };
+
+ bool Delete(const OUString& sName)
+ {
+ return SUCCEEDED(pInterface->Delete(OLEVariant(sName)));
+ };
+
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/Awrapado.hxx b/connectivity/source/inc/ado/Awrapado.hxx
new file mode 100644
index 000000000..8bc8cffb2
--- /dev/null
+++ b/connectivity/source/inc/ado/Awrapado.hxx
@@ -0,0 +1,372 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+// Includes for ADO
+#include <oledb.h>
+#include <ocidl.h>
+#include <adoint.h>
+#include <ado/adoimp.hxx>
+#include <ado/Aolewrap.hxx>
+#include <ado/Aolevariant.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOConnection;
+ class WpADOCommand;
+ class WpADORecordset;
+ class WpADOField;
+ class WpADOParameter;
+ class WpADOError;
+ class WpADOProperty;
+
+ typedef WpOLEAppendCollection< ADOFields, WpADOField> WpADOFields;
+ typedef WpOLECollection< ADOProperties, WpADOProperty> WpADOProperties;
+
+
+ class WpADOConnection : public WpOLEBase<ADOConnection>
+ {
+ public:
+
+ WpADOConnection() = default;
+
+ WpADOConnection(const WpADOConnection& rhs) : WpOLEBase<ADOConnection>(rhs) {}
+
+ WpADOConnection& operator=(const WpADOConnection& rhs)
+ {WpOLEBase<ADOConnection>::operator=(rhs); return *this;}
+
+
+ WpADOProperties get_Properties() const;
+
+ OUString GetConnectionString() const;
+ bool PutConnectionString(std::u16string_view aCon) const;
+ sal_Int32 GetCommandTimeout() const;
+ void PutCommandTimeout(sal_Int32 nRet);
+ sal_Int32 GetConnectionTimeout() const ;
+ void PutConnectionTimeout(sal_Int32 nRet);
+
+ bool Close( ) ;
+ bool Execute(std::u16string_view CommandText,OLEVariant& RecordsAffected,long Options, WpADORecordset** ppiRset);
+ bool BeginTrans();
+ bool CommitTrans( ) ;
+ bool RollbackTrans( );
+ bool Open(std::u16string_view ConnectionString, std::u16string_view UserID,std::u16string_view Password,long Options);
+ bool GetErrors(ADOErrors** pErrors);
+
+ OUString GetDefaultDatabase() const;
+ bool PutDefaultDatabase(std::u16string_view _bstr);
+
+ IsolationLevelEnum get_IsolationLevel() const ;
+ bool put_IsolationLevel(const IsolationLevelEnum& eNum) ;
+
+ sal_Int32 get_Attributes() const;
+ bool put_Attributes(sal_Int32 nRet);
+
+ CursorLocationEnum get_CursorLocation() const;
+ bool put_CursorLocation(const CursorLocationEnum &eNum) ;
+
+ ConnectModeEnum get_Mode() const;
+ bool put_Mode(const ConnectModeEnum &eNum) ;
+
+ OUString get_Provider() const;
+ bool put_Provider(std::u16string_view _bstr);
+
+ sal_Int32 get_State() const;
+
+ bool OpenSchema(SchemaEnum eNum,OLEVariant const & Restrictions,OLEVariant const & SchemaID,ADORecordset**pprset);
+
+ OUString get_Version() const;
+
+ // special methods
+ ADORecordset* getExportedKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table );
+ ADORecordset* getImportedKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table );
+ ADORecordset* getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table );
+ ADORecordset* getIndexInfo( const css::uno::Any& catalog, const OUString& schema, std::u16string_view table, bool unique, bool approximate );
+ ADORecordset* getTablePrivileges( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ const OUString& tableNamePattern );
+ ADORecordset* getCrossReference( const css::uno::Any& primaryCatalog,
+ const OUString& primarySchema,
+ std::u16string_view primaryTable,
+ const css::uno::Any& foreignCatalog,
+ const OUString& foreignSchema,
+ std::u16string_view foreignTable);
+ ADORecordset* getProcedures( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ const OUString& procedureNamePattern );
+ ADORecordset* getProcedureColumns( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ const OUString& procedureNamePattern,
+ const OUString& columnNamePattern );
+ ADORecordset* getTables( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const css::uno::Sequence< OUString >& types );
+ ADORecordset* getColumns( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ std::u16string_view columnNamePattern );
+ ADORecordset* getColumnPrivileges( const css::uno::Any& catalog,
+ const OUString& schemaPattern,
+ std::u16string_view table,
+ std::u16string_view columnNamePattern );
+ ADORecordset* getTypeInfo(DataTypeEnum _eType = adEmpty );
+ };
+
+
+ class WpADOCommand : public WpOLEBase<ADOCommand>
+ {
+ public:
+ WpADOCommand() = default;
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOCommand(const WpADOCommand& rhs) : WpOLEBase<ADOCommand>(rhs) {}
+
+ WpADOCommand& operator=(const WpADOCommand& rhs)
+ {
+ WpOLEBase<ADOCommand>::operator=(rhs); return *this;}
+
+
+ bool putref_ActiveConnection(const WpADOConnection& rCon);
+
+ void put_ActiveConnection(/* [in] */ const OLEVariant& vConn);
+ void Create();
+ sal_Int32 get_State() const;
+ OUString get_CommandText() const;
+ bool put_CommandText(std::u16string_view aCon) ;
+ sal_Int32 get_CommandTimeout() const;
+ void put_CommandTimeout(sal_Int32 nRet);
+ bool get_Prepared() const;
+ bool put_Prepared(VARIANT_BOOL bPrepared) const;
+ bool Execute(OLEVariant& RecordsAffected,OLEVariant& Parameters,long Options, ADORecordset** ppiRset);
+ ADOParameter* CreateParameter(std::u16string_view _bstr,DataTypeEnum Type,ParameterDirectionEnum Direction,long nSize,const OLEVariant &Value);
+
+ ADOParameters* get_Parameters() const;
+ bool put_CommandType( /* [in] */ CommandTypeEnum lCmdType);
+ CommandTypeEnum get_CommandType( ) const ;
+ // Returns the field's name
+ OUString GetName() const ;
+ bool put_Name(std::u16string_view Name);
+ bool Cancel();
+ };
+
+ class WpADOError : public WpOLEBase<ADOError>
+ {
+ public:
+
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOError() = default;
+
+ WpADOError(const WpADOError& rhs) : WpOLEBase<ADOError>(rhs) {}
+
+ WpADOError& operator=(const WpADOError& rhs)
+ {WpOLEBase<ADOError>::operator=(rhs); return *this;}
+
+
+ OUString GetDescription() const;
+ OUString GetSource() const ;
+ sal_Int32 GetNumber() const ;
+ OUString GetSQLState() const ;
+ sal_Int32 GetNativeError() const ;
+ };
+
+
+ class WpADOField : public WpOLEBase<ADOField>
+ {
+ // friend class WpADOFields;
+ public:
+
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOField() = default;
+ WpADOField(const WpADOField& rhs) : WpOLEBase<ADOField>(rhs) {}
+
+ WpADOField& operator=(const WpADOField& rhs)
+ {WpOLEBase<ADOField>::operator=(rhs); return *this;}
+
+
+ WpADOProperties get_Properties();
+ sal_Int32 GetActualSize() const ;
+ sal_Int32 GetAttributes() const ;
+ sal_Int32 GetStatus() const ;
+ sal_Int32 GetDefinedSize() const ;
+ // Returns the field's name
+ OUString GetName() const ;
+ DataTypeEnum GetADOType() const ;
+ void get_Value(OLEVariant& aValVar) const ;
+ OLEVariant get_Value() const;
+ bool PutValue(const OLEVariant& aVariant);
+ sal_Int32 GetPrecision() const ;
+ sal_Int32 GetNumericScale() const ;
+ bool AppendChunk(const OLEVariant& Variant);
+ OLEVariant GetChunk(long Length) const;
+ void GetChunk(long Length,OLEVariant &aValVar) const;
+ OLEVariant GetOriginalValue() const;
+ void GetOriginalValue(OLEVariant &aValVar) const;
+ OLEVariant GetUnderlyingValue() const;
+
+ void GetUnderlyingValue(OLEVariant &aValVar) const;
+
+ bool PutPrecision(sal_Int8 _prec);
+
+ bool PutNumericScale(sal_Int8 _prec);
+
+ void PutADOType(DataTypeEnum eType) ;
+
+ bool PutDefinedSize(sal_Int32 _nDefSize);
+
+ bool PutAttributes(sal_Int32 _nDefSize);
+ };
+
+
+ class WpADOProperty: public WpOLEBase<ADOProperty>
+ {
+ public:
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOProperty() = default;
+ WpADOProperty(const WpADOProperty& rhs) : WpOLEBase<ADOProperty>(rhs) {}
+ WpADOProperty& operator=(const WpADOProperty& rhs)
+ {WpOLEBase<ADOProperty>::operator=(rhs); return *this;}
+
+
+ OLEVariant GetValue() const;
+ void GetValue(OLEVariant &aValVar) const;
+ bool PutValue(const OLEVariant &aValVar) ;
+ OUString GetName() const ;
+ DataTypeEnum GetADOType() const ;
+ sal_Int32 GetAttributes() const ;
+ bool PutAttributes(sal_Int32 _nDefSize);
+ };
+
+
+ class WpADORecordset : public WpOLEBase<ADORecordset>
+ {
+
+ public:
+ // Ctors, operator=
+ // They only call the superclass
+ WpADORecordset() = default;
+ WpADORecordset(const WpADORecordset& rhs) : WpOLEBase<ADORecordset>() {operator=(rhs);}
+ WpADORecordset& operator=(const WpADORecordset& rhs)
+ {
+ WpOLEBase<ADORecordset>::operator=(rhs);
+ return *this;
+ }
+
+ void Create();
+ bool Open(
+ /* [optional][in] */ VARIANT Source,
+ /* [optional][in] */ VARIANT ActiveConnection,
+ /* [defaultvalue][in] */ CursorTypeEnum CursorType,
+ /* [defaultvalue][in] */ LockTypeEnum LockType,
+ /* [defaultvalue][in] */ sal_Int32 Options);
+ LockTypeEnum GetLockType();
+ void Close();
+ bool Cancel() const;
+ sal_Int32 get_State( );
+ bool Supports( /* [in] */ CursorOptionEnum CursorOptions);
+ PositionEnum_Param get_AbsolutePosition();
+ void GetDataSource(IUnknown** pIUnknown) const ;
+ void PutRefDataSource(IUnknown* pIUnknown);
+ void GetBookmark(VARIANT& var);
+ OLEVariant GetBookmark();
+ CompareEnum CompareBookmarks(const OLEVariant& left,const OLEVariant& right);
+ bool SetBookmark(const OLEVariant &pSafeAr);
+ WpADOFields GetFields() const;
+ bool Move(sal_Int32 nRows, VARIANT aBmk);
+ bool MoveNext();
+ bool MovePrevious();
+ bool MoveFirst();
+ bool MoveLast();
+
+ bool IsAtBOF() const;
+ bool IsAtEOF() const;
+ bool Delete(AffectEnum eNum);
+ bool AddNew(const OLEVariant &FieldList,const OLEVariant &Values);
+ bool Update(const OLEVariant &FieldList,const OLEVariant &Values);
+ bool CancelUpdate();
+ WpADOProperties get_Properties() const;
+ bool NextRecordset(OLEVariant& RecordsAffected,ADORecordset** ppiRset);
+ bool get_RecordCount(ADO_LONGPTR &_nRet) const;
+ bool get_MaxRecords(ADO_LONGPTR &_nRet) const;
+ bool put_MaxRecords(ADO_LONGPTR _nRet);
+ bool get_CursorType(CursorTypeEnum &_nRet) const;
+ bool put_CursorType(CursorTypeEnum _nRet);
+ bool get_LockType(LockTypeEnum &_nRet) const;
+ bool put_LockType(LockTypeEnum _nRet);
+ bool get_CacheSize(sal_Int32 &_nRet) const;
+ bool put_CacheSize(sal_Int32 _nRet);
+ bool UpdateBatch(AffectEnum AffectRecords);
+ };
+
+
+ class WpADOParameter:public WpOLEBase<ADOParameter>
+ {
+ public:
+ // Ctors, operator=
+ // They only call the superclass
+ WpADOParameter() = default;
+ WpADOParameter(const WpADOParameter& rhs):WpOLEBase<ADOParameter>(rhs){}
+ WpADOParameter& operator=(const WpADOParameter& rhs)
+ {WpOLEBase<ADOParameter>::operator=(rhs); return *this;}
+
+
+ OUString GetName() const ;
+ DataTypeEnum GetADOType() const ;
+ void put_Type(const DataTypeEnum& _eType);
+ bool put_Size(sal_Int32 _nSize);
+ sal_Int32 GetAttributes() const ;
+ sal_Int32 GetPrecision() const ;
+ sal_Int32 GetNumericScale() const ;
+ ParameterDirectionEnum get_Direction() const;
+ void GetValue(OLEVariant& aValVar) const ;
+ OLEVariant GetValue() const;
+ bool PutValue(const OLEVariant& aVariant);
+ bool AppendChunk(const OLEVariant& aVariant);
+ };
+
+ class OTools
+ {
+ public:
+ /** putValue set the property value at the ado column
+ @param _rProps the properties where to set
+ @param _aPosition which property to set
+ @param _aValVar the value to set
+ */
+ static void putValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition,const OLEVariant &_aValVar);
+
+ /** getValue returns a specific property value
+ @param _rProps the properties where to set
+ @param _aPosition the property
+
+ @return the property value
+ */
+ static OLEVariant getValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/Awrapadox.hxx b/connectivity/source/inc/ado/Awrapadox.hxx
new file mode 100644
index 000000000..ba91422a1
--- /dev/null
+++ b/connectivity/source/inc/ado/Awrapadox.hxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#ifndef __User_FWD_DEFINED__
+#define __User_FWD_DEFINED__
+typedef struct _ADOUser User;
+#endif
+
+#ifndef __Group_FWD_DEFINED__
+#define __Group_FWD_DEFINED__
+typedef struct _ADOGroup Group;
+#endif
+
+#ifndef __Column_FWD_DEFINED__
+#define __Column_FWD_DEFINED__
+typedef struct _ADOColumn Column;
+#endif
+
+#ifndef __Index_FWD_DEFINED__
+#define __Index_FWD_DEFINED__
+typedef struct _ADOIndex Index;
+#endif
+
+#ifndef __Key_FWD_DEFINED__
+#define __Key_FWD_DEFINED__
+typedef struct _ADOKey Key;
+#endif
+
+#ifndef __Table_FWD_DEFINED__
+#define __Table_FWD_DEFINED__
+typedef struct _ADOTable Table;
+#endif
+
+
+#include <adoint.h>
+#include <adoctint.h>
+
+
+#include <ado/Aolewrap.hxx>
+#include <ado/Aolevariant.hxx>
+#include <ado/adoimp.hxx>
+#include <ado/Awrapado.hxx>
+#include <ado/WrapColumn.hxx>
+#include <ado/WrapIndex.hxx>
+#include <ado/WrapKey.hxx>
+#include <ado/WrapTable.hxx>
+#include <ado/WrapCatalog.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOView : public WpOLEBase<ADOView>
+ {
+ public:
+ WpADOView(ADOView* pInt=nullptr) : WpOLEBase<ADOView>(pInt){}
+ WpADOView(const WpADOView& rhs) : WpOLEBase<ADOView>(rhs) {}
+
+ WpADOView& operator=(const WpADOView& rhs)
+ {WpOLEBase<ADOView>::operator=(rhs); return *this;}
+
+ OUString get_Name() const;
+ void get_Command(OLEVariant& _rVar) const;
+ void put_Command(OLEVariant const & _rVar);
+ };
+
+ class WpADOGroup : public WpOLEBase<ADOGroup>
+ {
+ public:
+ WpADOGroup() = default;
+ WpADOGroup(const WpADOGroup& rhs) : WpOLEBase<ADOGroup>(rhs) {}
+
+ WpADOGroup& operator=(const WpADOGroup& rhs)
+ {WpOLEBase<ADOGroup>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ RightsEnum GetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType);
+ bool SetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType,
+ /* [in] */ ActionEnum Action,
+ /* [in] */ RightsEnum Rights);
+ WpADOUsers get_Users( );
+ };
+
+ class WpADOUser : public WpOLEBase<_ADOUser>
+ {
+ public:
+ WpADOUser() = default;
+ WpADOUser(const WpADOUser& rhs) : WpOLEBase<_ADOUser>(rhs) {}
+
+ WpADOUser& operator=(const WpADOUser& rhs)
+ {WpOLEBase<_ADOUser>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ bool ChangePassword(std::u16string_view _rPwd,std::u16string_view _rNewPwd);
+ WpADOGroups get_Groups();
+ RightsEnum GetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType);
+ bool SetPermissions(
+ /* [in] */ const OLEVariant& Name,
+ /* [in] */ ObjectTypeEnum ObjectType,
+ /* [in] */ ActionEnum Action,
+ /* [in] */ RightsEnum Rights);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapCatalog.hxx b/connectivity/source/inc/ado/WrapCatalog.hxx
new file mode 100644
index 000000000..0bcff441c
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapCatalog.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/WrapTypeDefs.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOCatalog : public WpOLEBase<_ADOCatalog>
+ {
+ public:
+ WpADOCatalog(_ADOCatalog* pInt = nullptr) : WpOLEBase<_ADOCatalog>(pInt){}
+ WpADOCatalog(const WpADOCatalog& rhs) : WpOLEBase<_ADOCatalog>(rhs) {}
+
+ WpADOCatalog& operator=(const WpADOCatalog& rhs)
+ {WpOLEBase<_ADOCatalog>::operator=(rhs); return *this;}
+
+ OUString GetObjectOwner(std::u16string_view _rName, ObjectTypeEnum _eNum);
+
+ void putref_ActiveConnection(IDispatch* pCon);
+ WpADOTables get_Tables();
+ WpADOViews get_Views();
+ WpADOGroups get_Groups();
+ WpADOUsers get_Users();
+ ADOProcedures* get_Procedures();
+ void Create();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapColumn.hxx b/connectivity/source/inc/ado/WrapColumn.hxx
new file mode 100644
index 000000000..f1b73585f
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapColumn.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/Aolewrap.hxx>
+
+#include <adoint.h>
+
+namespace connectivity::ado
+{
+ class WpADOColumn : public WpOLEBase<_ADOColumn>
+ {
+ public:
+ WpADOColumn() = default;
+ WpADOColumn(const WpADOColumn& rhs) : WpOLEBase<_ADOColumn>(rhs) {}
+
+ void Create();
+
+ WpADOColumn& operator=(const WpADOColumn& rhs)
+ {WpOLEBase<_ADOColumn>::operator=(rhs); return *this;}
+
+ OUString get_Name() const;
+ OUString get_RelatedColumn() const;
+ void put_Name(std::u16string_view _rName);
+ void put_RelatedColumn(std::u16string_view _rName);
+ DataTypeEnum get_Type() const;
+ void put_Type(const DataTypeEnum& _eNum) ;
+ sal_Int32 get_Precision() const;
+ void put_Precision(sal_Int32 _nPre) ;
+ sal_uInt8 get_NumericScale() const;
+ void put_NumericScale(sal_Int8 _nScale);
+ SortOrderEnum get_SortOrder() const;
+ void put_SortOrder(SortOrderEnum _nScale);
+ sal_Int32 get_DefinedSize() const;
+ ColumnAttributesEnum get_Attributes() const;
+ bool put_Attributes(const ColumnAttributesEnum& _eNum);
+ WpADOProperties get_Properties() const;
+ void put_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapIndex.hxx b/connectivity/source/inc/ado/WrapIndex.hxx
new file mode 100644
index 000000000..4444bb340
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapIndex.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/WrapTypeDefs.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOIndex : public WpOLEBase<_ADOIndex>
+ {
+ public:
+ WpADOIndex() = default;
+ WpADOIndex(const WpADOIndex& rhs) : WpOLEBase<_ADOIndex>(rhs) {}
+
+ WpADOIndex& operator=(const WpADOIndex& rhs)
+ {WpOLEBase<_ADOIndex>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ bool get_Clustered() const;
+ void put_Clustered(bool _b);
+ bool get_Unique() const;
+ void put_Unique(bool _b);
+ bool get_PrimaryKey() const;
+ void put_PrimaryKey(bool _b);
+ WpADOColumns get_Columns() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapKey.hxx b/connectivity/source/inc/ado/WrapKey.hxx
new file mode 100644
index 000000000..1f984445b
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapKey.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/WrapTypeDefs.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOKey : public WpOLEBase<ADOKey>
+ {
+ public:
+ WpADOKey() = default;
+ WpADOKey(const WpADOKey& rhs) : WpOLEBase<ADOKey>(rhs) {}
+
+ WpADOKey& operator=(const WpADOKey& rhs)
+ {WpOLEBase<ADOKey>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ KeyTypeEnum get_Type() const;
+ void put_Type(const KeyTypeEnum& _eNum) ;
+ OUString get_RelatedTable() const;
+ void put_RelatedTable(std::u16string_view _rName);
+ RuleEnum get_DeleteRule() const;
+ void put_DeleteRule(const RuleEnum& _eNum) ;
+ RuleEnum get_UpdateRule() const;
+ void put_UpdateRule(const RuleEnum& _eNum) ;
+ WpADOColumns get_Columns() const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapTable.hxx b/connectivity/source/inc/ado/WrapTable.hxx
new file mode 100644
index 000000000..dc06dbc03
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapTable.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <ado/WrapTypeDefs.hxx>
+
+namespace connectivity::ado
+{
+ class WpADOCatalog;
+
+ class WpADOTable : public WpOLEBase<_ADOTable>
+ {
+ public:
+ WpADOTable() = default;
+ WpADOTable(const WpADOTable& rhs) : WpOLEBase<_ADOTable>(rhs) {}
+
+ WpADOTable& operator=(const WpADOTable& rhs)
+ {WpOLEBase<_ADOTable>::operator=(rhs); return *this;}
+
+ void Create();
+
+ OUString get_Name() const;
+ void put_Name(std::u16string_view _rName);
+ OUString get_Type() const;
+ WpADOColumns get_Columns() const;
+ WpADOIndexes get_Indexes() const;
+ WpADOKeys get_Keys() const;
+ WpADOCatalog get_ParentCatalog() const;
+ WpADOProperties get_Properties() const;
+ void putref_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject);
+ };
+
+
+ typedef WpOLEAppendCollection<ADOTables, WpADOTable> WpADOTables;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/WrapTypeDefs.hxx b/connectivity/source/inc/ado/WrapTypeDefs.hxx
new file mode 100644
index 000000000..91bea8453
--- /dev/null
+++ b/connectivity/source/inc/ado/WrapTypeDefs.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+
+namespace connectivity::ado
+{
+ class WpADOTable;
+ class WpADOKey;
+ class WpADOIndex;
+ class WpADOColumn;
+ class WpADOGroup;
+ class WpADOView;
+ class WpADOUser;
+
+ typedef WpOLEAppendCollection<ADOTables, WpADOTable> WpADOTables;
+ typedef WpOLEAppendCollection<ADOKeys, WpADOKey> WpADOKeys;
+ typedef WpOLEAppendCollection<ADOIndexes, WpADOIndex> WpADOIndexes;
+ typedef WpOLEAppendCollection<ADOColumns, WpADOColumn> WpADOColumns;
+ typedef WpOLEAppendCollection<ADOGroups, WpADOGroup> WpADOGroups;
+ typedef WpOLEAppendCollection<ADOViews, WpADOView> WpADOViews;
+ typedef WpOLEAppendCollection<ADOUsers, WpADOUser> WpADOUsers;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/ado/adoimp.hxx b/connectivity/source/inc/ado/adoimp.hxx
new file mode 100644
index 000000000..60c6fd313
--- /dev/null
+++ b/connectivity/source/inc/ado/adoimp.hxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <adoctint.h>
+
+struct ADOConnection;
+
+namespace sal::systools { class BStr; };
+
+namespace connectivity::ado
+{
+
+ class WpADOField;
+ class ADOS
+ {
+ public:
+ // Also here: Free BSTR with SysFreeString()!
+ static sal::systools::BStr& GetKeyStr();
+
+ static const CLSID CLSID_ADOCATALOG_25;
+ static const IID IID_ADOCATALOG_25;
+
+ static const CLSID CLSID_ADOCONNECTION_21;
+ static const IID IID_ADOCONNECTION_21;
+
+ static const CLSID CLSID_ADOCOMMAND_21;
+ static const IID IID_ADOCOMMAND_21;
+
+ static const CLSID CLSID_ADORECORDSET_21;
+ static const IID IID_ADORECORDSET_21;
+
+ static const CLSID CLSID_ADOINDEX_25;
+ static const IID IID_ADOINDEX_25;
+
+ static const CLSID CLSID_ADOCOLUMN_25;
+ static const IID IID_ADOCOLUMN_25;
+
+ static const CLSID CLSID_ADOKEY_25;
+ static const IID IID_ADOKEY_25;
+
+ static const CLSID CLSID_ADOTABLE_25;
+ static const IID IID_ADOTABLE_25;
+
+ static const CLSID CLSID_ADOGROUP_25;
+ static const IID IID_ADOGROUP_25;
+
+ static const CLSID CLSID_ADOUSER_25;
+ static const IID IID_ADOUSER_25;
+
+ static const CLSID CLSID_ADOVIEW_25;
+ static const IID IID_ADOVIEW_25;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void ThrowException(ADOConnection* _pAdoCon,const css::uno::Reference< css::uno::XInterface >& _xInterface);
+ static sal_Int32 MapADOType2Jdbc(DataTypeEnum eType);
+ static DataTypeEnum MapJdbc2ADOType(sal_Int32 _nType,sal_Int32 _nJetEngine);
+ static bool isJetEngine(sal_Int32 _nEngineType);
+
+ static ObjectTypeEnum mapObjectType2Ado(sal_Int32 objType);
+ static sal_Int32 mapAdoType2Object(ObjectTypeEnum objType);
+ static sal_Int32 mapAdoRights2Sdbc(RightsEnum eRights);
+ static sal_Int32 mapRights2Ado(sal_Int32 nRights);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static WpADOField getField(ADORecordset* _pRecordSet,sal_Int32 _nColumnIndex);
+ };
+
+
+}
+
+
+#define ADO_PROP(ItemName) \
+ WpADOProperty aProp(aProps.GetItem(ItemName)); \
+ OLEVariant aVar; \
+ if(aProp.IsValid()) \
+ aVar = aProp.GetValue(); \
+ else \
+ ADOS::ThrowException(m_rADOConnection,*this);
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CCatalog.hxx b/connectivity/source/inc/calc/CCatalog.hxx
new file mode 100644
index 000000000..466e96ece
--- /dev/null
+++ b/connectivity/source/inc/calc/CCatalog.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FCatalog.hxx>
+
+namespace connectivity::calc
+{
+ class OCalcConnection;
+ class OCalcCatalog : public file::OFileCatalog
+ {
+ public:
+ virtual void refreshTables() override;
+
+ public:
+ OCalcCatalog(OCalcConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CConnection.hxx b/connectivity/source/inc/calc/CConnection.hxx
new file mode 100644
index 000000000..6eabeccef
--- /dev/null
+++ b/connectivity/source/inc/calc/CConnection.hxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <file/FConnection.hxx>
+#include <com/sun/star/frame/XDesktop2.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <rtl/ref.hxx>
+#include <unotools/closeveto.hxx>
+
+namespace com::sun::star {
+ namespace sheet { class XSpreadsheetDocument; }
+}
+
+namespace utl { class CloseVeto; }
+
+
+namespace connectivity::calc
+ {
+ class ODriver;
+ class OCalcConnection : public file::OConnection
+ {
+ // the spreadsheet document:
+ css::uno::Reference< css::sheet::XSpreadsheetDocument > m_xDoc;
+ OUString m_sPassword;
+ OUString m_aFileName;
+ oslInterlockedCount m_nDocCount;
+
+ class CloseVetoButTerminateListener : public cppu::WeakComponentImplHelper<css::frame::XTerminateListener>
+ {
+ private:
+ /// close listener that vetoes so nobody else disposes m_xDoc
+ std::unique_ptr<utl::CloseVeto> m_pCloseListener;
+ /// but also listen to XDesktop and if app is terminating anyway, dispose m_xDoc while
+ /// its still possible to do so properly
+ css::uno::Reference<css::frame::XDesktop2> m_xDesktop;
+ osl::Mutex m_aMutex;
+ public:
+ CloseVetoButTerminateListener()
+ : cppu::WeakComponentImplHelper<css::frame::XTerminateListener>(m_aMutex)
+ {
+ }
+
+ void start(const css::uno::Reference<css::uno::XInterface>& rCloseable,
+ const css::uno::Reference<css::frame::XDesktop2>& rDesktop)
+ {
+ m_xDesktop = rDesktop;
+ m_xDesktop->addTerminateListener(this);
+ m_pCloseListener.reset(new utl::CloseVeto(rCloseable, true));
+ }
+
+ void stop()
+ {
+ m_pCloseListener.reset();
+ if (!m_xDesktop.is())
+ return;
+ m_xDesktop->removeTerminateListener(this);
+ m_xDesktop.clear();
+ }
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination(const css::lang::EventObject& /*rEvent*/) override
+ {
+ }
+
+ virtual void SAL_CALL notifyTermination(const css::lang::EventObject& /*rEvent*/) override
+ {
+ stop();
+ }
+
+ virtual void SAL_CALL disposing() override
+ {
+ stop();
+ cppu::WeakComponentImplHelperBase::disposing();
+ }
+
+ virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override
+ {
+ const bool bShutDown = (rEvent.Source == m_xDesktop);
+ if (bShutDown)
+ stop();
+ }
+ };
+
+ rtl::Reference<CloseVetoButTerminateListener> m_xCloseVetoButTerminateListener;
+
+ public:
+ OCalcConnection(ODriver* _pDriver);
+ virtual ~OCalcConnection() override;
+
+ virtual void construct(const OUString& _rUrl,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rInfo ) override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override;
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+
+ // no interface methods
+ css::uno::Reference< css::sheet::XSpreadsheetDocument> const & acquireDoc();
+ void releaseDoc();
+
+ class ODocHolder
+ {
+ OCalcConnection* m_pConnection;
+ css::uno::Reference< css::sheet::XSpreadsheetDocument> m_xDoc;
+ public:
+ ODocHolder(OCalcConnection* _pConnection) : m_pConnection(_pConnection)
+ {
+ m_xDoc = m_pConnection->acquireDoc();
+ }
+ ~ODocHolder()
+ {
+ m_xDoc.clear();
+ m_pConnection->releaseDoc();
+ }
+ const css::uno::Reference< css::sheet::XSpreadsheetDocument>& getDoc() const { return m_xDoc; }
+ };
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CDatabaseMetaData.hxx b/connectivity/source/inc/calc/CDatabaseMetaData.hxx
new file mode 100644
index 000000000..61f9f6aa7
--- /dev/null
+++ b/connectivity/source/inc/calc/CDatabaseMetaData.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <component/CDatabaseMetaData.hxx>
+
+namespace connectivity::calc
+ {
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class OCalcDatabaseMetaData : public component::OComponentDatabaseMetaData
+ {
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ protected:
+ virtual ~OCalcDatabaseMetaData() override;
+ public:
+ OCalcDatabaseMetaData(file::OConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CDriver.hxx b/connectivity/source/inc/calc/CDriver.hxx
new file mode 100644
index 000000000..99200d23e
--- /dev/null
+++ b/connectivity/source/inc/calc/CDriver.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDriver.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+namespace connectivity::calc
+ {
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::uno::XInterface >
+ ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory);
+
+ class ODriver : public file::OFileDriver
+ {
+ public:
+ ODriver(const css::uno::Reference<
+ css::uno::XComponentContext >& _rxContext) :
+ file::OFileDriver(_rxContext) {}
+
+ OUString SAL_CALL getImplementationName( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL
+ connect( const OUString& url, const css::uno::Sequence<
+ css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CTable.hxx b/connectivity/source/inc/calc/CTable.hxx
new file mode 100644
index 000000000..2c0e1d0e8
--- /dev/null
+++ b/connectivity/source/inc/calc/CTable.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <component/CTable.hxx>
+#include <tools/date.hxx>
+
+namespace com::sun::star::sheet {
+ class XSpreadsheet;
+}
+
+namespace com::sun::star::util {
+ class XNumberFormats;
+}
+
+
+namespace connectivity::calc
+ {
+ typedef component::OComponentTable OCalcTable_BASE;
+ class OCalcConnection;
+
+ class OCalcTable : public OCalcTable_BASE
+ {
+ private:
+ std::vector<sal_Int32> m_aTypes; // holds all type for columns just to avoid to ask the propertyset
+ css::uno::Reference< css::sheet::XSpreadsheet > m_xSheet;
+ OCalcConnection* m_pCalcConnection;
+ sal_Int32 m_nStartCol;
+ sal_Int32 m_nStartRow;
+ sal_Int32 m_nDataCols;
+ bool m_bHasHeaders;
+ css::uno::Reference< css::util::XNumberFormats > m_xFormats;
+ ::Date m_aNullDate;
+
+ void fillColumns();
+
+ public:
+ OCalcTable( sdbcx::OCollection* _pTables,OCalcConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description = OUString(),
+ const OUString& SchemaName = OUString(),
+ const OUString& CatalogName = OUString()
+ );
+
+ virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override;
+
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ void construct() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/calc/CTables.hxx b/connectivity/source/inc/calc/CTables.hxx
new file mode 100644
index 000000000..0b88592a2
--- /dev/null
+++ b/connectivity/source/inc/calc/CTables.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTables.hxx>
+
+namespace connectivity::calc
+ {
+ typedef file::OTables OCalcTables_BASE;
+
+ class OCalcTables : public OCalcTables_BASE
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ public:
+ OCalcTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : OCalcTables_BASE(_rMetaData,_rParent,_rMutex,_rVector)
+ {}
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CColumns.hxx b/connectivity/source/inc/component/CColumns.hxx
new file mode 100644
index 000000000..a63cae4bd
--- /dev/null
+++ b/connectivity/source/inc/component/CColumns.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FColumns.hxx>
+
+namespace connectivity::component
+ {
+ /// Columns implementation for Writer tables and Calc sheets.
+ class OComponentColumns : public file::OColumns
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ public:
+ OComponentColumns(file::OFileTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : file::OColumns(_pTable,_rMutex,_rVector)
+ {}
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CDatabaseMetaData.hxx b/connectivity/source/inc/component/CDatabaseMetaData.hxx
new file mode 100644
index 000000000..c4721ecad
--- /dev/null
+++ b/connectivity/source/inc/component/CDatabaseMetaData.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDatabaseMetaData.hxx>
+
+namespace connectivity::component
+ {
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class OOO_DLLPUBLIC_FILE OComponentDatabaseMetaData : public file::ODatabaseMetaData
+ {
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ protected:
+ virtual ~OComponentDatabaseMetaData() override;
+ public:
+ OComponentDatabaseMetaData(file::OConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CPreparedStatement.hxx b/connectivity/source/inc/component/CPreparedStatement.hxx
new file mode 100644
index 000000000..d39a3edad
--- /dev/null
+++ b/connectivity/source/inc/component/CPreparedStatement.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FPreparedStatement.hxx>
+
+namespace connectivity::component
+ {
+ class OConnection;
+ /// Prepared statement implementation for Writer tables and Calc sheets.
+ class OOO_DLLPUBLIC_FILE OComponentPreparedStatement : public file::OPreparedStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ OComponentPreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CResultSet.hxx b/connectivity/source/inc/component/CResultSet.hxx
new file mode 100644
index 000000000..4874f2215
--- /dev/null
+++ b/connectivity/source/inc/component/CResultSet.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <file/FResultSet.hxx>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/implbase2.hxx>
+
+namespace connectivity::component
+ {
+ class OComponentResultSet;
+ // these typedef's are only necessary for the compiler
+ typedef ::cppu::ImplHelper2< css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows> OComponentResultSet_BASE;
+ typedef file::OResultSet OComponentResultSet_BASE2;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OComponentResultSet> OComponentResultSet_BASE3;
+
+
+ /// ResultSet implementation for Writer tables and Calc sheets.
+ class OComponentResultSet : public OComponentResultSet_BASE2,
+ public OComponentResultSet_BASE,
+ public OComponentResultSet_BASE3
+ {
+ bool m_bBookmarkable;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex) override;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ OComponentResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator);
+
+ private:
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ virtual bool isRowDeleted() const override { return false; }
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CStatement.hxx b/connectivity/source/inc/component/CStatement.hxx
new file mode 100644
index 000000000..10346e7c8
--- /dev/null
+++ b/connectivity/source/inc/component/CStatement.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FStatement.hxx>
+
+namespace connectivity::component
+ {
+ class OConnection;
+ /// Statement implementation for Writer tables and Calc sheets.
+ class OOO_DLLPUBLIC_FILE OComponentStatement : public file::OStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ OComponentStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/component/CTable.hxx b/connectivity/source/inc/component/CTable.hxx
new file mode 100644
index 000000000..3ace6f922
--- /dev/null
+++ b/connectivity/source/inc/component/CTable.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTable.hxx>
+
+namespace com::sun::star::sheet {
+ class XSpreadsheet;
+}
+
+namespace com::sun::star::util {
+ class XNumberFormats;
+}
+
+
+namespace connectivity::component
+ {
+ typedef file::OFileTable OComponentTable_BASE;
+
+ /// Shared Table base class for Writer tables and Calc sheets.
+ class OOO_DLLPUBLIC_FILE OComponentTable : public OComponentTable_BASE
+ {
+ protected:
+ sal_Int32 m_nDataRows;
+
+ virtual void FileClose() override;
+ public:
+ OComponentTable( sdbcx::OCollection* _pTables,file::OConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ );
+
+ virtual void refreshColumns() override;
+ virtual void refreshIndexes() override;
+
+ virtual sal_Int32 getCurrentLastPos() const override;
+ virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override;
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DCatalog.hxx b/connectivity/source/inc/dbase/DCatalog.hxx
new file mode 100644
index 000000000..f8954d012
--- /dev/null
+++ b/connectivity/source/inc/dbase/DCatalog.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FCatalog.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseConnection;
+ class ODbaseCatalog : public file::OFileCatalog
+ {
+ public:
+ virtual void refreshTables() override;
+
+ public:
+ ODbaseCatalog(ODbaseConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DColumns.hxx b/connectivity/source/inc/dbase/DColumns.hxx
new file mode 100644
index 000000000..dbbbbec90
--- /dev/null
+++ b/connectivity/source/inc/dbase/DColumns.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FColumns.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseColumns : public file::OColumns
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ ODbaseColumns(file::OFileTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : file::OColumns(_pTable,_rMutex,_rVector)
+ {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DConnection.hxx b/connectivity/source/inc/dbase/DConnection.hxx
new file mode 100644
index 000000000..864e9a22c
--- /dev/null
+++ b/connectivity/source/inc/dbase/DConnection.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FConnection.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODriver;
+ class ODbaseConnection : public file::OConnection
+ {
+ protected:
+ virtual ~ODbaseConnection() override;
+ public:
+ ODbaseConnection(ODriver* _pDriver);
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override;
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DDatabaseMetaData.hxx b/connectivity/source/inc/dbase/DDatabaseMetaData.hxx
new file mode 100644
index 000000000..fed3fcc70
--- /dev/null
+++ b/connectivity/source/inc/dbase/DDatabaseMetaData.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDatabaseMetaData.hxx>
+
+namespace connectivity::dbase
+ {
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class ODbaseDatabaseMetaData : public file::ODatabaseMetaData
+ {
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+
+ virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override;
+ virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override;
+
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override;
+ protected:
+ virtual ~ODbaseDatabaseMetaData() override;
+ public:
+ ODbaseDatabaseMetaData(file::OConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DDriver.hxx b/connectivity/source/inc/dbase/DDriver.hxx
new file mode 100644
index 000000000..310f9b1dc
--- /dev/null
+++ b/connectivity/source/inc/dbase/DDriver.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <file/FDriver.hxx>
+
+namespace connectivity::dbase
+ {
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::uno::XInterface > ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory);
+
+ class ODriver : public file::OFileDriver
+ {
+ public:
+ ODriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) : file::OFileDriver(_rxContext){}
+
+ OUString SAL_CALL getImplementationName( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DIndex.hxx b/connectivity/source/inc/dbase/DIndex.hxx
new file mode 100644
index 000000000..cd18ded0c
--- /dev/null
+++ b/connectivity/source/inc/dbase/DIndex.hxx
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VIndex.hxx>
+#include <dbase/DTable.hxx>
+#include <dbase/dindexnode.hxx>
+
+inline constexpr OStringLiteral dBASE_III_GROUP = "dBase III";
+
+namespace connectivity::dbase
+ {
+ class OIndexIterator;
+ class ONDXKey;
+
+ typedef sdbcx::OIndex ODbaseIndex_BASE;
+
+ class ODbaseIndex : public ODbaseIndex_BASE
+ {
+ friend SvStream& WriteODbaseIndex(SvStream &rStream, const ODbaseIndex&);
+ friend SvStream& operator >> (SvStream &rStream, ODbaseIndex&);
+
+ friend class ONDXNode;
+ friend class ONDXPage;
+ friend class ONDXPagePtr;
+ friend class OIndexIterator;
+
+ public:
+
+ // Header struct - stays in memory
+
+ struct NDXHeader
+ {
+ sal_uInt32 db_rootpage; /* Rootpage position */
+ sal_uInt32 db_pagecount; /* Page count */
+ sal_uInt8 db_free[4]; /* Reserved */
+ sal_uInt16 db_keylen; /* Key length */
+ sal_uInt16 db_maxkeys; /* Maximum number of keys per page */
+ sal_uInt16 db_keytype; /* Type of key:
+ 0 = Text
+ 1 = Numerical */
+ sal_uInt16 db_keyrec; /* Length of an index record
+ RecordNumber + keylen */
+ sal_uInt8 db_free1[3]; /* Reserved */
+ sal_uInt8 db_unique; /* Unique */
+ char db_name[488]; /* index_name (field name) */
+ };
+
+ private:
+ std::unique_ptr<SvStream> m_pFileStream; // Stream to read/write the index
+ NDXHeader m_aHeader = {};
+ std::vector<ONDXPage*>
+ m_aCollector; // Pool of obsolete pages
+ ONDXPagePtr m_aRoot, // Root of the B+ tree
+ m_aCurLeaf; // Current leaf
+ sal_uInt16 m_nCurNode; // Position of the current node
+
+ sal_uInt32 m_nPageCount,
+ m_nRootPage;
+
+ ODbaseTable* m_pTable;
+ bool m_bUseCollector : 1; // Use the Garbage Collector
+
+ OUString getCompletePath() const;
+ void closeImpl();
+ // Closes and kills the index file and throws an error
+ void impl_killFileAndthrowError_throw(TranslateId pErrorId, const OUString& _sFile);
+ protected:
+ virtual ~ODbaseIndex() override;
+ public:
+ ODbaseIndex(ODbaseTable* _pTable);
+ ODbaseIndex(ODbaseTable* _pTable,const NDXHeader& _aHeader,const OUString& Name);
+
+ void openIndexFile();
+ virtual void refreshColumns() override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ const ODbaseTable* getTable() const { return m_pTable; }
+ const NDXHeader& getHeader() const { return m_aHeader; }
+ std::unique_ptr<OIndexIterator> createIterator();
+
+ void SetRootPos(sal_uInt32 nPos) {m_nRootPage = nPos;}
+ void SetPageCount(sal_uInt32 nCount) {m_nPageCount = nCount;}
+
+ sal_uInt32 GetPageCount() const {return m_nPageCount;}
+
+ sal_uInt16 GetMaxNodes() const {return m_aHeader.db_maxkeys;}
+
+ bool Insert(sal_uInt32 nRec, const ORowSetValue& rValue);
+ bool Update(sal_uInt32 nRec, const ORowSetValue&, const ORowSetValue&);
+ bool Delete(sal_uInt32 nRec, const ORowSetValue& rValue);
+ bool Find(sal_uInt32 nRec, const ORowSetValue& rValue);
+
+ void createINFEntry();
+ void CreateImpl();
+ void DropImpl();
+
+ DECLARE_SERVICE_INFO();
+ protected:
+
+ ONDXPage* CreatePage(sal_uInt32 nPagePos, ONDXPage* pParent = nullptr, bool bLoad = false);
+ void Collect(ONDXPage*);
+ ONDXPagePtr const & getRoot();
+
+ bool isUnique() const { return m_IsUnique; }
+ bool UseCollector() const {return m_bUseCollector;}
+ // Tree operations
+ void Release(bool bSave = true);
+ bool ConvertToKey(ONDXKey* rKey, sal_uInt32 nRec, const ORowSetValue& rValue);
+ };
+
+ SvStream& WriteODbaseIndex(SvStream &rStream, const ODbaseIndex&);
+ SvStream& operator >> (SvStream &rStream, ODbaseIndex&);
+
+ void ReadHeader(SvStream & rStream, ODbaseIndex::NDXHeader & rHeader);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DIndexColumns.hxx b/connectivity/source/inc/dbase/DIndexColumns.hxx
new file mode 100644
index 000000000..8f7a895b9
--- /dev/null
+++ b/connectivity/source/inc/dbase/DIndexColumns.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <dbase/DIndex.hxx>
+#include <dbase/DTable.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseIndexColumns : public sdbcx::OCollection
+ {
+ ODbaseIndex* m_pIndex;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ public:
+ ODbaseIndexColumns( ODbaseIndex* _pIndex,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector)
+ : sdbcx::OCollection(*_pIndex,_pIndex->getTable()->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector)
+ , m_pIndex(_pIndex)
+ {}
+
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DIndexIter.hxx b/connectivity/source/inc/dbase/DIndexIter.hxx
new file mode 100644
index 000000000..2de327be1
--- /dev/null
+++ b/connectivity/source/inc/dbase/DIndexIter.hxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcode.hxx>
+#include <dbase/DIndex.hxx>
+#include <dbase/dindexnode.hxx>
+
+namespace connectivity::dbase
+ {
+
+ // IndexIterator
+
+ class OIndexIterator final
+ {
+ file::OBoolOperator* m_pOperator;
+ const file::OOperand* m_pOperand;
+ rtl::Reference<ODbaseIndex> m_xIndex;
+ ONDXPagePtr m_aRoot,
+ m_aCurLeaf;
+ sal_uInt16 m_nCurNode;
+
+ sal_uInt32 Find(bool bFirst);
+ sal_uInt32 GetCompare(bool bFirst);
+ sal_uInt32 GetLike(bool bFirst);
+ sal_uInt32 GetNull(bool bFirst);
+ sal_uInt32 GetNotNull(bool bFirst);
+
+ ONDXKey* GetFirstKey(ONDXPage* pPage,
+ const file::OOperand& rKey);
+ ONDXKey* GetNextKey();
+
+ public:
+ OIndexIterator(ODbaseIndex* pInd)
+ :m_pOperator(nullptr)
+ ,m_pOperand(nullptr)
+ ,m_xIndex(pInd)
+ ,m_nCurNode(NODE_NOTFOUND)
+ {
+ }
+
+ ~OIndexIterator();
+ sal_uInt32 First();
+ sal_uInt32 Next();
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DIndexes.hxx b/connectivity/source/inc/dbase/DIndexes.hxx
new file mode 100644
index 000000000..a5b1c27e6
--- /dev/null
+++ b/connectivity/source/inc/dbase/DIndexes.hxx
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <dbase/DTable.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseTable;
+
+ typedef sdbcx::OCollection ODbaseIndexes_BASE;
+
+ class ODbaseIndexes : public ODbaseIndexes_BASE
+ {
+ ODbaseTable* m_pTable;
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ ODbaseIndexes(ODbaseTable* _pTable, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : ODbaseIndexes_BASE(*_pTable,_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector)
+ , m_pTable(_pTable)
+ {}
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DPreparedStatement.hxx b/connectivity/source/inc/dbase/DPreparedStatement.hxx
new file mode 100644
index 000000000..a2a792f62
--- /dev/null
+++ b/connectivity/source/inc/dbase/DPreparedStatement.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FPreparedStatement.hxx>
+
+namespace connectivity::dbase
+ {
+ class OConnection;
+ class ODbasePreparedStatement : public file::OPreparedStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ ODbasePreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DResultSet.hxx b/connectivity/source/inc/dbase/DResultSet.hxx
new file mode 100644
index 000000000..106a63cbb
--- /dev/null
+++ b/connectivity/source/inc/dbase/DResultSet.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <file/FResultSet.hxx>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/implbase2.hxx>
+
+namespace connectivity::dbase
+ {
+ class ODbaseResultSet;
+ // these typedef's are only necessary for the compiler
+ typedef ::cppu::ImplHelper2< css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows> ODbaseResultSet_BASE;
+ typedef file::OResultSet ODbaseResultSet_BASE2;
+ typedef ::comphelper::OPropertyArrayUsageHelper<ODbaseResultSet> ODbaseResultSet_BASE3;
+
+
+ class ODbaseResultSet : public ODbaseResultSet_BASE2,
+ public ODbaseResultSet_BASE,
+ public ODbaseResultSet_BASE3
+ {
+ bool m_bBookmarkable;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex) override;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ ODbaseResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator);
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ // own methods
+ sal_Int32 getCurrentFilePos() const;
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DStatement.hxx b/connectivity/source/inc/dbase/DStatement.hxx
new file mode 100644
index 000000000..cb4b1d8e4
--- /dev/null
+++ b/connectivity/source/inc/dbase/DStatement.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FStatement.hxx>
+
+namespace connectivity::dbase
+ {
+ class OConnection;
+ class ODbaseStatement : public file::OStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ ODbaseStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DTable.hxx b/connectivity/source/inc/dbase/DTable.hxx
new file mode 100644
index 000000000..dd2e83361
--- /dev/null
+++ b/connectivity/source/inc/dbase/DTable.hxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTable.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <tools/urlobj.hxx>
+
+
+namespace connectivity::dbase
+ {
+ typedef file::OFileTable ODbaseTable_BASE;
+ class ODbaseConnection;
+
+ class ODbaseTable : public ODbaseTable_BASE
+ {
+ // The first byte of a dBase file specifies its type
+ public:
+ enum DBFType { dBaseIII = 0x03,
+ dBaseIV = 0x04,
+ dBaseV = 0x05,
+ VisualFoxPro = 0x30,
+ VisualFoxProAuto = 0x31, // Visual FoxPro with AutoIncrement field
+ dBaseFS = 0x43,
+ dBaseFSMemo = 0xB3,
+ dBaseIIIMemo = 0x83,
+ dBaseIVMemo = 0x8B,
+ dBaseIVMemoSQL = 0x8E,
+ FoxProMemo = 0xF5
+ };
+ enum DBFMemoType { MemodBaseIII = 0,
+ MemodBaseIV,
+ MemoFoxPro
+ };
+
+ private:
+ // sources: https://www.clicketyclick.dk/databases/xbase/format/dbf.html (dBASE III and 5)
+ // http://www.dbase.com/KnowledgeBase/int/db7_file_fmt.htm (dBASE 7) which is similar at least for this part
+ struct DBFHeader { // address/pos in trailer
+ DBFType type; // dBASE/xBASE type, see DBFType 00h
+ sal_uInt8 dateElems[3]; // Date of last change (YYMMDD) 01h
+ sal_uInt32 nbRecords; // Number of records 04h
+ sal_uInt16 headerLength; // 08h
+ sal_uInt16 recordLength; // Length of 1 record 10h
+ sal_uInt8 trailer[20];
+ // this last field contains these data:
+ // - reserved:2 bytes:should be filled with 0 12h/0
+ // - incomplete transaction:1 byte:dBASE IV 14h/2
+ // 00h Transaction ended (or rolled back)
+ // 01h Transaction started
+ // - encryptionFlag:1 byte: dBASE IV 15h/3
+ // 00h not encrypted
+ // 01h for encrypted
+ // - freeRecordThread:4 bytes:reserved for LAN only 16h/4
+ // - multiUserdBASE:8 bytes:reserved for multi-user dBASE (dBASE III+) 20h/8
+ // - MDXFlag:1 byte:dBASE IV 28h/16
+ // 0x01 if a production .MDX file exists for this table
+ // 0x00 if no .MDX file exists
+ // - languageDriver:1 byte:codepage (from Foxpro) 29h/17
+ // - reserved:2 bytes: should be filled with 0 30h/18
+ };
+ struct DBFColumn { /* Column descriptors */
+ sal_uInt8 db_fnm[11]; /* Field name */
+ sal_uInt8 db_typ; /* Field type */
+ sal_uInt32 db_adr; /* Field address */
+ sal_uInt8 db_flng; /* Field length */
+ sal_uInt8 db_dez; /* Decimal places for N */
+ sal_uInt8 db_free2[14]; /* Reserved */
+ };
+ struct DBFMemoHeader
+ {
+ DBFMemoType db_typ; /* File type */
+ sal_uInt32 db_next; /* Next free block */
+ sal_uInt16 db_size; /* Block size: dBase 3 fixed */
+ DBFMemoHeader()
+ : db_typ(MemodBaseIII)
+ , db_next(0)
+ , db_size(0)
+ {
+ }
+ };
+
+ std::vector<sal_Int32> m_aTypes; // holds all types for columns just to avoid to ask the propertyset
+ std::vector<sal_Int32> m_aPrecisions; // same as above
+ std::vector<sal_Int32> m_aScales;
+ std::vector<sal_Int32> m_aRealFieldLengths;
+ DBFHeader m_aHeader = {};
+ DBFMemoHeader m_aMemoHeader;
+ std::unique_ptr<SvStream> m_pMemoStream;
+ rtl_TextEncoding m_eEncoding;
+
+ void alterColumn(sal_Int32 index,
+ const css::uno::Reference< css::beans::XPropertySet>& descriptor ,
+ const css::uno::Reference< css::sdbcx::XDataDescriptorFactory>& xOldColumn );
+ void readHeader();
+ void fillColumns();
+ OUString createTempFile();
+ void copyData(ODbaseTable* _pNewTable,sal_Int32 _nPos);
+ bool CreateFile(const INetURLObject& aFile, bool& bCreateMemo);
+ bool CreateMemoFile(const INetURLObject& aFile);
+ bool HasMemoFields() const;
+ void ReadMemoHeader();
+ bool ReadMemo(std::size_t nBlockNo, ORowSetValue& aVariable);
+
+ void WriteMemo(const ORowSetValue& aVariable, std::size_t& rBlockNr);
+ bool WriteBuffer();
+ bool UpdateBuffer(OValueRefVector& rRow, const OValueRefRow& pOrgRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols, bool bForceAllFields);
+ css::uno::Reference< css::beans::XPropertySet> isUniqueByColumnName(sal_Int32 _nColumnPos);
+ bool AllocBuffer();
+
+ void throwInvalidDbaseFormat();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::container::ElementExistException
+ /// @throws css::uno::RuntimeException
+ void renameImpl( const OUString& newName );
+ void throwInvalidColumnType(TranslateId pErrorId, const OUString& _sColumnName);
+
+ protected:
+ virtual void FileClose() override;
+// using ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper;
+
+ public:
+ virtual void refreshColumns() override;
+ virtual void refreshIndexes() override;
+
+ public:
+ ODbaseTable( sdbcx::OCollection* _pTables,ODbaseConnection* _pConnection);
+ ODbaseTable( sdbcx::OCollection* _pTables,ODbaseConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description = OUString(),
+ const OUString& SchemaName = OUString(),
+ const OUString& CatalogName = OUString()
+ );
+
+ void construct() override; // can throw any exception
+
+ virtual sal_Int32 getCurrentLastPos() const override;
+ virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override;
+ virtual bool fetchRow(OValueRefRow& _rRow,const OSQLColumns& _rCols, bool bRetrieveData) override;
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void SAL_CALL alterColumnByIndex( sal_Int32 index, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ bool DropImpl();
+ bool CreateImpl();
+
+
+ virtual bool InsertRow(OValueRefVector& rRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols) override;
+ virtual bool DeleteRow(const OSQLColumns& _rCols) override;
+ virtual bool UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow,const css::uno::Reference< css::container::XIndexAccess>& _xCols) override;
+
+ virtual void addColumn(const css::uno::Reference< css::beans::XPropertySet>& descriptor) override;
+ virtual void dropColumn(sal_Int32 _nPos) override;
+
+ static OUString getEntry(file::OConnection const * _pConnection, std::u16string_view _sURL );
+ static bool Drop_Static(std::u16string_view _sUrl, bool _bHasMemoFields, sdbcx::OCollection* _pIndexes );
+
+ virtual void refreshHeader() override;
+
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/DTables.hxx b/connectivity/source/inc/dbase/DTables.hxx
new file mode 100644
index 000000000..c85a1ab3c
--- /dev/null
+++ b/connectivity/source/inc/dbase/DTables.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTables.hxx>
+
+namespace connectivity::dbase
+ {
+ typedef file::OTables ODbaseTables_BASE;
+
+ class ODbaseTables : public ODbaseTables_BASE
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ ODbaseTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : ODbaseTables_BASE(_rMetaData,_rParent,_rMutex,_rVector)
+ {}
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/dbase/dindexnode.hxx b/connectivity/source/inc/dbase/dindexnode.hxx
new file mode 100644
index 000000000..6000c3622
--- /dev/null
+++ b/connectivity/source/inc/dbase/dindexnode.hxx
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <file/fcode.hxx>
+#include <connectivity/FValue.hxx>
+#include <memory>
+
+#define NODE_NOTFOUND 0xFFFF
+#define DINDEX_PAGE_SIZE 512
+
+class SvStream;
+
+namespace connectivity::dbase
+ {
+
+ class ONDXNode;
+ class ODbaseIndex;
+
+ // Index Key
+
+ typedef file::OOperand ONDXKey_BASE;
+ class ONDXKey : public ONDXKey_BASE
+ {
+ friend class ONDXNode;
+ sal_uInt32 nRecord; /* Record pointer */
+ ORowSetValue xValue; /* Key values */
+
+ public:
+ ONDXKey();
+ ONDXKey(const ORowSetValue& rVal, sal_Int32 eType, sal_uInt32 nRec);
+ ONDXKey(const OUString& aStr, sal_uInt32 nRec);
+ ONDXKey(double aVal, sal_uInt32 nRec);
+
+ inline ONDXKey(const ONDXKey& rKey);
+
+ inline ONDXKey& operator= (const ONDXKey& rKey);
+ virtual void setValue(const ORowSetValue& _rVal) override;
+
+ virtual const ORowSetValue& getValue() const override;
+
+ sal_uInt32 GetRecord() const { return nRecord; }
+ void setRecord(sal_uInt32 _nRec) { nRecord = _nRec; }
+ void ResetRecord() { nRecord = 0; }
+
+ bool operator == (const ONDXKey& rKey) const;
+ bool operator != (const ONDXKey& rKey) const;
+ bool operator < (const ONDXKey& rKey) const;
+ bool operator <= (const ONDXKey& rKey) const;
+ bool operator > (const ONDXKey& rKey) const;
+
+ static bool IsText(sal_Int32 eType);
+
+ private:
+ int Compare(const ONDXKey& rKey) const;
+ };
+
+
+ class ONDXPage;
+
+ // Index Page Pointer
+ // This is ref-count pointer class
+ class ONDXPagePtr
+ {
+ friend SvStream& WriteONDXPagePtr(SvStream &rStream, const ONDXPagePtr&);
+ friend SvStream& operator >> (SvStream &rStream, ONDXPagePtr&);
+
+ ONDXPage* mpPage;
+ sal_uInt32 nPagePos; // Position in the index file
+
+ public:
+ ONDXPagePtr();
+ ONDXPagePtr(ONDXPagePtr&& rObj) noexcept;
+ ONDXPagePtr(ONDXPagePtr const & rRef);
+ ONDXPagePtr(ONDXPage* pRefPage);
+ ~ONDXPagePtr();
+ void Clear();
+ ONDXPagePtr& operator=(ONDXPagePtr const & rRef);
+ ONDXPagePtr& operator=(ONDXPagePtr && rRef);
+ bool Is() const { return mpPage != nullptr; }
+
+ ONDXPage * operator ->() const { assert(mpPage != nullptr); return mpPage; }
+ operator ONDXPage *() const { return mpPage; }
+
+ sal_uInt32 GetPagePos() const {return nPagePos;}
+ bool HasPage() const {return nPagePos != 0;}
+ };
+
+ // Index Page
+ // This is a ref-counted class, with re-cycling
+ class ONDXPage
+ {
+ friend class ODbaseIndex;
+ friend class ONDXPagePtr;
+
+ friend SvStream& WriteONDXPage(SvStream &rStream, const ONDXPage&);
+ friend SvStream& operator >> (SvStream &rStream, ONDXPage&);
+
+ // work around a clang 3.5 optimization bug: if the bNoDelete is *first*
+ // it mis-compiles "if (--nRefCount == 0)" and never deletes any object
+ unsigned int nRefCount : 31;
+ // the only reason this is not bool is because MSVC cannot handle mixed type bitfields
+ unsigned int bNoDelete : 1;
+ sal_uInt32 nPagePos; // Position in the index file
+ bool bModified : 1;
+ sal_uInt16 nCount;
+
+ ONDXPagePtr aParent, // Parent page
+ aChild; // Pointer to the right child page
+ ODbaseIndex& rIndex;
+ std::unique_ptr<ONDXNode[]>
+ ppNodes; // Array of nodes
+
+ public:
+ // Node operations
+ sal_uInt16 Count() const {return nCount;}
+
+ bool Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft = 0);
+ bool Insert(sal_uInt16 nIndex, ONDXNode& rNode);
+ bool Append(ONDXNode& rNode);
+ void Delete(sal_uInt16);
+ void Remove(sal_uInt16);
+ void Release(bool bSave = true);
+ void ReleaseFull();
+
+ // Split and merge
+ ONDXNode Split(ONDXPage& rPage);
+ void Merge(sal_uInt16 nParentNodePos, const ONDXPagePtr& xPage);
+
+ // Access operators
+ ONDXNode& operator[] (sal_uInt16 nPos);
+ const ONDXNode& operator[] (sal_uInt16 nPos) const;
+
+ bool IsRoot() const;
+ bool IsLeaf() const;
+ bool IsModified() const;
+ bool HasParent() const;
+
+ bool IsFull() const;
+
+ sal_uInt32 GetPagePos() const {return nPagePos;}
+ ONDXPagePtr& GetChild(ODbaseIndex const * pIndex = nullptr);
+
+ // Parent does not need to be reloaded
+ const ONDXPagePtr& GetParent() const;
+ ODbaseIndex& GetIndex() {return rIndex;}
+ const ODbaseIndex& GetIndex() const {return rIndex;}
+
+ // Setting the child, via reference to retain the PagePos
+ void SetChild(ONDXPagePtr aCh);
+ void SetParent(ONDXPagePtr aPa);
+
+ sal_uInt16 Search(const ONDXKey& rSearch);
+ sal_uInt16 Search(const ONDXPage* pPage);
+ void SearchAndReplace(const ONDXKey& rSearch, ONDXKey const & rReplace);
+
+ protected:
+ ONDXPage(ODbaseIndex& rIndex, sal_uInt32 nPos, ONDXPage*);
+ ~ONDXPage();
+
+ void ReleaseRef();
+ void QueryDelete();
+ void AddNextRef()
+ {
+ assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" );
+ ++nRefCount;
+ }
+ void AddFirstRef()
+ {
+ assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" );
+ if( bNoDelete )
+ bNoDelete = 0;
+ ++nRefCount;
+ }
+
+ void SetModified(bool bMod) {bModified = bMod;}
+ void SetPagePos(sal_uInt32 nPage) {nPagePos = nPage;}
+
+ bool Find(const ONDXKey&); // Descend recursively
+ sal_uInt16 FindPos(const ONDXKey& rKey) const;
+
+#if OSL_DEBUG_LEVEL > 1
+ void PrintPage();
+#endif
+ };
+
+ SvStream& WriteONDXPagePtr(SvStream &rStream, const ONDXPagePtr&);
+ SvStream& operator >> (SvStream &rStream, ONDXPagePtr&);
+
+ inline bool ONDXPage::IsRoot() const {return !aParent.Is();}
+ inline bool ONDXPage::IsLeaf() const {return !aChild.HasPage();}
+ inline bool ONDXPage::IsModified() const {return bModified;}
+ inline bool ONDXPage::HasParent() const {return aParent.Is();}
+ inline const ONDXPagePtr& ONDXPage::GetParent() const {return aParent;}
+
+ inline void ONDXPage::SetParent(ONDXPagePtr aPa = ONDXPagePtr())
+ {
+ aParent = aPa;
+ }
+
+ inline void ONDXPage::SetChild(ONDXPagePtr aCh = ONDXPagePtr())
+ {
+ aChild = aCh;
+ if (aChild.Is())
+ aChild->SetParent(this);
+ }
+ SvStream& operator >> (SvStream &rStream, ONDXPage& rPage);
+ SvStream& WriteONDXPage(SvStream &rStream, const ONDXPage& rPage);
+
+
+ // Index Node
+
+ class ONDXNode
+ {
+ friend class ONDXPage;
+ ONDXPagePtr aChild; /* Next page reference */
+ ONDXKey aKey;
+
+ public:
+ ONDXNode(){}
+ ONDXNode(const ONDXKey& rKey)
+ :aKey(rKey) {}
+
+ // Does the node point to a page?
+ bool HasChild() const {return aChild.HasPage();}
+ // If an index is provided, we may be able to retrieve the page
+ ONDXPagePtr& GetChild(ODbaseIndex* pIndex = nullptr, ONDXPage* = nullptr);
+
+ const ONDXKey& GetKey() const { return aKey;}
+ ONDXKey& GetKey() { return aKey;}
+
+ // Setting the child, via reference to retain the PagePos
+ void SetChild(ONDXPagePtr aCh = ONDXPagePtr(), ONDXPage* = nullptr);
+
+ void Write(SvStream &rStream, const ONDXPage& rPage) const;
+ void Read(SvStream &rStream, ODbaseIndex const &);
+ };
+
+ inline ONDXKey::ONDXKey(const ONDXKey& rKey)
+ : ONDXKey_BASE(rKey.getDBType())
+ ,nRecord(rKey.nRecord)
+ ,xValue(rKey.xValue)
+ {
+ }
+
+ inline ONDXKey& ONDXKey::operator=(const ONDXKey& rKey)
+ {
+ if(&rKey == this)
+ return *this;
+
+ xValue = rKey.xValue;
+ nRecord = rKey.nRecord;
+ m_eDBType = rKey.getDBType();
+ return *this;
+ }
+
+ inline bool ONDXKey::operator == (const ONDXKey& rKey) const
+ {
+ if(&rKey == this)
+ return true;
+ return Compare(rKey) == 0;
+ }
+ inline bool ONDXKey::operator != (const ONDXKey& rKey) const
+ {
+ return !operator== (rKey);
+ }
+ inline bool ONDXKey::operator < (const ONDXKey& rKey) const
+ {
+ return Compare(rKey) < 0;
+ }
+ inline bool ONDXKey::operator > (const ONDXKey& rKey) const
+ {
+ return Compare(rKey) > 0;
+ }
+ inline bool ONDXKey::operator <= (const ONDXKey& rKey) const
+ {
+ return !operator > (rKey);
+ }
+
+ inline void ONDXNode::SetChild(ONDXPagePtr aCh, ONDXPage* pParent)
+ {
+ aChild = aCh;
+ if (aChild.Is())
+ aChild->SetParent(pParent);
+ }
+
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FCatalog.hxx b/connectivity/source/inc/file/FCatalog.hxx
new file mode 100644
index 000000000..2bcf82df2
--- /dev/null
+++ b/connectivity/source/inc/file/FCatalog.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+ class OConnection;
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OFileCatalog :
+ public connectivity::sdbcx::OCatalog
+ {
+ protected:
+ OConnection* m_pConnection;
+
+ /** builds the name which should be used to access the object later on in the collection.
+ Will only be called in fillNames.
+ @param _xRow
+ The current row from the resultset given to fillNames.
+ */
+ virtual OUString buildName( const css::uno::Reference< css::sdbc::XRow >& _xRow) override;
+
+ public:
+ virtual void refreshTables() override;
+ virtual void refreshViews() override;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override;
+
+ public:
+ OFileCatalog(OConnection* _pCon);
+ OConnection* getConnection() { return m_pConnection; }
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // ::cppu::OComponentHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual void SAL_CALL disposing() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FColumns.hxx b/connectivity/source/inc/file/FColumns.hxx
new file mode 100644
index 000000000..f5fce16b6
--- /dev/null
+++ b/connectivity/source/inc/file/FColumns.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <file/FTable.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+ class OOO_DLLPUBLIC_FILE OColumns : public sdbcx::OCollection
+ {
+ protected:
+ OFileTable* m_pTable;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ public:
+ OColumns( OFileTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : sdbcx::OCollection(*_pTable,_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector)
+ ,m_pTable(_pTable)
+ {}
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FConnection.hxx b/connectivity/source/inc/file/FConnection.hxx
new file mode 100644
index 000000000..e6412992a
--- /dev/null
+++ b/connectivity/source/inc/file/FConnection.hxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/ucb/XDynamicResultSet.hpp>
+#include <TConnection.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+ class ODatabaseMetaData;
+ class OFileDriver;
+
+ class OOO_DLLPUBLIC_FILE OConnection : public connectivity::OMetaConnection
+ {
+ protected:
+
+ // Data attributes
+
+ css::uno::WeakReference< css::sdbcx::XTablesSupplier> m_xCatalog;
+
+ OUString m_aFilenameExtension;
+ OFileDriver* m_pDriver; // Pointer to the owning
+ // driver object
+ css::uno::Reference< css::ucb::XDynamicResultSet > m_xDir; // directory
+ css::uno::Reference< css::ucb::XContent> m_xContent;
+
+ bool m_bAutoCommit;
+ bool m_bReadOnly;
+ bool m_bShowDeleted;
+ bool m_bCaseSensitiveExtension;
+ bool m_bCheckSQL92;
+ bool m_bDefaultTextEncoding;
+
+
+ void throwUrlNotValid(const OUString & _rsUrl,const OUString & _rsMessage);
+
+ virtual ~OConnection() override;
+ public:
+
+ OConnection(OFileDriver* _pDriver);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ /// @throws css::uno::DeploymentException
+ virtual void construct(const OUString& _rUrl, const css::uno::Sequence< css::beans::PropertyValue >& _rInfo );
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override final;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override final;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ //XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // no interface methods
+ css::uno::Reference< css::ucb::XDynamicResultSet > getDir() const;
+ const css::uno::Reference< css::ucb::XContent>& getContent() const { return m_xContent; }
+ // create a catalog or return the catalog already created
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog();
+
+ bool matchesExtension( const OUString& _rExt ) const;
+
+ const OUString& getExtension() const { return m_aFilenameExtension; }
+ bool isCaseSensitiveExtension() const { return m_bCaseSensitiveExtension; }
+ OFileDriver* getDriver() const { return m_pDriver; }
+ bool showDeleted() const { return m_bShowDeleted; }
+ bool isCheckEnabled() const { return m_bCheckSQL92; }
+ bool isTextEncodingDefaulted() const { return m_bDefaultTextEncoding; }
+
+ public:
+ struct GrantAccess
+ {
+ friend class ODatabaseMetaData;
+ private:
+ GrantAccess() { }
+ };
+
+ void setCaseSensitiveExtension( bool _bIsCS, GrantAccess ) { m_bCaseSensitiveExtension = _bIsCS; }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FDatabaseMetaData.hxx b/connectivity/source/inc/file/FDatabaseMetaData.hxx
new file mode 100644
index 000000000..5c766c31d
--- /dev/null
+++ b/connectivity/source/inc/file/FDatabaseMetaData.hxx
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <TDatabaseMetaDataBase.hxx>
+#include <file/FConnection.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+
+ //************ Class: ODatabaseMetaData
+
+
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE ODatabaseMetaData :
+ public ODatabaseMetaDataBase
+ {
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+ protected:
+ OConnection* m_pConnection; // I need the native class not only the interface
+ virtual ~ODatabaseMetaData() override;
+ public:
+
+ ODatabaseMetaData(OConnection* _pCon);
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FDateFunctions.hxx b/connectivity/source/inc/file/FDateFunctions.hxx
new file mode 100644
index 000000000..e8eb12d0c
--- /dev/null
+++ b/connectivity/source/inc/file/FDateFunctions.hxx
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcode.hxx>
+
+namespace connectivity::file
+ {
+ /** DAYOFWEEK(date)
+ Returns the weekday index for date (1 = Sunday, 2 = Monday, ... 7 = Saturday). These index values correspond to the ODBC standard.
+
+ > SELECT DAYOFWEEK('1998-02-03');
+ -> 3
+ */
+ class OOp_DayOfWeek : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** DAYOFMONTH(date)
+ Returns the day of the month for date, in the range 1 to 31:
+
+ > SELECT DAYOFMONTH('1998-02-03');
+ -> 3
+ */
+ class OOp_DayOfMonth : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** DAYOFYEAR(date)
+ Returns the day of the year for date, in the range 1 to 366:
+
+ > SELECT DAYOFYEAR('1998-02-03');
+ -> 34
+
+ */
+ class OOp_DayOfYear : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** MONTH(date)
+ Returns the month for date, in the range 1 to 12:
+
+ > SELECT MONTH('1998-02-03');
+ -> 2
+ */
+ class OOp_Month : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** DAYNAME(date)
+ Returns the name of the weekday for date:
+
+ > SELECT DAYNAME('1998-02-05');
+ -> 'Thursday'
+
+ */
+ class OOp_DayName : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** MONTHNAME(date)
+ Returns the name of the month for date:
+
+ > SELECT MONTHNAME('1998-02-05');
+ -> 'February'
+
+ */
+ class OOp_MonthName : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** QUARTER(date)
+ Returns the quarter of the year for date, in the range 1 to 4:
+
+ > SELECT QUARTER('98-04-01');
+ -> 2
+
+ */
+ class OOp_Quarter : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** WEEK(date)
+ WEEK(date,first)
+ With a single argument, returns the week for date, in the range 0 to 53 (yes, there may be the beginnings of a week 53), for locations where Sunday is the first day of the week. The two-argument form of WEEK() allows you to specify whether the week starts on Sunday or Monday and whether the return value should be in the range 0-53 or 1-52. Here is a table for how the second argument works:
+ Value Meaning
+ 0 Week starts on Sunday and return value is in range 0-53
+ 1 Week starts on Monday and return value is in range 0-53
+ 2 Week starts on Sunday and return value is in range 1-53
+ 3 Week starts on Monday and return value is in range 1-53 (ISO 8601)
+
+ > SELECT WEEK('1998-02-20');
+ -> 7
+ > SELECT WEEK('1998-02-20',0);
+ -> 7
+ > SELECT WEEK('1998-02-20',1);
+ -> 8
+ > SELECT WEEK('1998-12-31',1);
+ -> 53
+
+ */
+ class OOp_Week : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** YEAR(date)
+ Returns the year for date, in the range 1000 to 9999:
+
+ > SELECT YEAR('98-02-03');
+ -> 1998
+ */
+ class OOp_Year : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** HOUR(time)
+ Returns the hour for time, in the range 0 to 23:
+
+ > SELECT HOUR('10:05:03');
+ -> 10
+ */
+ class OOp_Hour : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** MINUTE(time)
+ Returns the minute for time, in the range 0 to 59:
+
+ > SELECT MINUTE('98-02-03 10:05:03');
+ -> 5
+
+ */
+ class OOp_Minute : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** SECOND(time)
+ Returns the second for time, in the range 0 to 59:
+
+ > SELECT SECOND('10:05:03');
+ -> 3
+ */
+ class OOp_Second : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** CURDATE()
+ CURRENT_DATE
+ Returns today's date as a value in 'YYYY-MM-DD' or YYYYMMDD format, depending on whether the function is used in a string or numeric context:
+
+ > SELECT CURDATE();
+ -> '1997-12-15'
+ */
+ class OOp_CurDate : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** CURTIME()
+ CURRENT_TIME
+ Returns the current time as a value in 'HH:MM:SS' or HHMMSS format, depending on whether the function is used in a string or numeric context:
+
+ > SELECT CURTIME();
+ -> '23:50:26'
+ */
+ class OOp_CurTime : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** NOW()
+ Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether the function is used in a string or numeric context:
+
+ > SELECT NOW();
+ -> '1997-12-15 23:50:26'
+ */
+ class OOp_Now : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FDriver.hxx b/connectivity/source/inc/file/FDriver.hxx
new file mode 100644
index 000000000..9d289d618
--- /dev/null
+++ b/connectivity/source/inc/file/FDriver.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity::file
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver,
+ css::lang::XServiceInfo,
+ css::sdbcx::XDataDefinitionSupplier> ODriver_BASE;
+
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OFileDriver : public ODriver_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+
+ connectivity::OWeakRefArray m_xConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ public:
+ OFileDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ const css::uno::Reference< css::uno::XComponentContext >& getComponentContext() const { return m_xContext; }
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FNumericFunctions.hxx b/connectivity/source/inc/file/FNumericFunctions.hxx
new file mode 100644
index 000000000..765f2cde8
--- /dev/null
+++ b/connectivity/source/inc/file/FNumericFunctions.hxx
@@ -0,0 +1,362 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcode.hxx>
+
+namespace connectivity::file
+ {
+ /** ABS(X)
+ Returns the absolute value of X:
+
+ > SELECT ABS(2);
+ -> 2
+ > SELECT ABS(-32);
+ -> 32
+
+ */
+ class OOp_Abs : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** SIGN(X)
+ Returns the sign of the argument as -1, 0, or 1, depending on whether X is negative, zero, or positive:
+
+ > SELECT SIGN(-32);
+ -> -1
+ > SELECT SIGN(0);
+ -> 0
+ > SELECT SIGN(234);
+ -> 1
+
+ */
+ class OOp_Sign : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** MOD(N,M)
+ %
+ Modulo (like the % operator in C). Returns the remainder of N divided by M:
+
+ > SELECT MOD(234, 10);
+ -> 4
+ > SELECT 253 % 7;
+ -> 1
+ > SELECT MOD(29,9);
+ -> 2
+ > SELECT 29 MOD 9;
+ -> 2
+ */
+ class OOp_Mod : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** FLOOR(X)
+ Returns the largest integer value not greater than X:
+
+ > SELECT FLOOR(1.23);
+ -> 1
+ > SELECT FLOOR(-1.23);
+ -> -2
+
+ */
+ class OOp_Floor : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** CEILING(X)
+ Returns the smallest integer value not less than X:
+
+ > SELECT CEILING(1.23);
+ -> 2
+ > SELECT CEILING(-1.23);
+ -> -1
+
+ */
+ class OOp_Ceiling : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ROUND(X)
+ ROUND(X,D)
+ Returns the argument X, rounded to the nearest integer. With two arguments rounded to a number to D decimals.
+
+ > SELECT ROUND(-1.23);
+ -> -1
+ > SELECT ROUND(-1.58);
+ -> -2
+ > SELECT ROUND(1.58);
+ -> 2
+ > SELECT ROUND(1.298, 1);
+ -> 1.3
+ > SELECT ROUND(1.298, 0);
+ -> 1
+ > SELECT ROUND(23.298, -1);
+ -> 20
+ */
+ class OOp_Round : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** EXP(X)
+ Returns the value of e (the base of natural logarithms) raised to the power of X:
+
+ > SELECT EXP(2);
+ -> 7.389056
+ > SELECT EXP(-2);
+ -> 0.135335
+ */
+ class OOp_Exp : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** LN(X)
+ Returns the natural logarithm of X:
+
+ > SELECT LN(2);
+ -> 0.693147
+ > SELECT LN(-2);
+ -> NULL
+
+ */
+ class OOp_Ln : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** LOG(X)
+ LOG(B,X)
+ If called with one parameter, this function returns the natural logarithm of X:
+
+ > SELECT LOG(2);
+ -> 0.693147
+ > SELECT LOG(-2);
+ -> NULL
+
+ If called with two parameters, this function returns the logarithm of X for an arbitrary base B:
+
+ > SELECT LOG(2,65536);
+ -> 16.000000
+ > SELECT LOG(1,100);
+ -> NULL
+ */
+ class OOp_Log : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** LOG10(X)
+ Returns the base-10 logarithm of X:
+
+ > SELECT LOG10(2);
+ -> 0.301030
+ > SELECT LOG10(100);
+ -> 2.000000
+ > SELECT LOG10(-100);
+ -> NULL
+ */
+ class OOp_Log10 : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** POWER(X,Y)
+ Returns the value of X raised to the power of Y:
+
+ > SELECT POW(2,2);
+ -> 4.000000
+ > SELECT POW(2,-2);
+ -> 0.250000
+ */
+ class OOp_Pow : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** SQRT(X)
+ Returns the non-negative square root of X:
+
+ > SELECT SQRT(4);
+ -> 2.000000
+ > SELECT SQRT(20);
+ -> 4.472136
+ */
+ class OOp_Sqrt : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** PI()
+ Returns the value of PI. The default shown number of decimals is 5, but internally uses the full double precision for PI.
+
+ > SELECT PI();
+ -> 3.141593
+ > SELECT PI()+0.000000000000000000;
+ -> 3.141592653589793238
+
+ */
+ class OOp_Pi : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** COS(X)
+ Returns the cosine of X, where X is given in radians:
+
+ > SELECT COS(PI());
+ -> -1.000000
+ */
+ class OOp_Cos : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** SIN(X)
+ Returns the sine of X, where X is given in radians:
+
+ > SELECT SIN(PI());
+ -> 0.000000
+
+ */
+ class OOp_Sin : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+ /** TAN(X)
+ Returns the tangent of X, where X is given in radians:
+
+ > SELECT TAN(PI()+1);
+ -> 1.557408
+ */
+ class OOp_Tan : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ACOS(X)
+ Returns the arc cosine of X, that is, the value whose cosine is X. Returns NULL if X is not in the range -1 to 1:
+
+ > SELECT ACOS(1);
+ -> 0.000000
+ > SELECT ACOS(1.0001);
+ -> NULL
+ > SELECT ACOS(0);
+ -> 1.570796
+ */
+ class OOp_ACos : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ASIN(X)
+ Returns the arc sine of X, that is, the value whose sine is X. Returns NULL if X is not in the range -1 to 1:
+
+ > SELECT ASIN(0.2);
+ -> 0.201358
+ > SELECT ASIN('foo');
+ -> 0.000000
+ */
+ class OOp_ASin : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ATAN(X)
+ Returns the arc tangent of X, that is, the value whose tangent is X:
+
+ > SELECT ATAN(2);
+ -> 1.107149
+ > SELECT ATAN(-2);
+ -> -1.107149
+ */
+ class OOp_ATan : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ATAN2(Y,X)
+ Returns the arc tangent of the two variables X and Y. It is similar to calculating the arc tangent of Y / X, except that the signs of both arguments are used to determine the quadrant of the result:
+
+ > SELECT ATAN2(-2,2);
+ -> -0.785398
+ > SELECT ATAN2(PI(),0);
+ -> 1.570796
+
+ */
+ class OOp_ATan2 : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** DEGREES(X)
+ Returns the argument X, converted from radians to degrees:
+
+ > SELECT DEGREES(PI());
+ -> 180.000000
+ */
+ class OOp_Degrees : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** RADIANS(X)
+ Returns the argument X, converted from degrees to radians:
+
+ > SELECT RADIANS(90);
+ -> 1.570796
+
+ */
+ class OOp_Radians : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FPreparedStatement.hxx b/connectivity/source/inc/file/FPreparedStatement.hxx
new file mode 100644
index 000000000..f83d74a6d
--- /dev/null
+++ b/connectivity/source/inc/file/FPreparedStatement.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/filedllapi.hxx>
+#include <file/FStatement.hxx>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <file/FResultSet.hxx>
+
+namespace connectivity::file
+ {
+
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OPreparedStatement : public OStatement_BASE2,
+ public css::sdbc::XPreparedStatement,
+ public css::sdbc::XParameters,
+ public css::sdbc::XResultSetMetaDataSupplier,
+ public css::lang::XServiceInfo
+
+ {
+ protected:
+
+ // Data attributes
+
+ OValueRefRow m_aParameterRow;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+
+ ::rtl::Reference<connectivity::OSQLColumns> m_xParamColumns; // the parameter columns
+
+ // factory method for resultset's
+ virtual rtl::Reference<OResultSet> createResultSet() override;
+ ::rtl::Reference< OResultSet > makeResultSet();
+ void initResultSet(OResultSet*);
+
+ void checkAndResizeParameters(sal_Int32 parameterIndex);
+ void setParameter(sal_Int32 parameterIndex, const ORowSetValue& x);
+
+ sal_uInt32 AddParameter(connectivity::OSQLParseNode const * pParameter,
+ const css::uno::Reference< css::beans::XPropertySet>& _xCol);
+ void scanParameter(OSQLParseNode* pParseNode,std::vector< OSQLParseNode*>& _rParaNodes);
+ void describeColumn(OSQLParseNode const * _pParameter, OSQLParseNode const * _pNode, const OSQLTable& _xTable);
+ void describeParameter();
+
+ virtual void parseParamterElem(const OUString& _sColumnName,OSQLParseNode* pRow_Value_Constructor_Elem) override;
+ virtual void initializeResultSet(OResultSet* _pResult) override;
+
+ virtual ~OPreparedStatement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OPreparedStatement( OConnection* _pConnection);
+
+ virtual void construct(const OUString& sql) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FResultSet.hxx b/connectivity/source/inc/file/FResultSet.hxx
new file mode 100644
index 000000000..62a52fe2b
--- /dev/null
+++ b/connectivity/source/inc/file/FResultSet.hxx
@@ -0,0 +1,305 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <file/FStatement.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <file/fanalyzer.hxx>
+#include <file/FTable.hxx>
+#include <file/filedllapi.hxx>
+#include <TSortIndex.hxx>
+#include <TSkipDeletedSet.hxx>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <o3tl/safeint.hxx>
+
+namespace connectivity::file
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo,
+ css::lang::XEventListener,
+ css::lang::XUnoTunnel> OResultSet_BASE;
+
+ class OOO_DLLPUBLIC_FILE OResultSet :
+ public cppu::BaseMutex,
+ public ::connectivity::IResultSetHelper,
+ public OResultSet_BASE,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<OResultSet>
+ {
+
+ protected:
+ std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+
+ std::vector<sal_Int32> m_aOrderbyColumnNumber;
+ std::vector<TAscendingOrder> m_aOrderbyAscending;
+
+ OValueRefRow m_aSelectRow;
+ OValueRefRow m_aRow;
+ OValueRefRow m_aEvaluateRow; // contains all values of a row
+ OValueRefRow m_aInsertRow; // needed for insert by cursor
+ ORefAssignValues m_aAssignValues; // needed for insert,update and parameters
+ // to compare with the restrictions
+ OSkipDeletedSet m_aSkipDeletedSet;
+
+ ::rtl::Reference<OKeySet> m_pFileSet;
+ OKeySet::iterator m_aFileSetIter;
+
+
+ std::unique_ptr<OSortIndex> m_pSortIndex;
+ ::rtl::Reference<connectivity::OSQLColumns> m_xColumns; // this are the select columns
+ rtl::Reference<OFileTable> m_pTable;
+ connectivity::OSQLParseNode* m_pParseTree;
+
+ OSQLAnalyzer* m_pSQLAnalyzer;
+ connectivity::OSQLParseTreeIterator& m_aSQLIterator;
+
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+
+ css::uno::Reference< css::uno::XInterface> m_xStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ css::uno::Reference< css::container::XNameAccess> m_xColNames; // table columns
+ css::uno::Reference< css::container::XIndexAccess> m_xColsIdx; // table columns
+
+
+ sal_Int32 m_nRowPos;
+ sal_Int32 m_nFilePos;
+ sal_Int32 m_nLastVisitedPos;
+ sal_Int32 m_nRowCountResult;
+ sal_Int32 m_nColumnCount;
+ bool m_bWasNull;
+ bool m_bInserted; // true when moveToInsertRow was called
+ // set to false when cursor moved or cancel
+ bool m_bRowUpdated;
+ bool m_bRowInserted;
+ bool m_bRowDeleted;
+ bool m_bShowDeleted;
+ bool m_bIsCount;
+
+ static void initializeRow(OValueRefRow& _rRow,sal_Int32 _nColumnCount);
+ void construct();
+ //sal_Bool evaluate();
+
+ bool ExecuteRow(IResultSetHelper::Movement eFirstCursorPosition,
+ sal_Int32 nOffset = 1,
+ bool bEvaluate = true,
+ bool bRetrieveData = true);
+
+ std::unique_ptr<OKeyValue> GetOrderbyKeyValue(OValueRefRow const & _rRow);
+ bool IsSorted() const { return !m_aOrderbyColumnNumber.empty() && m_aOrderbyColumnNumber[0] >= 0;}
+
+ // return true when the select statement is "select count(*) from table"
+ bool isCount() const { return m_bIsCount; }
+ /// @throws css::sdbc::SQLException
+ void checkIndex(sal_Int32 columnIndex );
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ const ORowSetValue& getValue(sal_Int32 columnIndex);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void updateValue(sal_Int32 columnIndex,const ORowSetValue& x );
+ // clear insert row
+ void clearInsertRow();
+ void sortRows();
+ protected:
+
+ using OResultSet_BASE::rBHelper;
+
+ bool Move(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, bool bRetrieveData);
+ virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex);
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual ~OResultSet() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator);
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override final;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+ //XEventlistener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // special methods
+ inline sal_Int32 mapColumn(sal_Int32 column);
+ void OpenImpl();
+ void doTableSpecials(const OSQLTable& _xTable);
+
+ sal_Int32 getRowCountResult() const { return m_nRowCountResult; }
+ void setEvaluationRow(const OValueRefRow& _aRow) { m_aEvaluateRow = _aRow; }
+ void setAssignValues(const ORefAssignValues& _aAssignValues) { m_aAssignValues = _aAssignValues; }
+ void setBindingRow(const OValueRefRow& _aRow) { m_aRow = _aRow; }
+ void setSelectRow(const OValueRefRow& _rRow)
+ {
+ m_aSelectRow = _rRow;
+ m_nColumnCount = m_aSelectRow->size();
+ }
+ void setColumnMapping(std::vector<sal_Int32>&& _aColumnMapping) { m_aColMapping = std::move(_aColumnMapping); }
+ void setSqlAnalyzer(OSQLAnalyzer* _pSQLAnalyzer) { m_pSQLAnalyzer = _pSQLAnalyzer; }
+
+ void setOrderByColumns(std::vector<sal_Int32>&& _aColumnOrderBy) { m_aOrderbyColumnNumber = std::move(_aColumnOrderBy); }
+ void setOrderByAscending(std::vector<TAscendingOrder>&& _aOrderbyAsc) { m_aOrderbyAscending = std::move(_aOrderbyAsc); }
+ void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;}
+
+ static void setBoundedColumns(const OValueRefRow& _rRow,
+ const OValueRefRow& _rSelectRow,
+ const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,
+ const css::uno::Reference< css::container::XIndexAccess>& _xNames,
+ bool _bSetColumnMapping,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData,
+ std::vector<sal_Int32>& _rColMapping);
+
+ // IResultSetHelper
+ virtual bool move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) override;
+ virtual sal_Int32 getDriverPos() const override;
+ virtual bool isRowDeleted() const override;
+ };
+
+ inline sal_Int32 OResultSet::mapColumn(sal_Int32 column)
+ {
+ sal_Int32 map = column;
+
+ OSL_ENSURE(column > 0, "file::OResultSet::mapColumn: invalid column index!");
+ // the first column (index 0) is for convenience only. The first real select column is number 1.
+ if ((column > 0) && (o3tl::make_unsigned(column) < m_aColMapping.size()))
+ map = m_aColMapping[column];
+
+ return map;
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FResultSetMetaData.hxx b/connectivity/source/inc/file/FResultSetMetaData.hxx
new file mode 100644
index 000000000..65fc0bb3c
--- /dev/null
+++ b/connectivity/source/inc/file/FResultSetMetaData.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <rtl/ref.hxx>
+
+namespace connectivity::file
+ {
+ class OFileTable;
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
+
+ class OResultSetMetaData :
+ public OResultSetMetaData_BASE
+ {
+ OUString m_aTableName;
+ ::rtl::Reference<connectivity::OSQLColumns> m_xColumns;
+ OFileTable* m_pTable;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkColumnIndex(sal_Int32 column);
+ protected:
+ virtual ~OResultSetMetaData() override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OResultSetMetaData(const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,const OUString& _aTableName,OFileTable* _pTable);
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FStatement.hxx b/connectivity/source/inc/file/FStatement.hxx
new file mode 100644
index 000000000..57ce0a2fc
--- /dev/null
+++ b/connectivity/source/inc/file/FStatement.hxx
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <file/FConnection.hxx>
+#include <file/filedllapi.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <comphelper/propertycontainer.hxx>
+#include <file/fanalyzer.hxx>
+#include <TSortIndex.hxx>
+
+namespace connectivity::file
+ {
+ class OResultSet;
+ class OFileTable;
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable> OStatement_BASE;
+
+
+ //************ Class: java.sql.Statement
+
+ class OOO_DLLPUBLIC_FILE OStatement_Base :
+ public cppu::BaseMutex,
+ public OStatement_BASE,
+ public ::comphelper::OPropertyContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base>
+
+ {
+ protected:
+ std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+ std::vector<sal_Int32> m_aParameterIndexes; // maps the parameter index to column index
+ std::vector<sal_Int32> m_aOrderbyColumnNumber;
+ std::vector<TAscendingOrder> m_aOrderbyAscending;
+
+ css::sdbc::SQLWarning m_aLastWarning;
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+ css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xDBMetaData;
+ css::uno::Reference< css::container::XNameAccess> m_xColNames; // table columns // for this Statement
+
+
+ connectivity::OSQLParser m_aParser;
+ connectivity::OSQLParseTreeIterator m_aSQLIterator;
+
+ rtl::Reference<OConnection> m_pConnection;// The owning Connection object
+ connectivity::OSQLParseNode* m_pParseTree;
+ std::unique_ptr<OSQLAnalyzer> m_pSQLAnalyzer; //the sql analyzer used by the resultset
+
+ rtl::Reference<OFileTable> m_pTable; // the current table
+ OValueRefRow m_aSelectRow;
+ OValueRefRow m_aRow;
+ OValueRefRow m_aEvaluateRow; // contains all values of a row
+ ORefAssignValues m_aAssignValues; // needed for insert,update and parameters
+ // to compare with the restrictions
+
+ OUString m_aCursorName;
+ sal_Int32 m_nMaxFieldSize;
+ sal_Int32 m_nMaxRows;
+ sal_Int32 m_nQueryTimeOut;
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nResultSetType;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nResultSetConcurrency;
+ bool m_bEscapeProcessing;
+
+ protected:
+ // initialize the column index map (mapping select columns to table columns)
+ void createColumnMapping();
+ // searches the statement for sort criteria
+ void analyzeSQL();
+ void setOrderbyColumn( connectivity::OSQLParseNode const * pColumnRef,
+ connectivity::OSQLParseNode const * pAscendingDescending);
+
+ virtual void initializeResultSet(OResultSet* _pResult);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void closeResultSet();
+
+ void disposeResultSet();
+ void GetAssignValues();
+ void SetAssignValue(const OUString& aColumnName,
+ const OUString& aValue,
+ bool bSetNull = false,
+ sal_uInt32 nParameter=SQL_NO_PARAMETER);
+ void ParseAssignValues( const std::vector< OUString>& aColumnNameList,
+ connectivity::OSQLParseNode* pRow_Value_Constructor_Elem, sal_Int32 nIndex);
+
+ virtual void parseParamterElem(const OUString& _sColumnName,OSQLParseNode* pRow_Value_Constructor_Elem);
+ // factory method for resultset's
+ virtual rtl::Reference<OResultSet> createResultSet() = 0;
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual ~OStatement_Base() override;
+ public:
+ connectivity::OSQLParseNode* getParseTree() const { return m_pParseTree;}
+
+ OStatement_Base(OConnection* _pConnection );
+
+ OConnection* getOwnConnection() const { return m_pConnection.get(); }
+
+ using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void construct(const OUString& sql);
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ // virtual void SAL_CALL release() throw(css::uno::RuntimeException) = 0;
+ virtual void SAL_CALL acquire() noexcept override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OStatement_BASE2 : public OStatement_Base
+
+ {
+ public:
+ OStatement_BASE2(OConnection* _pConnection ) : OStatement_Base(_pConnection ) {}
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+ };
+
+ typedef ::cppu::ImplHelper2< css::sdbc::XStatement,css::lang::XServiceInfo > OStatement_XStatement;
+ class OOO_DLLPUBLIC_FILE OStatement :
+ public OStatement_BASE2,
+ public OStatement_XStatement
+ {
+ protected:
+ // factory method for resultset's
+ virtual rtl::Reference<OResultSet> createResultSet() override;
+ public:
+ // a Constructor, that is needed for when Returning the Object is needed:
+ OStatement( OConnection* _pConnection) : OStatement_BASE2( _pConnection){}
+ DECLARE_SERVICE_INFO();
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FStringFunctions.hxx b/connectivity/source/inc/file/FStringFunctions.hxx
new file mode 100644
index 000000000..b3d72294f
--- /dev/null
+++ b/connectivity/source/inc/file/FStringFunctions.hxx
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcode.hxx>
+
+namespace connectivity::file
+ {
+ /** UCASE(str)
+ UPPER(str)
+ Returns the string str with all characters changed to uppercase according to the current character set mapping (the default is ISO-8859-1 Latin1):
+
+ > SELECT UCASE('Hej');
+ -> 'HEJ'
+
+ */
+ class OOp_Upper : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** LCASE(str)
+ LOWER(str)
+ Returns the string str with all characters changed to lowercase according to the current character set mapping (the default is ISO-8859-1 Latin1):
+
+ > SELECT LCASE('QUADRATICALLY');
+ -> 'quadratically'
+
+ */
+ class OOp_Lower : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** ASCII(str)
+ Returns the ASCII code value of the leftmost character of the string str. Returns 0 if str is the empty string. Returns NULL if str is NULL:
+
+ > SELECT ASCII('2');
+ -> 50
+ > SELECT ASCII(2);
+ -> 50
+ > SELECT ASCII('dx');
+ -> 100
+
+ */
+ class OOp_Ascii : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** LENGTH(str)
+ OCTET_LENGTH(str)
+ CHAR_LENGTH(str)
+ CHARACTER_LENGTH(str)
+ Returns the length of the string str:
+
+ > SELECT LENGTH('text');
+ -> 4
+ > SELECT OCTET_LENGTH('text');
+ -> 4
+
+ */
+ class OOp_CharLength : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** CHAR(N,...)
+ CHAR() interprets the arguments as integers and returns a string consisting of the characters given by the ASCII code values of those integers. NULL values are skipped:
+
+ > SELECT CHAR(ascii('t'),ascii('e'),ascii('s'),ascii('t'));
+ -> 'test'
+ > SELECT CHAR(77,77.3,'77.3');
+ -> 'MMM'
+
+ */
+ class OOp_Char : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** CONCAT(str1,str2,...)
+ Returns the string that results from concatenating the arguments. Returns NULL if any argument is NULL. May have more than 2 arguments. A numeric argument is converted to the equivalent string form:
+
+ > SELECT CONCAT('OO', 'o', 'OO');
+ -> 'OOoOO'
+ > SELECT CONCAT('OO', NULL, 'OO');
+ -> NULL
+ > SELECT CONCAT(14.3);
+ -> '14.3'
+
+ */
+ class OOp_Concat : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** LOCATE(substr,str)
+ POSITION(substr IN str)
+ Returns the position of the first occurrence of substring substr in string str. Returns 0 if substr is not in str:
+
+ > SELECT LOCATE('bar', 'foobarbar');
+ -> 4
+ > SELECT LOCATE('xbar', 'foobar');
+ -> 0
+ LOCATE(substr,str,pos)
+ Returns the position of the first occurrence of substring substr in string str, starting at position pos. Returns 0 if substr is not in str:
+
+ > SELECT LOCATE('bar', 'foobarbar',5);
+ -> 7
+
+ */
+ class OOp_Locate : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** SUBSTRING(str,pos)
+ SUBSTRING(str FROM pos)
+ Returns a substring from string str starting at position pos:
+
+ > SELECT SUBSTRING('Quadratically',5);
+ -> 'ratically'
+ > SELECT SUBSTRING('foobarbar' FROM 4);
+ -> 'barbar'
+ SUBSTRING(str,pos,len)
+ SUBSTRING(str FROM pos FOR len)
+ Returns a substring len characters long from string str, starting at position pos. The variant form that uses FROM is SQL-92 syntax:
+
+ > SELECT SUBSTRING('Quadratically',5,6);
+ -> 'ratica'
+
+ */
+ class OOp_SubString : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** LTRIM(str)
+ Returns the string str with leading space characters removed:
+
+ > SELECT LTRIM(' barbar');
+ -> 'barbar'
+
+ */
+ class OOp_LTrim : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** RTRIM(str)
+ Returns the string str with trailing space characters removed:
+
+ > SELECT RTRIM('barbar ');
+ -> 'barbar'
+
+ */
+ class OOp_RTrim : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** SPACE(N)
+ Returns a string consisting of N space characters:
+
+ > SELECT SPACE(6);
+ -> ' '
+
+ */
+ class OOp_Space : public OUnaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const override;
+ };
+
+ /** REPLACE(str,from_str,to_str)
+ Returns the string str with all occurrences of the string from_str replaced by the string to_str:
+
+ > SELECT REPLACE('www.OOo.com', 'w', 'Ww');
+ -> 'WwWwWw.OOo.com'
+
+ */
+ class OOp_Replace : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** REPEAT(str,count)
+ Returns a string consisting of the string str repeated count times. If count <= 0, returns an empty string. Returns NULL if str or count are NULL:
+
+ > SELECT REPEAT('OOo', 3);
+ -> 'OOoOOoOOo'
+
+ */
+ class OOp_Repeat : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** INSERT(str,pos,len,newstr)
+ Returns the string str, with the substring beginning at position pos and len characters long replaced by the string newstr:
+
+ > SELECT INSERT('Quadratic', 3, 4, 'What');
+ -> 'QuWhattic'
+
+ */
+ class OOp_Insert : public ONthOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override;
+ };
+
+ /** LEFT(str,len)
+ Returns the leftmost len characters from the string str:
+
+ > SELECT LEFT('foobarbar', 5);
+ -> 'fooba'
+
+ */
+ class OOp_Left : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+ /** RIGHT(str,len)
+ Returns the rightmost len characters from the string str:
+
+ > SELECT RIGHT('foobarbar', 4);
+ -> 'rbar'
+ */
+ class OOp_Right : public OBinaryOperator
+ {
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FTable.hxx b/connectivity/source/inc/file/FTable.hxx
new file mode 100644
index 000000000..4f925f799
--- /dev/null
+++ b/connectivity/source/inc/file/FTable.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 <connectivity/sdbcx/VTable.hxx>
+#include <file/FConnection.hxx>
+#include <file/filedllapi.hxx>
+#include <tools/stream.hxx>
+#include <connectivity/FValue.hxx>
+#include <TResultSetHelper.hxx>
+
+namespace connectivity::file
+ {
+ typedef connectivity::sdbcx::OTable OTable_TYPEDEF;
+
+ class OOO_DLLPUBLIC_FILE OFileTable : public OTable_TYPEDEF
+ {
+ protected:
+ OConnection* m_pConnection;
+ std::unique_ptr<SvStream> m_pFileStream;
+ ::rtl::Reference<OSQLColumns> m_aColumns;
+ sal_Int32 m_nFilePos; // current IResultSetHelper::Movement
+ std::unique_ptr<sal_uInt8[]> m_pBuffer;
+ sal_uInt16 m_nBufferSize; // size of the ReadBuffer, if pBuffer != NULL
+ bool m_bWriteable; // svstream can't say if we are writeable
+ // so we have to
+
+ virtual void FileClose();
+ virtual ~OFileTable( ) override;
+ public:
+ virtual void refreshColumns() override;
+ virtual void refreshKeys() override;
+ virtual void refreshIndexes() override;
+ public:
+ OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection);
+ OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName
+ );
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ OConnection* getConnection() const { return m_pConnection;}
+ virtual sal_Int32 getCurrentLastPos() const {return -1;}
+
+ virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) = 0;
+ virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) = 0;
+
+ const ::rtl::Reference<OSQLColumns>& getTableColumns() const {return m_aColumns;}
+ virtual bool InsertRow(OValueRefVector& rRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols);
+ virtual bool DeleteRow(const OSQLColumns& _rCols);
+ virtual bool UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow,const css::uno::Reference< css::container::XIndexAccess>& _xCols);
+ virtual void addColumn(const css::uno::Reference< css::beans::XPropertySet>& descriptor);
+ virtual void dropColumn(sal_Int32 _nPos);
+ // refresh the header of file based tables to see changes done by someone
+ virtual void refreshHeader();
+
+ OUString SAL_CALL getName() override { return m_Name; }
+
+ const OUString& getSchema() const { return m_SchemaName; }
+ bool isReadOnly() const { return !m_bWriteable; }
+ // m_pFileStream && !m_pFileStream->IsWritable(); }
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+
+ sal_Int32 getFilePos() const { return m_nFilePos; }
+
+ public:
+ // helper
+
+ // creates a stream using ::utl::UcbStreamHelper::CreateStream, but the error is simplified
+ // (NULL or non-NULL is returned)
+ static std::unique_ptr<SvStream> createStream_simpleError( const OUString& _rFileName, StreamMode _eOpenMode);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/FTables.hxx b/connectivity/source/inc/file/FTables.hxx
new file mode 100644
index 000000000..9d14c3627
--- /dev/null
+++ b/connectivity/source/inc/file/FTables.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/filedllapi.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+
+namespace connectivity::file
+ {
+ class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OTables :
+ public sdbcx::OCollection
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ public:
+ OTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent,_rMetaData->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector)
+ {}
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/fanalyzer.hxx b/connectivity/source/inc/file/fanalyzer.hxx
new file mode 100644
index 000000000..f913529d2
--- /dev/null
+++ b/connectivity/source/inc/file/fanalyzer.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/fcomp.hxx>
+
+namespace connectivity::file
+ {
+ class OConnection;
+ class OSQLAnalyzer final
+ {
+ typedef std::pair< ::rtl::Reference<OPredicateCompiler>,::rtl::Reference<OPredicateInterpreter> > TPredicates;
+
+ std::vector< TPredicates > m_aSelectionEvaluations;
+ ::rtl::Reference<OPredicateCompiler> m_aCompiler;
+ ::rtl::Reference<OPredicateInterpreter> m_aInterpreter;
+ OConnection* m_pConnection;
+
+ mutable bool m_bHasSelectionCode;
+ mutable bool m_bSelectionFirstTime;
+
+ static void bindRow(OCodeList& rCodeList,const OValueRefRow& _pRow);
+
+ public:
+ OSQLAnalyzer(OConnection* _pConnection);
+ ~OSQLAnalyzer();
+
+ OConnection* getConnection() const { return m_pConnection; }
+ void bindEvaluationRow(OValueRefRow const & _pRow); // Bind an evaluation row to the restriction
+ /** bind the select columns if they contain a function which needs a row value
+ @param _pRow the result row
+ */
+ void bindSelectRow(const OValueRefRow& _pRow);
+
+ /** binds the row to parameter for the restrictions
+ @param _pRow the parameter row
+ */
+ void bindParameterRow(OValueRefRow const & _pRow);
+
+ void dispose();
+ void start(OSQLParseNode const * pSQLParseNode);
+ bool hasRestriction() const;
+ bool hasFunctions() const;
+ bool evaluateRestriction() { return m_aInterpreter->start(); }
+ void setSelectionEvaluationResult(OValueRefRow const & _pRow,const std::vector<sal_Int32>& _rColumnMapping);
+ void setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols);
+ static OOperandAttr* createOperandAttr(sal_Int32 _nPos,
+ const css::uno::Reference< css::beans::XPropertySet>& _xCol);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/fcode.hxx b/connectivity/source/inc/file/fcode.hxx
new file mode 100644
index 000000000..c78461743
--- /dev/null
+++ b/connectivity/source/inc/file/fcode.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <connectivity/sqliterator.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <connectivity/FValue.hxx>
+#include <file/filedllapi.hxx>
+
+#include <stack>
+
+namespace connectivity
+{
+ class OSQLParseNode;
+ namespace file
+ {
+
+ class OOperand;
+ typedef std::stack<OOperand*> OCodeStack;
+
+ class OOO_DLLPUBLIC_FILE OCode
+ {
+ public:
+ //virtual dtor to allow this to be the root of the class hierarchy
+ virtual ~OCode();
+ //but that disables the default move ctor
+ OCode(OCode&&) = default;
+ //but that disables the rest of default ctors
+ OCode(const OCode&) = default;
+ OCode() = default;
+ //and same issue for the assignment operators
+ OCode& operator=(const OCode&) = default;
+ OCode& operator=(OCode&&) = default;
+ };
+
+
+ // operands that the parsetree generate
+ class OOO_DLLPUBLIC_FILE OOperand : public OCode
+ {
+ protected:
+ sal_Int32 m_eDBType;
+
+ OOperand(sal_Int32 _rType) : m_eDBType(_rType){}
+ OOperand() : m_eDBType(css::sdbc::DataType::OTHER){}
+
+ public:
+ virtual const ORowSetValue& getValue() const = 0;
+ virtual void setValue(const ORowSetValue& _rVal) = 0;
+
+ sal_Int32 getDBType() const {return m_eDBType;}
+ inline bool isValid() const;
+
+ };
+
+ class OOperandRow : public OOperand
+ {
+ sal_uInt16 m_nRowPos;
+ OValueRefRow m_pRow;
+
+ protected:
+ OOperandRow(sal_uInt16 _nPos, sal_Int32 _rType);
+ public:
+ virtual const ORowSetValue& getValue() const override;
+ virtual void setValue(const ORowSetValue& _rVal) override;
+ void bindValue(const OValueRefRow& _pRow); // Bind to the value that the operand represents
+
+ };
+
+ // Attributes from a result row
+ class OOperandAttr : public OOperandRow
+ {
+ public:
+ OOperandAttr(sal_uInt16 _nPos,
+ const css::uno::Reference< css::beans::XPropertySet>& _xColumn);
+
+ };
+
+ // Parameter for a predicate
+ class OOperandParam : public OOperandRow
+ {
+ public:
+ OOperandParam(sal_Int32 _nPos);
+ };
+
+ // Value operands
+ class OOperandValue : public OOperand
+ {
+ protected:
+ ORowSetValue m_aValue;
+
+ protected:
+ OOperandValue(){}
+ OOperandValue(const ORowSetValue& _rVar, sal_Int32 eDbType)
+ : OOperand(eDbType)
+ , m_aValue(_rVar)
+ {}
+
+ OOperandValue(sal_Int32 eDbType) :OOperand(eDbType){}
+ public:
+ virtual const ORowSetValue& getValue() const override;
+ virtual void setValue(const ORowSetValue& _rVal) override;
+
+ };
+
+
+ // Constants
+ class OOperandConst : public OOperandValue
+ {
+ public:
+ OOperandConst(const connectivity::OSQLParseNode& rColumnRef, const OUString& aStrValue);
+
+ };
+
+
+ // Result operands
+ class OOperandResult : public OOperandValue
+ {
+ protected:
+ OOperandResult(sal_Int32 eDbType)
+ :OOperandValue(eDbType) {}
+ public:
+ OOperandResult(const ORowSetValue& _rVar)
+ :OOperandValue(_rVar, _rVar.getTypeKind()) {}
+ };
+
+
+ class OOperandResultBOOL : public OOperandResult
+ {
+ public:
+ OOperandResultBOOL(bool bResult) : OOperandResult(css::sdbc::DataType::BIT)
+ {
+ m_aValue = bResult ? 1.0 : 0.0;
+ m_aValue.setBound(true);
+ }
+ };
+
+ class OOperandResultNUM : public OOperandResult
+ {
+ public:
+ OOperandResultNUM(double fNum) : OOperandResult(css::sdbc::DataType::DOUBLE)
+ {
+ m_aValue = fNum;
+ m_aValue.setBound(true);
+ }
+ };
+
+ /** special stop operand
+ is appended when a list of arguments ends
+ */
+ class OStopOperand : public OOperandValue
+ {
+ public:
+ OStopOperand(){}
+ };
+
+ // Operators
+ class OOO_DLLPUBLIC_FILE OOperator : public OCode
+ {
+ public:
+ virtual void Exec(OCodeStack&) = 0;
+ };
+
+
+ // Boolean operators
+ class OOO_DLLPUBLIC_FILE OBoolOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+ virtual bool operate(const OOperand*, const OOperand*) const;
+ };
+
+ class OOp_NOT : public OBoolOperator
+ {
+ public:
+
+ protected:
+ virtual void Exec(OCodeStack&) override;
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOp_AND : public OBoolOperator
+ {
+ public:
+
+ protected:
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOp_OR : public OBoolOperator
+ {
+ public:
+ protected:
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OOp_ISNULL : public OBoolOperator
+ {
+ public:
+ public:
+ virtual void Exec(OCodeStack&) override;
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OOp_ISNOTNULL : public OOp_ISNULL
+ {
+ public:
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OOp_LIKE : public OBoolOperator
+ {
+ const sal_Unicode cEscape;
+
+ public:
+ OOp_LIKE(const sal_Unicode cEsc):cEscape(cEsc){};
+
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOp_NOTLIKE : public OOp_LIKE
+ {
+ public:
+ public:
+ OOp_NOTLIKE(const sal_Unicode cEsc):OOp_LIKE(cEsc){};
+
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ class OOO_DLLPUBLIC_FILE OOp_COMPARE : public OBoolOperator
+ {
+ sal_Int32 aPredicateType;
+
+ public:
+ OOp_COMPARE(sal_Int32 aPType)
+ :aPredicateType(aPType) {}
+
+ sal_Int32 getPredicateType() const { return aPredicateType; }
+ virtual bool operate(const OOperand*, const OOperand*) const override;
+ };
+
+ // Numerical operators
+ class ONumOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+
+
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const = 0;
+ };
+
+ class OOp_ADD : public ONumOperator
+ {
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const override;
+ };
+
+ class OOp_SUB : public ONumOperator
+ {
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const override;
+ };
+
+ class OOp_MUL : public ONumOperator
+ {
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const override;
+ };
+
+ class OOp_DIV : public ONumOperator
+ {
+ protected:
+ virtual double operate(const double& fLeft,const double& fRight) const override;
+ };
+
+ inline bool OOperand::isValid() const
+ {
+ return getValue().getDouble() != 0.0;
+ }
+
+ // Operator
+ class ONthOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+
+
+ protected:
+ virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const = 0;
+ };
+
+ class OBinaryOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+
+
+ protected:
+ virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const = 0;
+ };
+
+ class OUnaryOperator : public OOperator
+ {
+ public:
+ virtual void Exec(OCodeStack&) override;
+ virtual ORowSetValue operate(const ORowSetValue& lhs) const = 0;
+
+
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/fcomp.hxx b/connectivity/source/inc/file/fcomp.hxx
new file mode 100644
index 000000000..ebdb0679e
--- /dev/null
+++ b/connectivity/source/inc/file/fcomp.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 <file/fcode.hxx>
+
+namespace connectivity
+{
+ class OSQLParseNode;
+ namespace file
+ {
+ class OCode;
+ class OOperand;
+ class OSQLAnalyzer;
+ typedef std::vector<std::unique_ptr<OCode>> OCodeList;
+
+ class OPredicateCompiler final : public ::salhelper::SimpleReferenceObject
+ {
+ friend class OPredicateInterpreter;
+ friend class OSQLAnalyzer;
+
+ OCodeList m_aCodeList;
+ css::uno::Reference< css::container::XNameAccess> m_orgColumns; // in filecurs this are the filecolumns
+ OSQLAnalyzer* m_pAnalyzer;
+ sal_Int32 m_nParamCounter;
+ public:
+ OPredicateCompiler(OSQLAnalyzer* pAnalyzer);
+
+ virtual ~OPredicateCompiler() override;
+
+ void dispose();
+
+ void start(connectivity::OSQLParseNode const * pSQLParseNode);
+ OOperand* execute(connectivity::OSQLParseNode const * pPredicateNode);
+
+ void Clean();
+ bool isClean() const {return m_aCodeList.empty();}
+ bool hasCode() const {return !isClean();}
+ void setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols) { m_orgColumns = rCols; }
+ const css::uno::Reference< css::container::XNameAccess>& getOrigColumns() const { return m_orgColumns; }
+ private:
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_COMPARE(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_LIKE(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_BETWEEN(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_ISNULL(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OOperand* execute_Operand(connectivity::OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void execute_Fold(OSQLParseNode const * pPredicateNode);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void executeFunction(OSQLParseNode const * pPredicateNode);
+ };
+
+
+ class OPredicateInterpreter :
+ public ::salhelper::SimpleReferenceObject
+ {
+ OCodeStack m_aStack;
+ ::rtl::Reference<OPredicateCompiler> m_rCompiler;
+
+ public:
+ OPredicateInterpreter(const ::rtl::Reference<OPredicateCompiler>& rComp) : m_rCompiler(rComp){}
+ virtual ~OPredicateInterpreter() override;
+
+ bool evaluate(OCodeList& rCodeList);
+ void evaluateSelection(OCodeList& rCodeList, ORowSetValueDecoratorRef const & _rVal);
+
+ bool start()
+ {
+ return evaluate(m_rCompiler->m_aCodeList);
+ }
+
+ void startSelection(ORowSetValueDecoratorRef const & _rVal)
+ {
+ evaluateSelection(m_rCompiler->m_aCodeList,_rVal);
+ }
+
+
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/filedllapi.hxx b/connectivity/source/inc/file/filedllapi.hxx
new file mode 100644
index 000000000..e32f5f17c
--- /dev/null
+++ b/connectivity/source/inc/file/filedllapi.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+#if defined OOO_DLLIMPLEMENTATION_FILE
+#define OOO_DLLPUBLIC_FILE SAL_DLLPUBLIC_EXPORT
+#else
+#define OOO_DLLPUBLIC_FILE SAL_DLLPUBLIC_IMPORT
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/file/quotedstring.hxx b/connectivity/source/inc/file/quotedstring.hxx
new file mode 100644
index 000000000..7c6becc37
--- /dev/null
+++ b/connectivity/source/inc/file/quotedstring.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <file/filedllapi.hxx>
+
+namespace connectivity
+{
+
+ // Derived from String, overriding GetToken/GetTokenCount methods
+ // Especially true for the flat file format: Strings can be quoted
+
+ class OOO_DLLPUBLIC_FILE QuotedTokenizedString
+ {
+ OUString m_sString;
+ public:
+ QuotedTokenizedString() {}
+
+ sal_Int32 GetTokenCount( sal_Unicode cTok , sal_Unicode cStrDel ) const;
+ OUString GetTokenSpecial(sal_Int32& nStartPos, sal_Unicode cTok, sal_Unicode cStrDel = '\0') const;
+ OUString& GetString() { return m_sString; }
+ void SetString(const OUString& aStr) { m_sString = aStr;}
+ sal_Int32 Len() const { return m_sString.getLength(); }
+ operator OUString&() { return m_sString; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/ECatalog.hxx b/connectivity/source/inc/flat/ECatalog.hxx
new file mode 100644
index 000000000..d1252e464
--- /dev/null
+++ b/connectivity/source/inc/flat/ECatalog.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FCatalog.hxx>
+
+namespace connectivity::flat
+ {
+ class OFlatConnection;
+ class OFlatCatalog : public file::OFileCatalog
+ {
+ public:
+ virtual void refreshTables() override;
+
+ public:
+ OFlatCatalog(OFlatConnection* _pCon);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EColumns.hxx b/connectivity/source/inc/flat/EColumns.hxx
new file mode 100644
index 000000000..d25f79aae
--- /dev/null
+++ b/connectivity/source/inc/flat/EColumns.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FColumns.hxx>
+
+namespace connectivity::flat
+ {
+ class OFlatColumns : public file::OColumns
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ public:
+ OFlatColumns(file::OFileTable* _pTable,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector
+ ) : file::OColumns(_pTable,_rMutex,_rVector)
+ {}
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EConnection.hxx b/connectivity/source/inc/flat/EConnection.hxx
new file mode 100644
index 000000000..be7c3596d
--- /dev/null
+++ b/connectivity/source/inc/flat/EConnection.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FConnection.hxx>
+
+namespace connectivity::flat
+ {
+ class ODriver;
+ class OFlatConnection : public file::OConnection
+ {
+ private:
+ sal_Int32 m_nMaxRowsToScan;
+ bool m_bHeaderLine; // column names in first row
+ sal_Unicode m_cFieldDelimiter; // look at the name
+ sal_Unicode m_cStringDelimiter;
+ sal_Unicode m_cDecimalDelimiter;
+ sal_Unicode m_cThousandDelimiter;
+ public:
+ OFlatConnection(ODriver* _pDriver);
+ virtual ~OFlatConnection() override;
+
+ virtual void construct(const OUString& _rUrl,const css::uno::Sequence< css::beans::PropertyValue >& _rInfo ) override;
+
+ // own methods
+ bool isHeaderLine() const { return m_bHeaderLine; }
+ sal_Unicode getFieldDelimiter() const { return m_cFieldDelimiter; }
+ sal_Unicode getStringDelimiter() const { return m_cStringDelimiter; }
+ sal_Unicode getDecimalDelimiter() const { return m_cDecimalDelimiter; }
+ sal_Unicode getThousandDelimiter() const { return m_cThousandDelimiter;}
+ sal_Int32 getMaxRowsToScan() const { return m_nMaxRowsToScan;}
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override;
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EDatabaseMetaData.hxx b/connectivity/source/inc/flat/EDatabaseMetaData.hxx
new file mode 100644
index 000000000..bd6ce7758
--- /dev/null
+++ b/connectivity/source/inc/flat/EDatabaseMetaData.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDatabaseMetaData.hxx>
+
+namespace connectivity::flat
+ {
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class OFlatDatabaseMetaData : public file::ODatabaseMetaData
+ {
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ protected:
+ virtual ~OFlatDatabaseMetaData() override;
+ public:
+ OFlatDatabaseMetaData(file::OConnection* _pCon);
+
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EDriver.hxx b/connectivity/source/inc/flat/EDriver.hxx
new file mode 100644
index 000000000..7ed2718f2
--- /dev/null
+++ b/connectivity/source/inc/flat/EDriver.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <file/FDriver.hxx>
+
+namespace connectivity::flat
+ {
+ /// @throws css::uno::Exception
+ css::uno::Reference< css::uno::XInterface > ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory);
+
+ class ODriver : public file::OFileDriver
+ {
+ public:
+ ODriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) : file::OFileDriver(_rxContext){}
+
+ OUString SAL_CALL getImplementationName( ) override;
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EPreparedStatement.hxx b/connectivity/source/inc/flat/EPreparedStatement.hxx
new file mode 100644
index 000000000..ca164be8d
--- /dev/null
+++ b/connectivity/source/inc/flat/EPreparedStatement.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FPreparedStatement.hxx>
+
+namespace connectivity::flat
+ {
+ class OConnection;
+ class OFlatPreparedStatement : public file::OPreparedStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ OFlatPreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EResultSet.hxx b/connectivity/source/inc/flat/EResultSet.hxx
new file mode 100644
index 000000000..8d99ed55d
--- /dev/null
+++ b/connectivity/source/inc/flat/EResultSet.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FResultSet.hxx>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+namespace connectivity::flat
+ {
+ class OFlatResultSet;
+ // these typedef's are only necessary for the compiler
+ typedef ::cppu::ImplHelper1< css::sdbcx::XRowLocate> OFlatResultSet_BASE;
+ typedef file::OResultSet OFlatResultSet_BASE2;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OFlatResultSet> OFlatResultSet_BASE3;
+
+
+ class OFlatResultSet : public OFlatResultSet_BASE2,
+ public OFlatResultSet_BASE,
+ public OFlatResultSet_BASE3
+ {
+ bool m_bBookmarkable;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ DECLARE_SERVICE_INFO();
+
+ OFlatResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator);
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/EStatement.hxx b/connectivity/source/inc/flat/EStatement.hxx
new file mode 100644
index 000000000..d30bfc709
--- /dev/null
+++ b/connectivity/source/inc/flat/EStatement.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FStatement.hxx>
+
+namespace connectivity::flat
+ {
+ class OConnection;
+ class OFlatStatement : public file::OStatement
+ {
+ protected:
+ virtual rtl::Reference<file::OResultSet> createResultSet() override;
+ public:
+ OFlatStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){}
+ DECLARE_SERVICE_INFO();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/ETable.hxx b/connectivity/source/inc/flat/ETable.hxx
new file mode 100644
index 000000000..ae283c10b
--- /dev/null
+++ b/connectivity/source/inc/flat/ETable.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTable.hxx>
+#include <flat/EConnection.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <file/quotedstring.hxx>
+#include <unotools/syslocale.hxx>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+
+namespace connectivity::flat
+ {
+ typedef file::OFileTable OFlatTable_BASE;
+ class OFlatConnection;
+
+ typedef std::pair<sal_Int32, sal_Int32> TRowPositionInFile;
+
+ class OFlatTable : public OFlatTable_BASE
+ {
+ // maps a row position to a file position
+ // row n is positions [m_aRowPosToFilePos[n]->first, m_aRowPosToFilePos[n]->second) in file
+ // "real" row indexes start at 1; for the purposes of m_aRowPosToFilePos, row 0 is headers
+ std::vector<TRowPositionInFile>
+ m_aRowPosToFilePos;
+ std::vector<sal_Int32> m_aTypes; // holds all type for columns just to avoid to ask the propertyset
+ std::vector<sal_Int32> m_aPrecisions; // same as aboth
+ std::vector<sal_Int32> m_aScales;
+ QuotedTokenizedString m_aCurrentLine;
+ css::uno::Reference< css::util::XNumberFormatter > m_xNumberFormatter;
+ css::util::Date m_aNullDate;
+ sal_Int32 m_nRowPos;
+ sal_Int32 m_nMaxRowCount; // will be set if stream is once eof
+ sal_Unicode m_cStringDelimiter; // delimiter for strings m_cStringDelimiter blabla m_cStringDelimiter
+ sal_Unicode m_cFieldDelimiter; // look at the name
+ bool m_bNeedToReadLine;
+ private:
+ void fillColumns(const css::lang::Locale& _aLocale);
+ bool readLine(sal_Int32 *pEndPos, sal_Int32 *pStartPos, bool nonEmpty = false);
+ void setRowPos(std::vector<TRowPositionInFile>::size_type rowNum, const TRowPositionInFile &rowPos);
+ void impl_fillColumnInfo_nothrow(QuotedTokenizedString const & aFirstLine, sal_Int32& nStartPosFirstLine, sal_Int32& nStartPosFirstLine2,
+ sal_Int32& io_nType, sal_Int32& io_nPrecisions, sal_Int32& io_nScales, OUString& o_sTypeName,
+ const sal_Unicode cDecimalDelimiter, const sal_Unicode cThousandDelimiter, const CharClass& aCharClass);
+ OFlatConnection* getFlatConnection()
+ {
+#if OSL_DEBUG_LEVEL > 0
+ OFlatConnection* pConnection = dynamic_cast<OFlatConnection*>(m_pConnection);
+ assert(pConnection);
+#else
+ OFlatConnection* pConnection = static_cast<OFlatConnection*>(m_pConnection);
+#endif
+ return pConnection;
+ }
+ public:
+ virtual void refreshColumns() override;
+
+ public:
+ // DECLARE_CTY_DEFAULTS( OFlatTable_BASE);
+ OFlatTable( sdbcx::OCollection* _pTables,OFlatConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description = OUString(),
+ const OUString& SchemaName = OUString(),
+ const OUString& CatalogName = OUString()
+ );
+
+ void construct() override; // can throw any exception
+
+ virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override;
+ virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override;
+ virtual void refreshHeader() override;
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ OUString getEntry() const;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/flat/ETables.hxx b/connectivity/source/inc/flat/ETables.hxx
new file mode 100644
index 000000000..cb9b032db
--- /dev/null
+++ b/connectivity/source/inc/flat/ETables.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTables.hxx>
+
+namespace connectivity::flat
+ {
+ typedef file::OTables OFlatTables_BASE;
+
+ class OFlatTables : public OFlatTables_BASE
+ {
+ protected:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ public:
+ OFlatTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector) : OFlatTables_BASE(_rMetaData,_rParent,_rMutex,_rVector)
+ {}
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HCatalog.hxx b/connectivity/source/inc/hsqldb/HCatalog.hxx
new file mode 100644
index 000000000..8d1da42de
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HCatalog.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::hsqldb
+ {
+ // please don't name the class the same name as in another namespaces
+ // some compilers have problems with this task as I noticed on windows
+ class OHCatalog : public connectivity::sdbcx::OCatalog
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ /** calls XDatabaseMetaData::getTables.
+ @param _sKindOfObject
+ The type of tables to be fetched.
+ @param _rNames
+ The container for the names to be filled.
+ */
+ void refreshObjects(const css::uno::Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames);
+
+ public:
+ // implementation of the pure virtual methods
+ virtual void refreshTables() override;
+ virtual void refreshViews() override ;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override ;
+
+ public:
+ OHCatalog(const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+
+ sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); }
+ sdbcx::OCollection* getPrivateViews() const { return m_pViews.get(); }
+ const css::uno::Reference< css::sdbc::XConnection >& getConnection() const { return m_xConnection; }
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // ::cppu::OComponentHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HColumns.hxx b/connectivity/source/inc/hsqldb/HColumns.hxx
new file mode 100644
index 000000000..c27645f45
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HColumns.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity::hsqldb
+ {
+ class OHSQLColumns : public OColumnsHelper
+ {
+ protected:
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ public:
+ OHSQLColumns( ::cppu::OWeakObject& _rParent
+ ,::osl::Mutex& _rMutex
+ ,const ::std::vector< OUString> &_rVector
+ );
+ };
+
+ class OHSQLColumn;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper<OHSQLColumn> OHSQLColumn_PROP;
+
+ class OHSQLColumn : public sdbcx::OColumn,
+ public OHSQLColumn_PROP
+ {
+ OUString m_sAutoIncrement;
+ protected:
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ public:
+ OHSQLColumn();
+ virtual void construct() override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HConnection.hxx b/connectivity/source/inc/hsqldb/HConnection.hxx
new file mode 100644
index 000000000..6e2a54c9c
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HConnection.hxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/ConnectionWrapper.hxx>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdb/application/XTableUIProvider.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+
+namespace connectivity::hsqldb
+ {
+ class SAL_NO_VTABLE IMethodGuardAccess
+ {
+ public:
+ virtual ::osl::Mutex& getMutex() const = 0;
+ virtual void checkDisposed() const = 0;
+
+ protected:
+ ~IMethodGuardAccess() {}
+ };
+
+
+ // OHsqlConnection - wraps all methods to the real connection from the driver
+ // but when disposed it doesn't dispose the real connection
+
+ typedef ::cppu::WeakComponentImplHelper< css::util::XFlushable
+ , css::sdb::application::XTableUIProvider
+ > OHsqlConnection_BASE;
+
+ class OHsqlConnection :public cppu::BaseMutex
+ ,public OHsqlConnection_BASE
+ ,public OConnectionWrapper
+ ,public IMethodGuardAccess
+ {
+ private:
+ ::comphelper::OInterfaceContainerHelper2 m_aFlushListeners;
+ css::uno::Reference< css::sdbc::XDriver > m_xDriver;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ bool m_bIni;
+ bool m_bReadOnly;
+
+ protected:
+ virtual void SAL_CALL disposing() override;
+ virtual ~OHsqlConnection() override;
+
+ public:
+ OHsqlConnection(
+ const css::uno::Reference< css::sdbc::XDriver >& _rxDriver,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const css::uno::Reference< css::uno::XComponentContext>& _rxContext
+ );
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ DECLARE_XTYPEPROVIDER()
+ DECLARE_XINTERFACE( )
+
+ // IMethodGuardAccess
+ virtual ::osl::Mutex& getMutex() const override;
+ virtual void checkDisposed() const override;
+
+ // XFlushable
+ virtual void SAL_CALL flush( ) override;
+ virtual void SAL_CALL addFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override;
+ virtual void SAL_CALL removeFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override;
+
+ // XTableUIProvider
+ virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL getTableIcon( const OUString& TableName, ::sal_Int32 ColorMode ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getTableEditor( const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& DocumentUI, const OUString& TableName ) override;
+
+ private:
+
+ /** retrieves our table container
+ @return
+ our table container. Guaranteed to not be <NULL/>.
+ @throws css::lang::WrappedTargetException
+ if a non-RuntimeException is caught during obtaining the container.
+ @throws css::uno::RuntimeException
+ if a serious error occurs
+ @precond
+ We're not disposed.
+ */
+ css::uno::Reference< css::container::XNameAccess >
+ impl_getTableContainer_throw();
+
+ /** checks whether the given table name denotes an existing table
+ @param _rTableName
+ the fully name of the table to check for existence
+ @throws css::lang::IllegalArgumentException
+ if the name does not denote an existing table
+ @precond
+ We're not disposed.
+ */
+ void impl_checkExistingTable_throw( const OUString& _rTableName );
+
+ /** checks whether the given table name refers to a HSQL TEXT TABLE
+ */
+ bool impl_isTextTable_nothrow( const OUString& _rTableName );
+
+ /** retrieves the icon for HSQL TEXT TABLEs
+ */
+ css::uno::Reference< css::graphic::XGraphic >
+ impl_getTextTableIcon_nothrow();
+ };
+
+
+ // OHsqlConnection
+
+ class MethodGuard : public ::osl::MutexGuard
+ {
+ public:
+ MethodGuard( const IMethodGuardAccess& _rComponent )
+ : ::osl::MutexGuard( _rComponent.getMutex() )
+ {
+ _rComponent.checkDisposed();
+ }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HDriver.hxx b/connectivity/source/inc/hsqldb/HDriver.hxx
new file mode 100644
index 000000000..0dda7e5e0
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HDriver.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/XCreateCatalog.hpp>
+#include <com/sun/star/embed/XTransactionListener.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+
+
+namespace connectivity::hsqldb
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver
+ , css::sdbcx::XDataDefinitionSupplier
+ , css::lang::XServiceInfo
+ , css::sdbcx::XCreateCatalog
+ , css::embed::XTransactionListener
+ > ODriverDelegator_BASE;
+
+ typedef std::pair< css::uno::WeakReferenceHelper,css::uno::WeakReferenceHelper> TWeakRefPair;
+ typedef std::pair< OUString ,TWeakRefPair > TWeakConnectionPair;
+
+ typedef std::pair< css::uno::WeakReferenceHelper,TWeakConnectionPair> TWeakPair;
+ typedef std::vector< TWeakPair > TWeakPairVector;
+
+
+ /** delegates all calls to the original driver and extend the existing one with the SDBCX layer.
+
+ */
+ class ODriverDelegator final : public ::cppu::BaseMutex
+ ,public ODriverDelegator_BASE
+ {
+ TWeakPairVector m_aConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+ css::uno::Reference< css::sdbc::XDriver > m_xDriver;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ bool m_bInShutDownConnections;
+
+ /** load the driver we want to delegate.
+ The <member>m_xDriver</member> may be <NULL/> if the driver could not be loaded.
+ @return
+ The driver which was currently selected.
+ */
+ css::uno::Reference< css::sdbc::XDriver > const & loadDriver( );
+
+ /** shut down the connection and revoke the storage from the map
+ @param _aIter
+ The connection to shut down and storage to revoke.
+ */
+ void shutdownConnection(const TWeakPairVector::iterator& _aIter);
+
+ public:
+ /** creates a new delegator for a HSQLDB driver
+ */
+ ODriverDelegator(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ // XCreateCatalog
+ virtual void SAL_CALL createCatalog( const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XTransactionListener
+ virtual void SAL_CALL preCommit( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL commited( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL preRevert( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL reverted( const css::lang::EventObject& aEvent ) override;
+
+ void shutdownConnections();
+ void flushConnections();
+ private:
+ /// dtor
+ virtual ~ODriverDelegator() override;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ /** called when we connected to a newly created embedded database
+ */
+ void onConnectedNewDatabase(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+ };
+
+
+} // namespace connectivity::hsqldb
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HStorageAccess.hxx b/connectivity/source/inc/hsqldb/HStorageAccess.hxx
new file mode 100644
index 000000000..5a49162c2
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HStorageAccess.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace connectivity::hsqldb
+{
+ class DataLogFile;
+}
+
+jint read_from_storage_stream( JNIEnv * env, jstring name, jstring key );
+jint read_from_storage_stream_into_buffer( JNIEnv * env, jstring name, jstring key, jbyteArray buffer, jint off, jint len );
+void write_to_storage_stream_from_buffer( JNIEnv* env, jstring name, jstring key, jbyteArray buffer, jint off, jint len );
+void write_to_storage_stream( JNIEnv* env, jstring name, jstring key, jint v );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HStorageMap.hxx b/connectivity/source/inc/hsqldb/HStorageMap.hxx
new file mode 100644
index 000000000..06f31e6df
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HStorageMap.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <memory>
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/XTransactionListener.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <uno/environment.hxx>
+
+namespace connectivity::hsqldb
+ {
+ class StreamHelper
+ {
+ css::uno::Reference< css::io::XStream> m_xStream;
+ css::uno::Reference< css::io::XSeekable> m_xSeek;
+ css::uno::Reference< css::io::XOutputStream> m_xOutputStream;
+ css::uno::Reference< css::io::XInputStream> m_xInputStream;
+ public:
+ StreamHelper(const css::uno::Reference< css::io::XStream>& _xStream);
+ ~StreamHelper();
+
+ css::uno::Reference< css::io::XInputStream> const & getInputStream();
+ css::uno::Reference< css::io::XOutputStream> const & getOutputStream();
+ css::uno::Reference< css::io::XSeekable> const & getSeek();
+ };
+
+
+ typedef std::map< OUString, std::shared_ptr<StreamHelper> > TStreamMap;
+
+ struct StorageData {
+ css::uno::Reference<css::embed::XStorage> storage;
+ css::uno::Environment storageEnvironment;
+ OUString url;
+ TStreamMap streams;
+
+ css::uno::Reference<css::embed::XStorage> mapStorage() const;
+ };
+
+ typedef std::map<OUString, StorageData> TStorages;
+ /** contains all storages so far accessed.
+ */
+ class StorageContainer
+ {
+ public:
+ static OUString registerStorage(const css::uno::Reference< css::embed::XStorage>& _xStorage,const OUString& _sURL);
+ static TStorages::mapped_type getRegisteredStorage(const OUString& _sKey);
+ static OUString getRegisteredKey(const css::uno::Reference< css::embed::XStorage>& _xStorage);
+ static void revokeStorage(const OUString& _sKey,const css::uno::Reference< css::embed::XTransactionListener>& _xListener);
+
+ static TStreamMap::mapped_type registerStream(JNIEnv * env,jstring name, jstring key,sal_Int32 _nMode);
+ static void revokeStream(JNIEnv * env,jstring name, jstring key);
+ static TStreamMap::mapped_type getRegisteredStream( JNIEnv * env, jstring name, jstring key);
+
+ static OUString jstring2ustring(JNIEnv * env, jstring jstr);
+ static OUString removeURLPrefix(std::u16string_view _sURL,const OUString& _sFileURL);
+ static OUString removeOldURLPrefix(const OUString& _sURL);
+ static void throwJavaException(const css::uno::Exception& _aException,JNIEnv * env);
+ };
+
+} // namespace connectivity::hsqldb
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HTable.hxx b/connectivity/source/inc/hsqldb/HTable.hxx
new file mode 100644
index 000000000..060784115
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HTable.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <connectivity/TTableHelper.hxx>
+#include <comphelper/IdPropArrayHelper.hxx>
+
+namespace connectivity::hsqldb
+ {
+
+ class OHSQLTable;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper< OHSQLTable > OHSQLTable_PROP;
+ class OHSQLTable : public OTableHelper
+ ,public OHSQLTable_PROP
+ {
+ sal_Int32 m_nPrivileges; // we have to set our privileges by our own
+
+ /** executes the statement.
+ @param _rStatement
+ The statement to execute.
+ */
+ void executeStatement(const OUString& _rStatement );
+ protected:
+
+ /** creates the column collection for the table
+ @param _rNames
+ The column names.
+ */
+ virtual sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the key collection for the table
+ @param _rNames
+ The key names.
+ */
+ virtual sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the index collection for the table
+ @param _rNames
+ The index names.
+ */
+ virtual sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override;
+
+ /** used to implement the creation of the array helper which is shared amongst all instances of the class.
+ This method needs to be implemented in derived classes.
+ <BR>
+ The method gets called with s_aMutex acquired.
+ @return a pointer to the newly created array helper. Must not be NULL.
+ */
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ public:
+ OHSQLTable( sdbcx::OCollection* _pTables,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+ OHSQLTable( sdbcx::OCollection* _pTables,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName,
+ sal_Int32 _nPrivileges
+ );
+
+ // ODescriptor
+ virtual void construct() override;
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ /**
+ returns the ALTER TABLE XXX COLUMN statement
+ */
+ OUString getAlterTableColumnPart() const;
+
+ // some methods to alter table structures
+ void alterColumnType(sal_Int32 nNewType,const OUString& _rColName,const css::uno::Reference< css::beans::XPropertySet >& _xDescriptor);
+ void alterDefaultValue(std::u16string_view _sNewDefault,const OUString& _rColName);
+ void dropDefaultValue(const OUString& _sNewDefault);
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HTables.hxx b/connectivity/source/inc/hsqldb/HTables.hxx
new file mode 100644
index 000000000..a421be35e
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HTables.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+namespace connectivity::hsqldb
+ {
+ class OTables final : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void createTable( const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+ virtual OUString getNameForObject(const sdbcx::ObjectType& _xObject) override;
+ public:
+ OTables(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)
+ {}
+
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ // XDrop
+ void appendNew(const OUString& _rsNewTable);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HTools.hxx b/connectivity/source/inc/hsqldb/HTools.hxx
new file mode 100644
index 000000000..a847b2d9a
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HTools.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustrbuf.hxx>
+
+
+namespace connectivity::hsqldb
+{
+
+ class HTools
+ {
+ public:
+ /** appends a proper WHERE clause to the given buffer, which filters
+ for a given table name
+
+ @param _bShortForm
+ <TRUE/> if the column names of the system table which is being asked
+ have the short form (TABLE_CAT instead of TABLE_CATALOG, and so on)
+ */
+ static void appendTableFilterCrit(
+ OUStringBuffer& _inout_rBuffer, std::u16string_view _rCatalog,
+ std::u16string_view _rSchema, std::u16string_view _rName,
+ bool _bShortForm
+ );
+ };
+
+
+} // namespace connectivity::hsqldb
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HUser.hxx b/connectivity/source/inc/hsqldb/HUser.hxx
new file mode 100644
index 000000000..dc69c636e
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HUser.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VUser.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace connectivity::hsqldb
+ {
+ typedef connectivity::sdbcx::OUser OUser_TYPEDEF;
+
+ class OHSQLUser : public OUser_TYPEDEF
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ static OUString getPrivilegeString(sal_Int32 nRights);
+ // return the privileges and additional the grant rights
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant);
+ public:
+ virtual void refreshGroups() override;
+ public:
+ OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+ OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const OUString& Name);
+
+ // XUser
+ virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override;
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ };
+
+ class OUserExtend;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;
+
+ class OUserExtend : public OHSQLUser,
+ public OUserExtend_PROP
+ {
+ OUString m_Password;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OUserExtend(const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+
+ virtual void construct() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HUsers.hxx b/connectivity/source/inc/hsqldb/HUsers.hxx
new file mode 100644
index 000000000..5f72bceb7
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HUsers.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+namespace connectivity
+{
+ namespace sdbcx
+ {
+ class IRefreshableUsers;
+ }
+ namespace hsqldb
+ {
+ class OUsers : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ connectivity::sdbcx::IRefreshableUsers* m_pParent;
+ public:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual void impl_refresh() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ OUsers( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ connectivity::sdbcx::IRefreshableUsers* _pParent);
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HView.hxx b/connectivity/source/inc/hsqldb/HView.hxx
new file mode 100644
index 000000000..62e8e5f45
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HView.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VView.hxx>
+
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+
+namespace connectivity::hsqldb
+{
+
+ typedef ::connectivity::sdbcx::OView HView_Base;
+ typedef ::cppu::ImplHelper1< css::sdbcx::XAlterView > HView_IBASE;
+ class HView :public HView_Base
+ ,public HView_IBASE
+ {
+ public:
+ HView(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ bool _bCaseSensitive,
+ const OUString& _rSchemaName,
+ const OUString& _rName
+ );
+
+ // UNO
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XAlterView
+ virtual void SAL_CALL alterCommand( const OUString& NewCommand ) override;
+
+ protected:
+ virtual ~HView() override;
+
+ protected:
+ // OPropertyContainer
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override;
+
+ private:
+ /** retrieves the current command of the View */
+ OUString impl_getCommand() const;
+
+ /** retrieves the current command of the View
+
+ @throws css::lang::WrappedTargetException
+ if an error occurs while retrieving the command from the database.
+ */
+ OUString impl_getCommand_wrapSQLException() const;
+ /** retrieves the current command of the View
+
+ @throws css::sdbc::SQLException
+ if an error occurs while retrieving the command from the database.
+ */
+ OUString impl_getCommand_throwSQLException() const;
+
+ private:
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ private:
+ using HView_Base::getFastPropertyValue;
+ };
+
+
+} // namespace connectivity::hsqldb
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/hsqldb/HViews.hxx b/connectivity/source/inc/hsqldb/HViews.hxx
new file mode 100644
index 000000000..cb2041524
--- /dev/null
+++ b/connectivity/source/inc/hsqldb/HViews.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+namespace connectivity::hsqldb
+ {
+ class HViews final : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ bool m_bInDrop;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void createView( const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+ public:
+ HViews(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, const ::std::vector< OUString> &_rVector );
+
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ void dropByNameImpl(const OUString& elementName);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/ContextClassLoader.hxx b/connectivity/source/inc/java/ContextClassLoader.hxx
new file mode 100644
index 000000000..e7079239a
--- /dev/null
+++ b/connectivity/source/inc/java/ContextClassLoader.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/GlobalRef.hxx>
+
+namespace comphelper
+{
+ class EventLogger;
+}
+
+
+namespace connectivity::jdbc
+{
+ class ContextClassLoaderScope
+ {
+ public:
+ /** creates the instance. If isActive returns <FALSE/> afterwards, then an exception
+ happened in the JVM, which should be raised as UNO exception by the caller
+
+ @param environment
+ the current JNI environment
+ @param newClassLoader
+ the new class loader to set at the current thread
+ @param _rLoggerForErrors
+ the logger which should be passed to java_lang_object::ThrowLoggedSQLException in case
+ an error occurs
+ @param _rxErrorContext
+ the context which should be passed to java_lang_object::ThrowLoggedSQLException in case
+ an error occurs
+
+ */
+ ContextClassLoaderScope(
+ JNIEnv& environment,
+ const GlobalRef< jobject >& newClassLoader,
+ const ::comphelper::EventLogger& _rLoggerForErrors,
+ const css::uno::Reference< css::uno::XInterface >& _rxErrorContext
+ );
+
+ ~ContextClassLoaderScope();
+
+ bool isActive() const
+ {
+ return ( m_currentThread.is() )
+ && ( m_setContextClassLoaderMethod != nullptr );
+ }
+
+ private:
+ ContextClassLoaderScope(ContextClassLoaderScope const &) = delete;
+ ContextClassLoaderScope& operator =(ContextClassLoaderScope const &) = delete;
+
+ JNIEnv& m_environment;
+ LocalRef< jobject > m_currentThread;
+ LocalRef< jobject > m_oldContextClassLoader;
+ jmethodID m_setContextClassLoaderMethod;
+ };
+
+
+} // namespace connectivity::jdbc
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/GlobalRef.hxx b/connectivity/source/inc/java/GlobalRef.hxx
new file mode 100644
index 000000000..1a97bfb33
--- /dev/null
+++ b/connectivity/source/inc/java/GlobalRef.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/LocalRef.hxx>
+#include <java/lang/Object.hxx>
+
+
+namespace connectivity::jdbc
+{
+ /** helper class to hold a local ref to a JNI object
+ */
+ template< typename T >
+ class GlobalRef
+ {
+ public:
+ GlobalRef()
+ :m_object( nullptr )
+ {
+ }
+
+ GlobalRef( const GlobalRef& _source )
+ :m_object( nullptr )
+ {
+ *this = _source;
+ }
+
+ GlobalRef& operator=( const GlobalRef& _source )
+ {
+ if ( &_source == this )
+ return *this;
+
+ SDBThreadAttach t;
+ set( t.env(), _source.get() );
+ return *this;
+ }
+
+ ~GlobalRef() COVERITY_NOEXCEPT_FALSE
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ if ( m_object != nullptr )
+ {
+ SDBThreadAttach t;
+ t.env().DeleteGlobalRef( m_object );
+ m_object = nullptr;
+ }
+ }
+
+ void set( JNIEnv& _environment, T _object )
+ {
+ if ( m_object != nullptr )
+ _environment.DeleteGlobalRef( m_object );
+ m_object = _object;
+ if ( m_object )
+ m_object = static_cast< T >( _environment.NewGlobalRef( m_object ) );
+ }
+
+ void set( LocalRef< T >& _object )
+ {
+ set( _object.env(), _object.release() );
+ }
+
+ T get() const
+ {
+ return m_object;
+ }
+
+ bool is() const
+ {
+ return m_object != nullptr;
+ }
+
+ private:
+ T m_object;
+ };
+
+
+} // namespace connectivity::jdbc
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/LocalRef.hxx b/connectivity/source/inc/java/LocalRef.hxx
new file mode 100644
index 000000000..ad40737f8
--- /dev/null
+++ b/connectivity/source/inc/java/LocalRef.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace connectivity::jdbc
+{
+
+ /** helper class to hold a local ref to a JNI object
+
+ Note that this class never actually calls NewLocalRef. It is assumed that all objects
+ passed are already acquired with a local ref (as it usually is the case if you obtain
+ the object from a JNI method).
+ */
+ template< typename T >
+ class LocalRef final
+ {
+ public:
+ explicit LocalRef( JNIEnv& environment )
+ :m_environment( environment )
+ ,m_object( nullptr )
+ {
+ }
+
+ LocalRef( JNIEnv& environment, T object )
+ :m_environment( environment )
+ ,m_object( object )
+ {
+ }
+
+ ~LocalRef()
+ {
+ reset();
+ }
+
+ T release()
+ {
+ T t = m_object;
+ m_object = nullptr;
+ return t;
+ }
+
+ void set( T object ) { reset(); m_object = object; }
+
+ void reset()
+ {
+ if ( m_object != nullptr )
+ {
+ m_environment.DeleteLocalRef( m_object );
+ m_object = nullptr;
+ }
+ }
+
+ JNIEnv& env() const { return m_environment; }
+ T get() const { return m_object; }
+ bool is() const { return m_object != nullptr; }
+
+ private:
+ LocalRef(LocalRef const &) = delete;
+ LocalRef& operator =(LocalRef const &) = delete;
+
+ JNIEnv& m_environment;
+ T m_object;
+ };
+
+
+} // namespace connectivity::jdbc
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/io/InputStream.hxx b/connectivity/source/inc/java/io/InputStream.hxx
new file mode 100644
index 000000000..4a0b5788f
--- /dev/null
+++ b/connectivity/source/inc/java/io/InputStream.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.io.InputStream
+
+ class java_io_InputStream : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::io::XInputStream>
+ {
+ protected:
+ // static Data for the Class
+ static jclass theClass;
+ virtual ~java_io_InputStream() override;
+ public:
+ virtual jclass getMyClass() const override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_io_InputStream( JNIEnv * pEnv, jobject myObj );
+ // XInputStream
+ virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+ virtual sal_Int32 SAL_CALL available( ) override;
+ virtual void SAL_CALL closeInput( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/io/Reader.hxx b/connectivity/source/inc/java/io/Reader.hxx
new file mode 100644
index 000000000..8386eda44
--- /dev/null
+++ b/connectivity/source/inc/java/io/Reader.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <optional>
+
+namespace connectivity
+{
+
+ //************ Class: java.io.InputStream
+
+ class java_io_Reader final : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::io::XInputStream>
+ {
+ // static Data for the Class
+ static jclass theClass;
+ virtual ~java_io_Reader() override;
+ std::optional<char> m_buf;
+ public:
+ virtual jclass getMyClass() const override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_io_Reader( JNIEnv * pEnv, jobject myObj );
+ // XInputStream
+ virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+ virtual sal_Int32 SAL_CALL available( ) override;
+ virtual void SAL_CALL closeInput( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Boolean.hxx b/connectivity/source/inc/java/lang/Boolean.hxx
new file mode 100644
index 000000000..536ba5de3
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Boolean.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+//************ Class: java.lang.Boolean
+
+namespace connectivity
+{
+ class java_lang_Boolean : public java_lang_Object
+ {
+ protected:
+ // static Data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_Boolean() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_Boolean( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+
+ static jclass st_getMyClass();
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Class.hxx b/connectivity/source/inc/java/lang/Class.hxx
new file mode 100644
index 000000000..bcd5628c1
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Class.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+//************ Class: java.lang.Class
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+ class java_lang_Class : public java_lang_Object
+ {
+ protected:
+ // static Data for the Class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_Class() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_Class( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+
+ static java_lang_Class * forName( std::u16string_view _par0 );
+ // return the jre object
+ jobject newInstanceObject();
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Exception.hxx b/connectivity/source/inc/java/lang/Exception.hxx
new file mode 100644
index 000000000..28b2d56dc
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Exception.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Throwable.hxx>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.lang.Exception
+
+ class java_lang_Exception : public java_lang_Throwable{
+ protected:
+ // statis Data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_Exception() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_Exception( JNIEnv * pEnv, jobject myObj ) : java_lang_Throwable( pEnv, myObj ){}
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Object.hxx b/connectivity/source/inc/java/lang/Object.hxx
new file mode 100644
index 000000000..63d7af3f5
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Object.hxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <jvmaccess/virtualmachine.hxx>
+
+#ifdef HAVE_64BIT_POINTERS
+#error "no 64 bit pointer"
+#endif //HAVE_64BIT_POINTERS
+
+namespace comphelper
+{
+ class EventLogger;
+}
+
+namespace connectivity
+{
+ class SDBThreadAttach
+ {
+ jvmaccess::VirtualMachine::AttachGuard m_aGuard;
+ SDBThreadAttach(SDBThreadAttach const &) = delete;
+ SDBThreadAttach& operator= (SDBThreadAttach const &) = delete;
+ public:
+ SDBThreadAttach();
+ ~SDBThreadAttach();
+
+ JNIEnv* pEnv;
+ static void addRef();
+ static void releaseRef();
+
+ public:
+ JNIEnv& env() const
+ {
+ // according to the documentation of jvmaccess::VirtualMachine::AttachGuard, our env is never
+ // NULL, so why bothering with pointer checks?
+ return *pEnv;
+ }
+ };
+
+
+ class java_lang_Object
+ {
+ java_lang_Object& operator= (java_lang_Object const &) = delete;
+ java_lang_Object(java_lang_Object const &) = delete;
+
+ protected:
+ // The Java handle to this class
+ jobject object;
+
+ // Class definition
+ // New in SJ2:
+ static jclass theClass; // The class needs to be requested only once!
+
+ virtual jclass getMyClass() const;
+
+ public:
+ // Ctor that should be used for the derived classes
+ java_lang_Object( JNIEnv * pEnv, jobject myObj );
+
+ // The actual ctor
+ java_lang_Object();
+
+ virtual ~java_lang_Object() COVERITY_NOEXCEPT_FALSE;
+
+ void saveRef( JNIEnv * pEnv, jobject myObj );
+ jobject getJavaObject() const { return object; }
+ void clearObject(JNIEnv& rEnv);
+ void clearObject();
+
+ OUString toString() const;
+
+ static void ThrowSQLException(JNIEnv * pEnv,const css::uno::Reference< css::uno::XInterface> & _rContext);
+ static void ThrowLoggedSQLException(
+ const ::comphelper::EventLogger& _rLogger,
+ JNIEnv* pEnvironment,
+ const css::uno::Reference< css::uno::XInterface >& _rxContext
+ );
+ static void ThrowRuntimeException(JNIEnv * pEnv,const css::uno::Reference< css::uno::XInterface> & _rContext);
+
+ static ::rtl::Reference< jvmaccess::VirtualMachine > getVM(const css::uno::Reference< css::uno::XComponentContext >& _rxContext=nullptr);
+
+ static jclass findMyClass(const char* _pClassName);
+ void obtainMethodId_throwSQL(JNIEnv* _pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID) const;
+ void obtainMethodId_throwRuntime(JNIEnv* _pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID) const;
+
+ bool callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const;
+ bool callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ jobject callResultSetMethod( JNIEnv& _rEnv, const char* _pMethodName, jmethodID& _inout_MethodID ) const;
+ sal_Int32 callIntMethod_ThrowSQL(const char* _pMethodName, jmethodID& _inout_MethodID) const;
+ sal_Int32 callIntMethod_ThrowRuntime(const char* _pMethodName, jmethodID& _inout_MethodID) const;
+ sal_Int32 callIntMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ sal_Int32 callIntMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ sal_Int32 callIntMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const;
+ OUString callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const;
+ OUString callStringMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const;
+ void callVoidMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID) const;
+ void callVoidMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID) const;
+ void callVoidMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ void callVoidMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const;
+ void callVoidMethodWithBoolArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const;
+ void callVoidMethodWithBoolArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const;
+ void callVoidMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID, const OUString& _nArgument ) const;
+ jobject callObjectMethod( JNIEnv * pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID ) const;
+ jobject callObjectMethodWithIntArg( JNIEnv * pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const;
+
+ template< typename T >
+ T callMethodWithIntArg(T (JNIEnv::*pCallMethod)( jobject obj, jmethodID methodID, ... ) ,const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const
+ {
+ SDBThreadAttach t;
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,_pSignature, _inout_MethodID);
+ T out = (t.pEnv->*pCallMethod)( object, _inout_MethodID,_nArgument);
+ ThrowSQLException( t.pEnv, nullptr );
+ return out;
+ }
+
+ template< typename T >
+ void callVoidMethod_ThrowSQL(const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID,sal_Int32 _nArgument, const T& _aValue) const
+ {
+ SDBThreadAttach t;
+ obtainMethodId_throwSQL(t.pEnv, _pMethodName,_pSignature, _inout_MethodID);
+ t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument,_aValue);
+ ThrowSQLException( t.pEnv, nullptr );
+ }
+
+
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/String.hxx b/connectivity/source/inc/java/lang/String.hxx
new file mode 100644
index 000000000..2783b6eeb
--- /dev/null
+++ b/connectivity/source/inc/java/lang/String.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+ class java_lang_String : public java_lang_Object
+ {
+ protected:
+ // statis Data for the Class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_String() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_String( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+
+ operator OUString();
+
+ static jclass st_getMyClass();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/lang/Throwable.hxx b/connectivity/source/inc/java/lang/Throwable.hxx
new file mode 100644
index 000000000..65cfc24fe
--- /dev/null
+++ b/connectivity/source/inc/java/lang/Throwable.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+
+ //************ Class: java.lang.Throwable
+
+ class java_lang_Throwable : public java_lang_Object
+ {
+ protected:
+ // static Data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_lang_Throwable() override;
+ // a Constructor, that is needed for when Returning the Object is needed:
+ java_lang_Throwable( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+ OUString getMessage() const;
+ OUString getLocalizedMessage() const;
+
+#if OSL_DEBUG_LEVEL > 0
+ void printStackTrace() const;
+#endif
+
+ static jclass st_getMyClass();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/math/BigDecimal.hxx b/connectivity/source/inc/java/math/BigDecimal.hxx
new file mode 100644
index 000000000..f4fb684b8
--- /dev/null
+++ b/connectivity/source/inc/java/math/BigDecimal.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+//************ Class: java.lang.Boolean
+
+namespace connectivity
+{
+ class java_math_BigDecimal : public java_lang_Object
+ {
+ // static Data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_math_BigDecimal() override;
+
+ java_math_BigDecimal( const OUString& _par0 );
+ java_math_BigDecimal( const double& _par0 );
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Array.hxx b/connectivity/source/inc/java/sql/Array.hxx
new file mode 100644
index 000000000..93cce6938
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Array.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XArray.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.sql.SQLWarning
+
+ class java_sql_Array : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::sdbc::XArray>
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_Array() override;
+ // A ctor that is needed for returning the object
+ java_sql_Array( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+
+ // XArray
+ virtual OUString SAL_CALL getBaseTypeName( ) override;
+ virtual sal_Int32 SAL_CALL getBaseType( ) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArray( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArrayAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSetAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Blob.hxx b/connectivity/source/inc/java/sql/Blob.hxx
new file mode 100644
index 000000000..02ac0df13
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Blob.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XBlob.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.sql.SQLWarning
+
+ class java_sql_Blob : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::sdbc::XBlob>
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ virtual ~java_sql_Blob() override;
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Blob( JNIEnv * pEnv, jobject myObj );
+
+ // XBlob
+ virtual sal_Int64 SAL_CALL length( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int64 pos, sal_Int32 length ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( ) override;
+ virtual sal_Int64 SAL_CALL position( const css::uno::Sequence< sal_Int8 >& pattern, sal_Int64 start ) override;
+ virtual sal_Int64 SAL_CALL positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& pattern, sal_Int64 start ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/CallableStatement.hxx b/connectivity/source/inc/java/sql/CallableStatement.hxx
new file mode 100644
index 000000000..739183774
--- /dev/null
+++ b/connectivity/source/inc/java/sql/CallableStatement.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/sql/PreparedStatement.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XOutParameters.hpp>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.sql.CallableStatement
+
+
+ class java_sql_CallableStatement : public java_sql_PreparedStatement,
+ public css::sdbc::XRow,
+ public css::sdbc::XOutParameters
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ virtual void createStatement(JNIEnv* _pEnv) override;
+
+ virtual ~java_sql_CallableStatement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_CallableStatement( JNIEnv * pEnv, java_sql_Connection& _rCon, const OUString& sql );
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XOutParameters
+ virtual void SAL_CALL registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Clob.hxx b/connectivity/source/inc/java/sql/Clob.hxx
new file mode 100644
index 000000000..67a69bb6d
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Clob.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XClob.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.sql.SQLWarning
+
+ class java_sql_Clob : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::sdbc::XClob>
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ virtual ~java_sql_Clob() override;
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Clob( JNIEnv * pEnv, jobject myObj );
+
+ // XClob
+ virtual sal_Int64 SAL_CALL length( ) override;
+ virtual OUString SAL_CALL getSubString( sal_Int64 pos, sal_Int32 length ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( ) override;
+ virtual sal_Int64 SAL_CALL position( const OUString& searchstr, sal_Int32 start ) override;
+ virtual sal_Int64 SAL_CALL positionOfClob( const css::uno::Reference< css::sdbc::XClob >& pattern, sal_Int64 start ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Connection.hxx b/connectivity/source/inc/java/sql/Connection.hxx
new file mode 100644
index 000000000..444d44df5
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Connection.hxx
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <TConnection.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <AutoRetrievingBase.hxx>
+#include <java/sql/ConnectionLog.hxx>
+#include <java/GlobalRef.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+
+namespace connectivity
+{
+ class java_sql_Driver;
+
+ typedef OMetaConnection java_sql_Connection_BASE;
+
+ class java_sql_Connection : public java_sql_Connection_BASE,
+ public java_lang_Object,
+ public OAutoRetrievingBase
+ {
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ const java_sql_Driver* m_pDriver;
+ jobject m_pDriverobject;
+ jdbc::GlobalRef< jobject >
+ m_pDriverClassLoader;
+
+ jclass m_Driver_theClass;
+ java::sql::ConnectionLog
+ m_aLogger;
+ bool m_bIgnoreDriverPrivileges;
+ bool m_bIgnoreCurrency;
+ css::uno::Any m_aCatalogRestriction;
+ css::uno::Any m_aSchemaRestriction;
+
+ /** transform named parameter into unnamed one.
+ @param _sSQL
+ The SQL statement to transform.
+ @return
+ The new statement with unnamed parameters.
+ */
+ OUString transFormPreparedStatement(const OUString& _sSQL);
+ void loadDriverFromProperties(
+ const OUString& _sDriverClass,
+ const OUString& _sDriverClassPath,
+ const css::uno::Sequence< css::beans::NamedValue >& _rSystemProperties
+ );
+ /** load driver class path from system configuration.
+ @param _sDriverClass
+ The driver class name to look for in the configuration.
+ */
+ OUString impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass);
+
+ protected:
+ // Static data for the class
+ static jclass theClass;
+
+ virtual ~java_sql_Connection() override;
+
+ public:
+ virtual jclass getMyClass() const override;
+
+ DECLARE_SERVICE_INFO();
+ // A ctor that is needed for returning the object
+ java_sql_Connection( const java_sql_Driver& _rDriver );
+ bool construct( const OUString& url,
+ const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ const css::uno::Sequence< css::beans::PropertyValue >&
+ getConnectionInfo() const { return m_aConnectionInfo; }
+
+ bool isIgnoreDriverPrivilegesEnabled() const { return m_bIgnoreDriverPrivileges;}
+ bool isIgnoreCurrencyEnabled() const { return m_bIgnoreCurrency; }
+ const css::uno::Any& getCatalogRestriction() const { return m_aCatalogRestriction; }
+ const css::uno::Any& getSchemaRestriction() const { return m_aSchemaRestriction; }
+
+ /** returns the instance used for logging events related to this connection
+ */
+ const java::sql::ConnectionLog& getLogger() const { return m_aLogger; }
+
+ /** returns the class loader which was used to load the driver class
+
+ Usually used in conjunction with a ContextClassLoaderScope instance.
+ */
+ const jdbc::GlobalRef< jobject >& getDriverClassLoader() const { return m_pDriverClassLoader; }
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/ConnectionLog.hxx b/connectivity/source/inc/java/sql/ConnectionLog.hxx
new file mode 100644
index 000000000..cea19cdff
--- /dev/null
+++ b/connectivity/source/inc/java/sql/ConnectionLog.hxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/logging/LogLevel.hpp>
+
+#include <rtl/ustring.hxx>
+
+// Strange enough, GCC requires the following forward declarations of the various
+// convertLogArgToString flavors to be *before* the inclusion of comphelper/logging.hxx
+
+namespace com::sun::star::util
+{
+ struct Date;
+ struct Time;
+ struct DateTime;
+}
+
+
+namespace comphelper::log::convert
+{
+
+
+ // helpers for logging more data types than are defined in comphelper/logging.hxx
+ OUString convertLogArgToString( const css::util::Date& _rDate );
+ OUString convertLogArgToString( const css::util::Time& _rTime );
+ OUString convertLogArgToString( const css::util::DateTime& _rDateTime );
+
+
+}
+
+
+#include <comphelper/logging.hxx>
+
+namespace connectivity
+{
+ namespace LogLevel = css::logging::LogLevel;
+}
+
+
+namespace connectivity::java::sql {
+
+ typedef ::comphelper::EventLogger ConnectionLog_Base;
+ class ConnectionLog : public ConnectionLog_Base
+ {
+ public:
+ enum ObjectType
+ {
+ CONNECTION = 0,
+ STATEMENT,
+ RESULTSET,
+
+ ObjectTypeCount = RESULTSET + 1
+ };
+
+ private:
+ const sal_Int32 m_nObjectID;
+
+ public:
+ /// will construct an instance of ObjectType CONNECTION
+ ConnectionLog( const ::comphelper::EventLogger & _rDriverLog );
+ /// will create an instance with the same object ID / ObjectType as a given source instance
+ ConnectionLog( const ConnectionLog& _rSourceLog );
+ /// will create an instance of arbitrary ObjectType
+ ConnectionLog( const ConnectionLog& _rSourceLog, ObjectType _eType );
+
+ sal_Int32 getObjectID() const { return m_nObjectID; }
+
+ /// logs a given message, without any arguments, or source class/method names
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage )
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID );
+ }
+
+ template< typename ARGTYPE1 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1 );
+ }
+
+ template< typename ARGTYPE1, typename ARGTYPE2 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2 );
+ }
+
+ template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3 );
+ }
+
+ template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3, typename ARGTYPE4 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3, ARGTYPE4 _argument4 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3, _argument4 );
+ }
+
+ template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3, typename ARGTYPE4, typename ARGTYPE5 >
+ void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3, ARGTYPE4 _argument4, ARGTYPE5 _argument5 ) const
+ {
+ ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3, _argument4, _argument5 );
+ }
+ };
+
+
+} // namespace connectivity::java::sql
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/DatabaseMetaData.hxx b/connectivity/source/inc/java/sql/DatabaseMetaData.hxx
new file mode 100644
index 000000000..eb43f2537
--- /dev/null
+++ b/connectivity/source/inc/java/sql/DatabaseMetaData.hxx
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <TDatabaseMetaDataBase.hxx>
+
+#include <java/sql/ConnectionLog.hxx>
+
+namespace connectivity
+{
+ class java_sql_Connection;
+
+ //************ Class: java.sql.DatabaseMetaDataDate
+
+
+ class java_sql_DatabaseMetaData : public ODatabaseMetaDataBase,
+ public java_lang_Object
+ {
+ java_sql_Connection* m_pConnection;
+ java::sql::ConnectionLog m_aLogger;
+
+ // Static data for the class
+ static jclass theClass;
+
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_DatabaseMetaData() override;
+ // A ctor that is needed for returning the object
+ java_sql_DatabaseMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rConnection );
+
+ private:
+
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+
+ private:
+ bool impl_callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID );
+ OUString impl_callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID );
+ sal_Int32 impl_callIntMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID );
+ sal_Int32 impl_callIntMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID );
+ bool impl_callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument );
+ css::uno::Reference< css::sdbc::XResultSet >
+ impl_callResultSetMethod( const char* _pMethodName, jmethodID& _inout_MethodID );
+ css::uno::Reference< css::sdbc::XResultSet >
+ impl_callResultSetMethodWithStrings( const char* _pMethodName, jmethodID& _inout_MethodID, const css::uno::Any& _rCatalog,
+ const OUString& _rSchemaPattern, const OUString& _rLeastPattern,
+ const OUString* _pOptionalAdditionalString = nullptr);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Driver.hxx b/connectivity/source/inc/java/sql/Driver.hxx
new file mode 100644
index 000000000..805df2ed1
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Driver.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <comphelper/logging.hxx>
+
+namespace connectivity
+{
+ class java_sql_Driver : public ::cppu::WeakImplHelper< css::sdbc::XDriver,css::lang::XServiceInfo>
+ {
+ css::uno::Reference<css::uno::XComponentContext> m_aContext;
+ ::comphelper::EventLogger m_aLogger;
+
+ protected:
+ virtual ~java_sql_Driver() override;
+
+ public:
+ java_sql_Driver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override ;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override ;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override ;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override ;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ const css::uno::Reference<css::uno::XComponentContext>& getContext() const { return m_aContext; }
+ const ::comphelper::EventLogger& getLogger() const { return m_aLogger; }
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx b/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx
new file mode 100644
index 000000000..4bc681622
--- /dev/null
+++ b/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+
+
+//************ Class: java.sql.DriverPropertyInfo
+
+ class java_sql_DriverPropertyInfo : public java_lang_Object
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_DriverPropertyInfo() override;
+ };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/JStatement.hxx b/connectivity/source/inc/java/sql/JStatement.hxx
new file mode 100644
index 000000000..89a091bd9
--- /dev/null
+++ b/connectivity/source/inc/java/sql/JStatement.hxx
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <java/sql/Connection.hxx>
+#include <java/sql/ConnectionLog.hxx>
+
+namespace connectivity
+{
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable,
+ css::sdbc::XGeneratedResultSet,
+ css::sdbc::XMultipleResults> java_sql_Statement_BASE;
+
+ //************ Class: java.sql.Statement
+
+ class java_sql_Statement_Base : public cppu::BaseMutex,
+ public java_sql_Statement_BASE,
+ public java_lang_Object,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<java_sql_Statement_Base>
+
+ {
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getQueryTimeOut();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getMaxFieldSize();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getMaxRows();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetConcurrency();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetType();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchDirection();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getCursorName();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setQueryTimeOut(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setMaxFieldSize(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setMaxRows(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setResultSetConcurrency(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setResultSetType(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setCursorName(const OUString &_par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setEscapeProcessing(bool _par0);
+
+ protected:
+ css::uno::Reference< css::sdbc::XStatement> m_xGeneratedStatement;
+ rtl::Reference<java_sql_Connection> m_pConnection;
+ java::sql::ConnectionLog m_aLogger;
+ OUString m_sSqlStatement;
+ // Properties
+ sal_Int32 m_nResultSetConcurrency;
+ sal_Int32 m_nResultSetType;
+ bool m_bEscapeProcessing;
+
+
+ // Static data for the class
+ static jclass theClass;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+
+ virtual void createStatement(JNIEnv* _pEnv) = 0;
+
+ virtual ~java_sql_Statement_Base() override;
+
+ sal_Int32 impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID);
+ sal_Int32 impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nDefault);
+
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Statement_Base( JNIEnv * pEnv, java_sql_Connection& _rCon );
+
+ sal_Int32 getStatementObjectID() const { return m_aLogger.getObjectID(); }
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+ //XGeneratedResultSet
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues( ) override;
+
+ public:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+
+ class OStatement_BASE2 : public java_sql_Statement_Base
+
+ {
+ public:
+ OStatement_BASE2(JNIEnv * pEnv, java_sql_Connection& _rCon ) : java_sql_Statement_Base( pEnv, _rCon ) {}
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+
+ class java_sql_Statement : public OStatement_BASE2,
+ public css::sdbc::XBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+
+ virtual void createStatement(JNIEnv* _pEnv) override;
+
+ virtual ~java_sql_Statement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Statement( JNIEnv * pEnv, java_sql_Connection& _rCon ) : OStatement_BASE2( pEnv, _rCon){};
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ // XBatchExecution
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/PreparedStatement.hxx b/connectivity/source/inc/java/sql/PreparedStatement.hxx
new file mode 100644
index 000000000..711fd2d00
--- /dev/null
+++ b/connectivity/source/inc/java/sql/PreparedStatement.hxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/sql/JStatement.hxx>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity
+{
+
+ //************ Class: java.sql.PreparedStatement
+
+
+ class java_sql_PreparedStatement : public OStatement_BASE2,
+ public css::sdbc::XPreparedStatement,
+ public css::sdbc::XResultSetMetaDataSupplier,
+ public css::sdbc::XParameters,
+ public css::sdbc::XPreparedBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+
+ virtual void createStatement(JNIEnv* _pEnv) override;
+ virtual ~java_sql_PreparedStatement() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_PreparedStatement( JNIEnv * pEnv, java_sql_Connection& _rCon,const OUString& sql );
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XPreparedBatchExecution
+ virtual void SAL_CALL addBatch( ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ public:
+ using java_sql_Statement_Base::executeQuery;
+ using java_sql_Statement_Base::executeUpdate;
+ using java_sql_Statement_Base::execute;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Ref.hxx b/connectivity/source/inc/java/sql/Ref.hxx
new file mode 100644
index 000000000..f127178b2
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Ref.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XRef.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+ //************ Class: java.sql.Ref
+
+ class java_sql_Ref : public java_lang_Object,
+ public ::cppu::WeakImplHelper< css::sdbc::XRef>
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ virtual ~java_sql_Ref() override;
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_Ref( JNIEnv * pEnv, jobject myObj );
+
+ // XRef
+ virtual OUString SAL_CALL getBaseTypeName( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/ResultSet.hxx b/connectivity/source/inc/java/sql/ResultSet.hxx
new file mode 100644
index 000000000..183c6fa3a
--- /dev/null
+++ b/connectivity/source/inc/java/sql/ResultSet.hxx
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <java/sql/JStatement.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <java/sql/ConnectionLog.hxx>
+
+namespace connectivity
+{
+
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo> java_sql_ResultSet_BASE;
+
+ class java_sql_Connection;
+ class java_sql_ResultSet : public cppu::BaseMutex,
+ public java_sql_ResultSet_BASE,
+ public java_lang_Object,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<java_sql_ResultSet>
+ {
+ css::uno::Reference< css::uno::XInterface> m_xStatement;
+ java::sql::ConnectionLog m_aLogger;
+ java_sql_Connection* m_pConnection;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetConcurrency() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getResultSetType() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchDirection() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getFetchSize() const;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getCursorName() const;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchDirection(sal_Int32 _par0);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setFetchSize(sal_Int32 _par0);
+ protected:
+ // Static data for the class
+ static jclass theClass;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual ~java_sql_ResultSet() override;
+ public:
+ DECLARE_SERVICE_INFO();
+ virtual jclass getMyClass() const override;
+ // A ctor that is needed for returning the object
+ java_sql_ResultSet( JNIEnv * pEnv, jobject myObj, const java::sql::ConnectionLog& _rParentLogger,java_sql_Connection& _rConnection,
+ java_sql_Statement_Base* pStmt = nullptr );
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ public:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/ResultSetMetaData.hxx b/connectivity/source/inc/java/sql/ResultSetMetaData.hxx
new file mode 100644
index 000000000..e5017f115
--- /dev/null
+++ b/connectivity/source/inc/java/sql/ResultSetMetaData.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace connectivity
+{
+
+ //************ Class: java.sql.ResultSetMetaData
+
+ class java_sql_Connection;
+ class java_sql_ResultSetMetaData final : public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData>,
+ public java_lang_Object
+ {
+ java_sql_Connection* m_pConnection;
+ sal_Int32 m_nColumnCount;
+
+ // Static data for the class
+ static jclass theClass;
+ virtual ~java_sql_ResultSetMetaData() override;
+ public:
+ virtual jclass getMyClass() const override;
+
+ // A ctor that is needed for returning the object
+ java_sql_ResultSetMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rCon );
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/SQLException.hxx b/connectivity/source/inc/java/sql/SQLException.hxx
new file mode 100644
index 000000000..cff1aad46
--- /dev/null
+++ b/connectivity/source/inc/java/sql/SQLException.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Exception.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+namespace connectivity
+{
+ //************ Class: java.sql.SQLException
+
+ class java_sql_SQLException_BASE;
+ class java_sql_SQLException : public css::sdbc::SQLException
+ {
+ public:
+ // A ctor that is needed for returning the object
+ java_sql_SQLException( const java_sql_SQLException_BASE& _rException,const css::uno::Reference< css::uno::XInterface> & _rContext);
+ };
+
+ class java_sql_SQLException_BASE : public java_lang_Exception
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_SQLException_BASE() override;
+ // A ctor that is needed for returning the object
+ java_sql_SQLException_BASE( JNIEnv * pEnv, jobject myObj );
+
+ OUString getSQLState() const;
+ sal_Int32 getErrorCode() const;
+ css::sdbc::SQLException getNextException() const;
+
+ static jclass st_getMyClass();
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/SQLWarning.hxx b/connectivity/source/inc/java/sql/SQLWarning.hxx
new file mode 100644
index 000000000..5fd8c9794
--- /dev/null
+++ b/connectivity/source/inc/java/sql/SQLWarning.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/sql/SQLException.hxx>
+
+namespace connectivity
+{
+ //************ Class: java.sql.SQLWarning
+
+ class java_sql_SQLWarning_BASE : public java_sql_SQLException_BASE
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_SQLWarning_BASE() override;
+ // A ctor that is needed for returning the object
+ java_sql_SQLWarning_BASE( JNIEnv * pEnv, jobject myObj ) : java_sql_SQLException_BASE( pEnv, myObj ){}
+
+ };
+
+ class java_sql_SQLWarning : public java_sql_SQLException
+ {
+ public:
+ java_sql_SQLWarning(const java_sql_SQLWarning_BASE& _rW,const css::uno::Reference< css::uno::XInterface> & _rContext)
+ : java_sql_SQLException(_rW,_rContext) {}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/sql/Timestamp.hxx b/connectivity/source/inc/java/sql/Timestamp.hxx
new file mode 100644
index 000000000..599dfb78e
--- /dev/null
+++ b/connectivity/source/inc/java/sql/Timestamp.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/util/Date.hxx>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+
+
+namespace connectivity
+{
+
+ //************ Class: java.sql.Date
+
+
+ class java_sql_Date : public java_util_Date
+ {
+ protected:
+ // static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_Date() override;
+ // A ctor that is needed for returning the object
+ java_sql_Date( JNIEnv * pEnv, jobject myObj ) : java_util_Date(pEnv,myObj){}
+ java_sql_Date( const css::util::Date& _rOut );
+
+ operator css::util::Date();
+ static jclass st_getMyClass();
+ };
+
+
+ //************ Class: java.sql.Time
+
+
+ class java_sql_Time : public java_util_Date
+ {
+ protected:
+ // static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_Time() override;
+ // A ctor that is needed for returning the object
+ java_sql_Time( JNIEnv * pEnv, jobject myObj ) : java_util_Date( pEnv, myObj ){}
+ java_sql_Time( const css::util::Time& _rOut );
+ operator css::util::Time();
+ static jclass st_getMyClass();
+ };
+
+
+ //************ Class: java.sql.Timestamp
+
+ class java_sql_Timestamp : public java_util_Date
+ {
+ protected:
+ // static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_sql_Timestamp() override;
+ // A ctor that is needed for returning the object
+ java_sql_Timestamp( JNIEnv * pEnv, jobject myObj ) : java_util_Date( pEnv, myObj ){}
+ java_sql_Timestamp( const css::util::DateTime& _rOut);
+ operator css::util::DateTime();
+
+ static jclass st_getMyClass();
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/tools.hxx b/connectivity/source/inc/java/tools.hxx
new file mode 100644
index 000000000..44a35ecee
--- /dev/null
+++ b/connectivity/source/inc/java/tools.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/Sequence.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+
+
+namespace connectivity
+{
+
+ jstring convertwchar_tToJavaString(JNIEnv *pEnv,const OUString& Temp);
+ OUString JavaString2String(JNIEnv *pEnv,jstring Str);
+ class java_util_Properties;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ std::unique_ptr<java_util_Properties> createStringPropertyArray(const css::uno::Sequence< css::beans::PropertyValue >& info );
+
+ jobject convertTypeMapToJavaMap(const css::uno::Reference< css::container::XNameAccess > & _rMap);
+
+ /** return if an exception occurred
+ the exception will be cleared.
+ @param pEnv
+ The native java env
+ */
+ bool isExceptionOccurred(JNIEnv *pEnv);
+
+ jobject createByteInputStream(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length);
+ jobject createCharArrayReader(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/util/Date.hxx b/connectivity/source/inc/java/util/Date.hxx
new file mode 100644
index 000000000..fe5524286
--- /dev/null
+++ b/connectivity/source/inc/java/util/Date.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <java/lang/Object.hxx>
+//#include <com/sun/star/util/Date.hpp>
+
+namespace connectivity
+{
+
+
+ //************ Class: java.util.Date
+
+
+ class java_util_Date : public java_lang_Object
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_util_Date() override;
+ // A ctor that is needed for returning the object
+ java_util_Date( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/java/util/Property.hxx b/connectivity/source/inc/java/util/Property.hxx
new file mode 100644
index 000000000..628f951ba
--- /dev/null
+++ b/connectivity/source/inc/java/util/Property.hxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <java/lang/Object.hxx>
+
+namespace connectivity
+{
+ class java_util_Properties : public java_lang_Object
+ {
+ protected:
+ // Static data for the class
+ static jclass theClass;
+ public:
+ virtual jclass getMyClass() const override;
+ virtual ~java_util_Properties() override;
+ java_util_Properties( );
+ void setProperty(const OUString& key, const OUString& value);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YCatalog.hxx b/connectivity/source/inc/mysql/YCatalog.hxx
new file mode 100644
index 000000000..5eb348af9
--- /dev/null
+++ b/connectivity/source/inc/mysql/YCatalog.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sdbcx/VCatalog.hxx>
+
+namespace connectivity::mysql
+ {
+ // please don't name the class the same name as in another namespaces
+ // some compilers have problems with this task as I noticed on windows
+ class OMySQLCatalog : public connectivity::sdbcx::OCatalog
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ /** calls XDatabaseMetaData::getTables.
+ @param _sKindOfObject
+ The type of tables to be fetched.
+ @param _rNames
+ The container for the names to be filled. <OUT/>
+ */
+ void refreshObjects(const css::uno::Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames);
+
+ public:
+ // implementation of the pure virtual methods
+ virtual void refreshTables() override;
+ virtual void refreshViews() override ;
+ virtual void refreshGroups() override;
+ virtual void refreshUsers() override ;
+
+ public:
+ OMySQLCatalog(const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+
+ sdbcx::OCollection* getPrivateTables() const { return m_pTables.get();}
+ sdbcx::OCollection* getPrivateViews() const { return m_pViews.get(); }
+ const css::uno::Reference< css::sdbc::XConnection >& getConnection() const { return m_xConnection; }
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ // ::cppu::OComponentHelper
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YColumns.hxx b/connectivity/source/inc/mysql/YColumns.hxx
new file mode 100644
index 000000000..1ffcfc953
--- /dev/null
+++ b/connectivity/source/inc/mysql/YColumns.hxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity::mysql
+ {
+ class OMySQLColumns : public OColumnsHelper
+ {
+ protected:
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ public:
+ OMySQLColumns( ::cppu::OWeakObject& _rParent
+ ,::osl::Mutex& _rMutex
+ ,const ::std::vector< OUString> &_rVector
+ );
+ };
+
+ class OMySQLColumn;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper<OMySQLColumn> OMySQLColumn_PROP;
+
+ class OMySQLColumn : public sdbcx::OColumn,
+ public OMySQLColumn_PROP
+ {
+ OUString m_sAutoIncrement;
+ protected:
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ public:
+ OMySQLColumn();
+ virtual void construct() override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YDriver.hxx b/connectivity/source/inc/mysql/YDriver.hxx
new file mode 100644
index 000000000..84fad1af1
--- /dev/null
+++ b/connectivity/source/inc/mysql/YDriver.hxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+
+
+namespace connectivity
+{
+
+
+ class OMetaConnection;
+
+ namespace mysql
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver
+ , css::sdbcx::XDataDefinitionSupplier
+ , css::lang::XServiceInfo
+ > ODriverDelegator_BASE;
+
+ typedef std::pair< css::uno::WeakReferenceHelper,OMetaConnection*> TWeakConnectionPair;
+ typedef std::pair< css::uno::WeakReferenceHelper,TWeakConnectionPair> TWeakPair;
+ typedef std::vector< TWeakPair > TWeakPairVector;
+ typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > TJDBCDrivers;
+
+ /** delegates all calls to the original driver and extend the existing one with the SDBCX layer.
+
+ */
+ class ODriverDelegator : public ::cppu::BaseMutex
+ ,public ODriverDelegator_BASE
+ {
+ TJDBCDrivers m_aJdbcDrivers; // all jdbc drivers
+ TWeakPairVector m_aConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+ css::uno::Reference< css::sdbc::XDriver > m_xODBCDriver;
+ css::uno::Reference< css::sdbc::XDriver > m_xNativeDriver;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ /** load the driver we want to delegate.
+ The <member>m_xODBCDriver</member> or <member>m_xDBCDriver</member> may be <NULL/> if the driver could not be loaded.
+ @param url
+ The URL.
+ @param info
+ The property info contains which driver we have to delegate.
+ @return
+ The driver which was currently selected.
+ */
+ css::uno::Reference< css::sdbc::XDriver > loadDriver( std::u16string_view url, const css::uno::Sequence< css::beans::PropertyValue >& info );
+
+ public:
+ /** creates a new delegator for a mysql driver
+ */
+ ODriverDelegator(const css::uno::Reference< css::uno::XComponentContext >& _rxContext);
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ // XDataDefinitionSupplier
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override;
+ virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ protected:
+ /// dtor
+ virtual ~ODriverDelegator() override;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+ }
+
+
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YTable.hxx b/connectivity/source/inc/mysql/YTable.hxx
new file mode 100644
index 000000000..1cb89b4c8
--- /dev/null
+++ b/connectivity/source/inc/mysql/YTable.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <connectivity/TTableHelper.hxx>
+#include <comphelper/IdPropArrayHelper.hxx>
+
+namespace connectivity::mysql
+ {
+
+ class OMySQLTable;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper< OMySQLTable > OMySQLTable_PROP;
+ class OMySQLTable : public OTableHelper
+ ,public OMySQLTable_PROP
+ {
+ sal_Int32 m_nPrivileges; // we have to set our privileges by our own
+
+ /** executes the statement.
+ @param _rStatement
+ The statement to execute.
+ */
+ void executeStatement(const OUString& _rStatement );
+ protected:
+
+ /** creates the column collection for the table
+ @param _rNames
+ The column names.
+ */
+ virtual sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the key collection for the table
+ @param _rNames
+ The key names.
+ */
+ virtual sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the index collection for the table
+ @param _rNames
+ The index names.
+ */
+ virtual sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override;
+
+ /** Returns always "RENAME TABLE " even for views.
+ *
+ * \return The start of the rename statement.
+ * @see http://dev.mysql.com/doc/refman/5.1/de/rename-table.html
+ */
+ virtual OUString getRenameStart() const override;
+
+ /** used to implement the creation of the array helper which is shared amongst all instances of the class.
+ This method needs to be implemented in derived classes.
+ <BR>
+ The method gets called with s_aMutex acquired.
+ @return a pointer to the newly created array helper. Must not be NULL.
+ */
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ public:
+ OMySQLTable( sdbcx::OCollection* _pTables,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+ OMySQLTable( sdbcx::OCollection* _pTables,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description,
+ const OUString& SchemaName,
+ const OUString& CatalogName,
+ sal_Int32 _nPrivileges
+ );
+
+ // ODescriptor
+ virtual void construct() override;
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // XAlterTable
+ virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ /** returns the ALTER TABLE XXX statement
+ */
+ OUString getAlterTableColumnPart() const;
+
+ // some methods to alter table structures
+ void alterColumnType(sal_Int32 nNewType,const OUString& _rColName,const css::uno::Reference< css::beans::XPropertySet >& _xDescriptor);
+ void alterDefaultValue(std::u16string_view _sNewDefault,const OUString& _rColName);
+ void dropDefaultValue(const OUString& _sNewDefault);
+
+ virtual OUString getTypeCreatePattern() const override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YTables.hxx b/connectivity/source/inc/mysql/YTables.hxx
new file mode 100644
index 000000000..11d768123
--- /dev/null
+++ b/connectivity/source/inc/mysql/YTables.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <SQLStatementHelper.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+namespace connectivity::mysql
+ {
+ class OTables final : public sdbcx::OCollection,
+ public ::dbtools::ISQLStatementHelper
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void createTable( const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+ virtual OUString getNameForObject(const sdbcx::ObjectType& _xObject) override;
+ public:
+ OTables(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)
+ {}
+
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ // XDrop
+ void appendNew(const OUString& _rsNewTable);
+
+ /** convert the sql statement to fit MySQL notation
+ @param _sSql in/out
+ */
+ static OUString adjustSQL(const OUString& _sSql);
+
+ // ISQLStatementHelper
+ virtual void addComment(const css::uno::Reference< css::beans::XPropertySet >& descriptor,OUStringBuffer& _rOut) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YUser.hxx b/connectivity/source/inc/mysql/YUser.hxx
new file mode 100644
index 000000000..ecb93fa21
--- /dev/null
+++ b/connectivity/source/inc/mysql/YUser.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sdbcx/VUser.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace connectivity::mysql
+ {
+ typedef connectivity::sdbcx::OUser OUser_TYPEDEF;
+
+ class OMySQLUser : public OUser_TYPEDEF
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+
+ static OUString getPrivilegeString(sal_Int32 nRights);
+ // return the privileges and additional the grant rights
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant);
+ public:
+ virtual void refreshGroups() override;
+ public:
+ OMySQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+ OMySQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const OUString& Name);
+
+ // XUser
+ virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override;
+ // XAuthorizable
+ virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override;
+ virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override;
+ };
+
+ class OUserExtend;
+ typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;
+
+ class OUserExtend : public OMySQLUser,
+ public OUserExtend_PROP
+ {
+ OUString m_Password;
+ protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ public:
+ OUserExtend(const css::uno::Reference< css::sdbc::XConnection >& _xConnection);
+
+ virtual void construct() override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YUsers.hxx b/connectivity/source/inc/mysql/YUsers.hxx
new file mode 100644
index 000000000..d27244775
--- /dev/null
+++ b/connectivity/source/inc/mysql/YUsers.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+namespace connectivity
+{
+ namespace sdbcx
+ {
+ class IRefreshableUsers;
+ }
+ namespace mysql
+ {
+ class OUsers : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ connectivity::sdbcx::IRefreshableUsers* m_pParent;
+ public:
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual void impl_refresh() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override;
+ public:
+ OUsers( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const ::std::vector< OUString> &_rVector,
+ const css::uno::Reference< css::sdbc::XConnection >& _xConnection,
+ connectivity::sdbcx::IRefreshableUsers* _pParent);
+ };
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/mysql/YViews.hxx b/connectivity/source/inc/mysql/YViews.hxx
new file mode 100644
index 000000000..22a1f605b
--- /dev/null
+++ b/connectivity/source/inc/mysql/YViews.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+namespace connectivity::mysql
+ {
+ class OViews final : public sdbcx::OCollection
+ {
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ bool m_bInDrop;
+ virtual sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ void createView( const css::uno::Reference< css::beans::XPropertySet >& descriptor );
+ public:
+ OViews(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)
+ ,m_bInDrop(false)
+ {}
+
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ void dropByNameImpl(const OUString& elementName);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OBoundParam.hxx b/connectivity/source/inc/odbc/OBoundParam.hxx
new file mode 100644
index 000000000..77d09ba29
--- /dev/null
+++ b/connectivity/source/inc/odbc/OBoundParam.hxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <odbc/odbcbasedllapi.hxx>
+#include <connectivity/odbc.hxx>
+
+namespace connectivity::odbc
+ {
+ class OOO_DLLPUBLIC_ODBCBASE OBoundParam
+ {
+
+ public:
+ OBoundParam()
+ : binaryData(nullptr)
+ , paramLength(0)
+ , paramInputStreamLen(0)
+ {
+ }
+ ~OBoundParam()
+ {
+ free(binaryData);
+ }
+
+ // allocBindDataBuffer
+ // Allocates and returns a new bind data buffer of the specified
+ // length
+
+ void* allocBindDataBuffer (sal_Int32 bufLen)
+ {
+ // Reset the input stream and sequence, we are doing a new bind
+ setInputStream (nullptr, 0);
+ aSequence.realloc(0);
+
+ free(binaryData);
+ binaryData = (bufLen > 0) ? malloc(bufLen) : nullptr;
+
+ return binaryData;
+ }
+
+
+ // getBindLengthBuffer
+ // Returns the length buffer to be used when binding to a parameter
+
+ SQLLEN& getBindLengthBuffer ()
+ {
+ return paramLength;
+ }
+
+
+ // setInputStream
+ // Sets the input stream for the bound parameter
+
+ void setInputStream(const css::uno::Reference< css::io::XInputStream>& inputStream,
+ sal_Int32 len)
+ {
+ paramInputStream = inputStream;
+ paramInputStreamLen = len;
+ }
+
+ void setSequence(const css::uno::Sequence< sal_Int8 >& _aSequence)
+ {
+ aSequence = _aSequence;
+ }
+
+
+ // getInputStream
+ // Gets the input stream for the bound parameter
+
+ const css::uno::Reference< css::io::XInputStream>& getInputStream () const
+ {
+ return paramInputStream;
+ }
+
+
+ // getInputStreamLen
+ // Gets the input stream length for the bound parameter
+
+ sal_Int32 getInputStreamLen () const
+ {
+ return paramInputStreamLen;
+ }
+
+
+ private:
+
+ // Data attributes
+
+
+ void *binaryData; // Storage area to be used
+ // when binding the parameter
+
+ SQLLEN paramLength; // Storage area to be used
+ // for the bound length of the
+ // parameter. Note that this
+ // data is in native format.
+
+ css::uno::Reference< css::io::XInputStream> paramInputStream;
+ css::uno::Sequence< sal_Int8 > aSequence;
+ // When an input stream is
+ // bound to a parameter, a
+ // reference to the input stream is saved
+ // until not needed anymore.
+
+ sal_Int32 paramInputStreamLen; // Length of input stream
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OConnection.hxx b/connectivity/source/inc/odbc/OConnection.hxx
new file mode 100644
index 000000000..b08544b85
--- /dev/null
+++ b/connectivity/source/inc/odbc/OConnection.hxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <connectivity/odbc.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <TConnection.hxx>
+#include <OTypeInfo.hxx>
+#include <odbc/OTools.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <AutoRetrievingBase.hxx>
+#include <osl/module.h>
+#include <rtl/ref.hxx>
+
+
+#include <map>
+
+namespace connectivity::odbc
+ {
+ class ODBCDriver;
+
+ typedef connectivity::OMetaConnection OConnection_BASE;
+ typedef std::vector< ::connectivity::OTypeInfo> TTypeInfoVector;
+
+ class OOO_DLLPUBLIC_ODBCBASE OConnection final :
+ public OConnection_BASE,
+ public OAutoRetrievingBase
+ {
+ // Data attributes
+
+ std::map< SQLHANDLE, rtl::Reference<OConnection>> m_aConnections; // holds all connections which are need for several statements
+
+
+ OUString m_sUser; // the user name
+ rtl::Reference<ODBCDriver>
+ m_xDriver; // Pointer to the owning
+ // driver object
+
+ SQLHANDLE m_aConnectionHandle;
+ SQLHANDLE m_pDriverHandleCopy; // performance reason
+ sal_Int32 m_nStatementCount;
+ bool m_bClosed;
+ bool m_bUseCatalog; // should we use the catalog on filebased databases
+ bool m_bUseOldDateFormat;
+ bool m_bIgnoreDriverPrivileges;
+ bool m_bPreventGetVersionColumns; // #i60273#
+ bool m_bReadOnly;
+
+
+ SQLRETURN OpenConnection(const OUString& aConnectStr,sal_Int32 nTimeOut, bool bSilent);
+
+ public:
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const;
+ /// @throws css::sdbc::SQLException
+ SQLRETURN Construct( const OUString& url,const css::uno::Sequence< css::beans::PropertyValue >& info);
+
+ OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver);
+ // OConnection(const SQLHANDLE _pConnectionHandle);
+ virtual ~OConnection() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ SQLHANDLE getConnection() { return m_aConnectionHandle; }
+
+ // should we use the catalog on filebased databases
+ bool isCatalogUsed() const { return m_bUseCatalog; }
+ bool isIgnoreDriverPrivilegesEnabled() const { return m_bIgnoreDriverPrivileges; }
+ bool preventGetVersionColumns() const { return m_bPreventGetVersionColumns; }
+ bool useOldDateFormat() const { return m_bUseOldDateFormat; }
+ ODBCDriver* getDriver() const { return m_xDriver.get();}
+
+ SQLHANDLE createStatementHandle();
+ // close and free the handle and set it to SQL_NULLHANDLE
+ void freeStatementHandle(SQLHANDLE& _pHandle);
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/ODatabaseMetaData.hxx b/connectivity/source/inc/odbc/ODatabaseMetaData.hxx
new file mode 100644
index 000000000..b0b4a6552
--- /dev/null
+++ b/connectivity/source/inc/odbc/ODatabaseMetaData.hxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <odbc/OConnection.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <TDatabaseMetaDataBase.hxx>
+
+namespace connectivity::odbc
+ {
+
+ //************ Class: ODatabaseMetaData
+
+
+ class OOO_DLLPUBLIC_ODBCBASE ODatabaseMetaData final :
+ public ODatabaseMetaDataBase
+ {
+ SQLHANDLE m_aConnectionHandle;
+ OConnection* m_pConnection;
+ bool m_bUseCatalog;
+
+ // cached database information
+ virtual OUString impl_getIdentifierQuoteString_throw( ) override;
+ virtual bool impl_isCatalogAtStart_throw( ) override;
+ virtual OUString impl_getCatalogSeparator_throw( ) override;
+ virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override;
+ virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ;
+ virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override;
+ virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ;
+ virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override ;
+ virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override;
+ virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override;
+ virtual sal_Int32 impl_getMaxStatements_throw( ) override;
+ virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override;
+ virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override;
+ OUString getURLImpl();
+ virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override;
+ virtual ~ODatabaseMetaData() override;
+
+ public:
+ ODatabaseMetaData(const SQLHANDLE _pHandle,OConnection* _pCon);
+
+ // XDatabaseMetaData
+ virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override;
+ virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override;
+ virtual OUString SAL_CALL getURL( ) override;
+ virtual OUString SAL_CALL getUserName( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override;
+ virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override;
+ virtual OUString SAL_CALL getDatabaseProductName( ) override;
+ virtual OUString SAL_CALL getDatabaseProductVersion( ) override;
+ virtual OUString SAL_CALL getDriverName( ) override;
+ virtual OUString SAL_CALL getDriverVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFiles( ) override;
+ virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override;
+ virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override;
+
+ virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override;
+ virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override;
+
+ virtual OUString SAL_CALL getSQLKeywords( ) override;
+ virtual OUString SAL_CALL getNumericFunctions( ) override;
+ virtual OUString SAL_CALL getStringFunctions( ) override;
+ virtual OUString SAL_CALL getSystemFunctions( ) override;
+ virtual OUString SAL_CALL getTimeDateFunctions( ) override;
+ virtual OUString SAL_CALL getSearchStringEscape( ) override;
+ virtual OUString SAL_CALL getExtraNameCharacters( ) override;
+ virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override;
+ virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override;
+ virtual sal_Bool SAL_CALL supportsTypeConversion( ) override;
+ virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override;
+ virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override;
+ virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override;
+ virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupBy( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override;
+ virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override;
+ virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override;
+ virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override;
+ virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override;
+ virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override;
+ virtual sal_Bool SAL_CALL supportsOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override;
+ virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override;
+ virtual OUString SAL_CALL getSchemaTerm( ) override;
+ virtual OUString SAL_CALL getProcedureTerm( ) override;
+ virtual OUString SAL_CALL getCatalogTerm( ) override;
+
+ virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override;
+
+ virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override;
+ virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override;
+ virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override;
+ virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override;
+ virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override;
+ virtual sal_Bool SAL_CALL supportsUnion( ) override;
+ virtual sal_Bool SAL_CALL supportsUnionAll( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override;
+ virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override;
+ virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override;
+ virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override;
+ virtual sal_Int32 SAL_CALL getMaxConnections( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxRowSize( ) override;
+ virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override;
+ virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override;
+ virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override;
+ virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override;
+ virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override;
+ virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override;
+ virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override;
+ virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override;
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx b/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx
new file mode 100644
index 000000000..5d6982807
--- /dev/null
+++ b/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx
@@ -0,0 +1,259 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <odbc/OStatement.hxx>
+#include <odbc/ODatabaseMetaData.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <memory>
+#include <string_view>
+
+namespace connectivity::odbc
+ {
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE;
+
+ class OOO_DLLPUBLIC_ODBCBASE ODatabaseMetaDataResultSet :
+ public cppu::BaseMutex,
+ public ODatabaseMetaDataResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet>
+ {
+ std::vector< sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time
+
+ std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> >
+ m_aValueRange;
+
+ std::map<sal_Int32,SWORD> m_aODBCColumnTypes;
+
+ SQLHANDLE m_aStatementHandle; // ... until freed
+ css::uno::WeakReferenceHelper m_aStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData>
+ m_xMetaData;
+ std::unique_ptr<SQLUSMALLINT[]> m_pRowStatusArray;
+ rtl::Reference<OConnection> m_pConnection;
+ rtl_TextEncoding m_nTextEncoding;
+ sal_Int32 m_nRowPos;
+ sal_Int32 m_nDriverColumnCount; // column count of the driver which can sometimes be less than the metadata count
+ SQLRETURN m_nCurrentFetchState;
+ bool m_bWasNull;
+ bool m_bEOF; // after last record
+
+ // set the columncount of the driver
+ void checkColumnCount();
+ static sal_Int32 getFetchDirection() { return css::sdbc::FetchDirection::FORWARD; }
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static sal_Int32 getFetchSize();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static OUString getCursorName();
+ SWORD impl_getColumnType_nothrow(sal_Int32 columnIndex);
+
+ sal_Int32 mapColumn (sal_Int32 column);
+
+ protected:
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+ virtual ~ODatabaseMetaDataResultSet() override;
+ template < typename T, SQLSMALLINT sqlTypeId > T getInteger ( sal_Int32 columnIndex );
+
+ public:
+ // A ctor needed for returning the object
+ ODatabaseMetaDataResultSet(OConnection* _pConnection);
+
+
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+ {
+ return m_pConnection->getOdbcFunction(_nIndex);
+ }
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ css::uno::Reference< css::uno::XInterface > operator *()
+ {
+ return css::uno::Reference< css::uno::XInterface >(*static_cast<ODatabaseMetaDataResultSet_BASE*>(this));
+ }
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openTablesTypes( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openTypeInfo();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openCatalogs();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openSchemas();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openTables(const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern, const css::uno::Sequence< OUString >& types );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openColumnPrivileges( const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table, std::u16string_view columnNamePattern );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openColumns( const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern, std::u16string_view columnNamePattern );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern,std::u16string_view columnNamePattern );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openProcedures( const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view procedureNamePattern);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openVersionColumns(const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table,sal_Int32 scope, bool nullable );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openForeignKeys( const css::uno::Any& catalog, const OUString* schema,const OUString* table,
+ const css::uno::Any& catalog2, const OUString* schema2,const OUString* table2);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openExportedKeys(const css::uno::Any& catalog, const OUString& schema,const OUString& table);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openImportedKeys(const css::uno::Any& catalog, const OUString& schema,const OUString& table);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openPrimaryKeys(const css::uno::Any& catalog, const OUString& schema,std::u16string_view table);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openTablePrivileges(const css::uno::Any& catalog, const OUString& schemaPattern,
+ std::u16string_view tableNamePattern);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openSpecialColumns(bool _bRowVer,const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table,sal_Int32 scope, bool nullable );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void openIndexInfo( const css::uno::Any& catalog, const OUString& schema,
+ std::u16string_view table,bool unique,bool approximate );
+
+ protected:
+ using OPropertySetHelper::getFastPropertyValue;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/ODriver.hxx b/connectivity/source/inc/odbc/ODriver.hxx
new file mode 100644
index 000000000..0152346b2
--- /dev/null
+++ b/connectivity/source/inc/odbc/ODriver.hxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <connectivity/odbc.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <osl/module.h>
+#include <odbc/OTools.hxx>
+
+namespace connectivity::odbc
+ {
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver, css::lang::XServiceInfo > ODriver_BASE;
+
+ class OOO_DLLPUBLIC_ODBCBASE SAL_NO_VTABLE ODBCDriver : public ODriver_BASE
+ {
+ protected:
+ ::osl::Mutex m_aMutex;
+
+ connectivity::OWeakRefArray m_xConnections; // vector containing a list
+ // of all the Connection objects
+ // for this Driver
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ SQLHANDLE m_pDriverHandle;
+
+ virtual SQLHANDLE EnvironmentHandle(OUString &_rPath) = 0;
+
+ public:
+
+ ODBCDriver(const css::uno::Reference< css::uno::XComponentContext >& rxContext);
+
+ // only possibility to get the odbc functions
+ virtual oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const = 0;
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDriver
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override;
+ virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual sal_Int32 SAL_CALL getMajorVersion( ) override;
+ virtual sal_Int32 SAL_CALL getMinorVersion( ) override;
+
+ const css::uno::Reference< css::uno::XComponentContext >& getContext() const { return m_xContext; }
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OFunctions.hxx b/connectivity/source/inc/odbc/OFunctions.hxx
new file mode 100644
index 000000000..a44fe5a15
--- /dev/null
+++ b/connectivity/source/inc/odbc/OFunctions.hxx
@@ -0,0 +1,600 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <connectivity/odbc.hxx>
+#include <rtl/ustring.hxx>
+#include <osl/module.h>
+
+namespace connectivity
+{
+
+// sal_Bool LoadFunctions(oslModule pODBCso, sal_Bool _bDS=sal_True);
+bool LoadLibrary_ODBC3(OUString &_rPath);
+// sal_Bool LoadLibrary_ADABAS(OUString &_rPath);
+
+ // Connecting to a data source
+ typedef SQLRETURN (SQL_API *T3SQLAllocHandle) (SQLSMALLINT HandleType,SQLHANDLE InputHandle,SQLHANDLE * OutputHandlePtr);
+
+ #define N3SQLAllocHandle(a,b,c) (*reinterpret_cast<T3SQLAllocHandle>(getOdbcFunction(ODBC3SQLFunctionId::AllocHandle)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLConnect) (SQLHDBC ConnectionHandle,SQLCHAR *ServerName,SQLSMALLINT NameLength1,SQLCHAR *UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);
+
+ #define N3SQLConnect(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLConnect>(getOdbcFunction(ODBC3SQLFunctionId::Connect)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLDriverConnect) ( SQLHDBC ConnectionHandle,
+ HWND WindowHandle,
+ SQLCHAR * InConnectionString,
+ SQLSMALLINT StringLength1,
+ SQLCHAR * OutConnectionString,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLength2Ptr,
+ SQLUSMALLINT DriverCompletion);
+
+ #define N3SQLDriverConnect(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDriverConnect>(getOdbcFunction(ODBC3SQLFunctionId::DriverConnect)))(a,b,c,d,e,f,g,h)
+
+ typedef SQLRETURN (SQL_API *T3SQLBrowseConnect) ( SQLHDBC ConnectionHandle,
+ SQLCHAR * InConnectionString,
+ SQLSMALLINT StringLength1,
+ SQLCHAR * OutConnectionString,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLength2Ptr);
+
+ #define N3SQLBrowseConnect(a,b,c,d,e,f) (*reinterpret_cast<T3SQLBrowseConnect>(getOdbcFunction(ODBC3SQLFunctionId::BrowseConnect)))(a,b,c,d,e,f)
+
+ // Obtaining information about a driver and data source
+ typedef SQLRETURN (SQL_API *T3SQLDataSources) ( SQLHENV EnvironmentHandle,
+ SQLUSMALLINT Direction,
+ SQLCHAR * ServerName,
+ SQLSMALLINT BufferLength1,
+ SQLSMALLINT * NameLength1Ptr,
+ SQLCHAR * Description,
+ SQLSMALLINT BufferLength2,
+ SQLSMALLINT * NameLength2Ptr);
+
+ #define N3SQLDataSources(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDataSources>(getOdbcFunction(ODBC3SQLFunctionId::DataSources)))(a,b,c,d,e,f,g,h)
+
+ typedef SQLRETURN (SQL_API *T3SQLDrivers) ( SQLHENV EnvironmentHandle,
+ SQLUSMALLINT Direction,
+ SQLCHAR * DriverDescription,
+ SQLSMALLINT BufferLength1,
+ SQLSMALLINT * DescriptionLengthPtr,
+ SQLCHAR * DriverAttributes,
+ SQLSMALLINT BufferLength2,
+ SQLSMALLINT * AttributesLengthPtr);
+
+ #define N3SQLDrivers(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDrivers>(getOdbcFunction(ODBC3SQLFunctionId::Drivers)))(a,b,c,d,e,f,g,h)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetInfo) ( SQLHDBC ConnectionHandle,
+ SQLUSMALLINT InfoType,
+ SQLPOINTER InfoValuePtr,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLengthPtr);
+
+ #define N3SQLGetInfo(a,b,c,d,e) (*reinterpret_cast<T3SQLGetInfo>(getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(a,b,c,d,e)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetFunctions) (SQLHDBC ConnectionHandle,
+ SQLUSMALLINT FunctionId,
+ SQLUSMALLINT * SupportedPtr);
+
+ #define N3SQLGetFunctions(a,b,c) (*reinterpret_cast<T3SQLGetFunctions>(getOdbcFunction(ODBC3SQLFunctionId::GetFunctions)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetTypeInfo) ( SQLHSTMT StatementHandle,
+ SQLSMALLINT DataType);
+
+ #define N3SQLGetTypeInfo(a,b) (*reinterpret_cast<T3SQLGetTypeInfo>(getOdbcFunction(ODBC3SQLFunctionId::GetTypeInfo)))(a,b)
+
+ // Setting and retrieving driver attributes
+ typedef SQLRETURN (SQL_API *T3SQLSetConnectAttr)(SQLHDBC ConnectionHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER StringLength);
+
+ #define N3SQLSetConnectAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetConnectAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetConnectAttr)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetConnectAttr) (SQLHDBC ConnectionHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength,
+ SQLINTEGER* StringLength);
+
+ #define N3SQLGetConnectAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetConnectAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetConnectAttr)))(a,b,c,d,e)
+
+
+ typedef SQLRETURN (SQL_API *T3SQLSetEnvAttr) ( SQLHENV EnvironmentHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER StringLength);
+
+ #define N3SQLSetEnvAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetEnvAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetEnvAttr)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetEnvAttr) ( SQLHENV EnvironmentHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength,
+ SQLINTEGER* StringLength);
+
+ #define N3SQLGetEnvAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetEnvAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetEnvAttr)))(a,b,c,d,e)
+
+
+ typedef SQLRETURN (SQL_API *T3SQLSetStmtAttr) ( SQLHSTMT StatementHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER StringLength);
+
+ #define N3SQLSetStmtAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetStmtAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetStmtAttr)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetStmtAttr) ( SQLHSTMT StatementHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength,
+ SQLINTEGER* StringLength);
+
+ #define N3SQLGetStmtAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetStmtAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetStmtAttr)))(a,b,c,d,e)
+
+ // Setting and retrieving descriptor fields
+ /*typedef SQLRETURN (SQL_API *T3SQLSetDescField) (SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength);
+
+ #define N3SQLSetDescField(a,b,c,d,e) (*reinterpret_cast<T3SQLSetDescField>(getOdbcFunction(ODBC3SQLFunctionId::SetDescField)))(a,b,c,d,e)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetDescField) ( SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber,
+ SQLSMALLINT FieldIdentifier,
+ SQLPOINTER ValuePtr,
+ SQLINTEGER BufferLength,
+ SQLINTEGER * StringLengthPtr);
+
+ #define N3SQLGetDescField(a,b,c,d,e,f) (*reinterpret_cast<T3SQLGetDescField>(getOdbcFunction(ODBC3SQLFunctionId::GetDescField)))(a,b,c,d,e,f)
+
+
+ typedef SQLRETURN (SQL_API *T3SQLGetDescRec) ( SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber,
+ SQLCHAR * Name,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLengthPtr,
+ SQLSMALLINT * TypePtr,
+ SQLSMALLINT * SubTypePtr,
+ SQLLEN * LengthPtr,
+ SQLSMALLINT * PrecisionPtr,
+ SQLSMALLINT * ScalePtr,
+ SQLSMALLINT * NullablePtr);
+
+ #define N3SQLGetDescRec(a,b,c,d,e,f,g,h,i,j,k) (*reinterpret_cast<T3SQLGetDescRec>(getOdbcFunction(ODBC3SQLFunctionId::GetDescRec)))(a,b,c,d,e,f,g,h,i,j,k)
+
+
+ typedef SQLRETURN (SQL_API *T3SQLSetDescRec) ( SQLHDESC DescriptorHandle,
+ SQLSMALLINT RecNumber,
+ SQLSMALLINT Type,
+ SQLSMALLINT SubType,
+ SQLLEN Length,
+ SQLSMALLINT Precision,
+ SQLSMALLINT Scale,
+ SQLPOINTER DataPtr,
+ SQLLEN * StringLengthPtr,
+ SQLLEN * IndicatorPtr);
+
+ #define N3SQLSetDescRec(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLSetDescRec>(getOdbcFunction(ODBC3SQLFunctionId::SetDescRec)))(a,b,c,d,e,f,g,h,i,j)
+ */
+
+ // Preparing SQL requests
+ typedef SQLRETURN (SQL_API *T3SQLPrepare) ( SQLHSTMT StatementHandle,
+ SQLCHAR * StatementText,
+ SQLINTEGER TextLength);
+
+ #define N3SQLPrepare(a,b,c) (*reinterpret_cast<T3SQLPrepare>(getOdbcFunction(ODBC3SQLFunctionId::Prepare)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLBindParameter) (SQLHSTMT StatementHandle,
+ SQLUSMALLINT ParameterNumber,
+ SQLSMALLINT InputOutputType,
+ SQLSMALLINT ValueType,
+ SQLSMALLINT ParameterType,
+ SQLULEN ColumnSize,
+ SQLSMALLINT DecimalDigits,
+ SQLPOINTER ParameterValuePtr,
+ SQLLEN BufferLength,
+ SQLLEN * StrLen_or_IndPtr);
+
+ #define N3SQLBindParameter(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLBindParameter>(getOdbcFunction(ODBC3SQLFunctionId::BindParameter)))(a,b,c,d,e,f,g,h,i,j)
+
+ /*typedef SQLRETURN (SQL_API *T3SQLGetCursorName) (SQLHSTMT StatementHandle,
+ SQLCHAR * CursorName,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * NameLengthPtr);
+
+ #define N3SQLGetCursorName(a,b,c,d) (*reinterpret_cast<T3SQLGetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::GetCursorName)))(a,b,c,d)
+ */
+
+ typedef SQLRETURN (SQL_API *T3SQLSetCursorName) (SQLHSTMT StatementHandle,
+ SQLCHAR * CursorName,
+ SQLSMALLINT NameLength);
+
+ #define N3SQLSetCursorName(a,b,c) (*reinterpret_cast<T3SQLSetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::SetCursorName)))(a,b,c)
+
+ // Submitting requests
+ typedef SQLRETURN (SQL_API *T3SQLExecute) ( SQLHSTMT StatementHandle);
+
+ #define N3SQLExecute(a) (*reinterpret_cast<T3SQLExecute>(getOdbcFunction(ODBC3SQLFunctionId::Execute)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLExecDirect) ( SQLHSTMT StatementHandle,
+ SQLCHAR * StatementText,
+ SQLINTEGER TextLength);
+
+ #define N3SQLExecDirect(a,b,c) (*reinterpret_cast<T3SQLExecDirect>(getOdbcFunction(ODBC3SQLFunctionId::ExecDirect)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLDescribeParam) (SQLHSTMT StatementHandle,
+ SQLUSMALLINT ParameterNumber,
+ SQLSMALLINT * DataTypePtr,
+ SQLULEN * ParameterSizePtr,
+ SQLSMALLINT * DecimalDigitsPtr,
+ SQLSMALLINT * NullablePtr);
+
+ #define N3SQLDescribeParam(a,b,c,d,e,f) (*reinterpret_cast<T3SQLDescribeParam>(getOdbcFunction(ODBC3SQLFunctionId::DescribeParam)))(a,b,c,d,e,f)
+
+ typedef SQLRETURN (SQL_API *T3SQLNumParams) ( SQLHSTMT StatementHandle,
+ SQLSMALLINT * ParameterCountPtr);
+
+ #define N3SQLNumParams(a,b) (*reinterpret_cast<T3SQLNumParams>(getOdbcFunction(ODBC3SQLFunctionId::NumParams)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLParamData) ( SQLHSTMT StatementHandle,
+ SQLPOINTER * ValuePtrPtr);
+
+ #define N3SQLParamData(a,b) (*reinterpret_cast<T3SQLParamData>(getOdbcFunction(ODBC3SQLFunctionId::ParamData)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLPutData) ( SQLHSTMT StatementHandle,
+ SQLPOINTER DataPtr,
+ SQLLEN StrLen_or_Ind);
+
+ #define N3SQLPutData(a,b,c) (*reinterpret_cast<T3SQLPutData>(getOdbcFunction(ODBC3SQLFunctionId::PutData)))(a,b,c)
+
+ // Retrieving results and information about results
+ typedef SQLRETURN (SQL_API *T3SQLRowCount) ( SQLHSTMT StatementHandle,
+ SQLLEN * RowCountPtr);
+
+ #define N3SQLRowCount(a,b) (*reinterpret_cast<T3SQLRowCount>(getOdbcFunction(ODBC3SQLFunctionId::RowCount)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLNumResultCols) (SQLHSTMT StatementHandle,
+ SQLSMALLINT * ColumnCountPtr);
+
+ #define N3SQLNumResultCols(a,b) (*reinterpret_cast<T3SQLNumResultCols>(getOdbcFunction(ODBC3SQLFunctionId::NumResultCols)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLDescribeCol) ( SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * NameLengthPtr,
+ SQLSMALLINT * DataTypePtr,
+ SQLULEN * ColumnSizePtr,
+ SQLSMALLINT * DecimalDigitsPtr,
+ SQLSMALLINT * NullablePtr);
+
+ #define N3SQLDescribeCol(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLDescribeCol>(getOdbcFunction(ODBC3SQLFunctionId::DescribeCol)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLColAttribute) (SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLUSMALLINT FieldIdentifier,
+ SQLPOINTER CharacterAttributePtr,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLengthPtr,
+ SQLLEN * NumericAttributePtr);
+
+ #define N3SQLColAttribute(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLColAttribute>(getOdbcFunction(ODBC3SQLFunctionId::ColAttribute)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLBindCol) ( SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLSMALLINT TargetType,
+ SQLPOINTER TargetValuePtr,
+ SQLLEN BufferLength,
+ SQLLEN * StrLen_or_IndPtr);
+
+ #define N3SQLBindCol(a,b,c,d,e,f) (*reinterpret_cast<T3SQLBindCol>(getOdbcFunction(ODBC3SQLFunctionId::BindCol)))(a,b,c,d,e,f)
+
+ typedef SQLRETURN (SQL_API *T3SQLFetch) ( SQLHSTMT StatementHandle);
+
+ #define N3SQLFetch(a) (*reinterpret_cast<T3SQLFetch>(getOdbcFunction(ODBC3SQLFunctionId::Fetch)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLFetchScroll) ( SQLHSTMT StatementHandle,
+ SQLSMALLINT FetchOrientation,
+ SQLLEN FetchOffset);
+
+ #define N3SQLFetchScroll(a,b,c) (*reinterpret_cast<T3SQLFetchScroll>(getOdbcFunction(ODBC3SQLFunctionId::FetchScroll)))(a,b,c)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetData) ( SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLSMALLINT TargetType,
+ SQLPOINTER TargetValuePtr,
+ SQLLEN BufferLength,
+ SQLLEN * StrLen_or_IndPtr);
+
+ #define N3SQLGetData(a,b,c,d,e,f) (*reinterpret_cast<T3SQLGetData>(getOdbcFunction(ODBC3SQLFunctionId::GetData)))(a,b,c,d,e,f)
+
+ typedef SQLRETURN (SQL_API *T3SQLSetPos) ( SQLHSTMT StatementHandle,
+ SQLSETPOSIROW RowNumber,
+ SQLUSMALLINT Operation,
+ SQLUSMALLINT LockType);
+
+ #define N3SQLSetPos(a,b,c,d) (*reinterpret_cast<T3SQLSetPos>(getOdbcFunction(ODBC3SQLFunctionId::SetPos)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLBulkOperations) ( SQLHSTMT StatementHandle,
+ SQLSMALLINT Operation);
+
+ #define N3SQLBulkOperations(a,b) (*reinterpret_cast<T3SQLBulkOperations>(getOdbcFunction(ODBC3SQLFunctionId::BulkOperations)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLMoreResults) ( SQLHSTMT StatementHandle);
+
+ #define N3SQLMoreResults(a) (*reinterpret_cast<T3SQLMoreResults>(getOdbcFunction(ODBC3SQLFunctionId::MoreResults)))(a)
+
+ /*typedef SQLRETURN (SQL_API *T3SQLGetDiagField) (SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT RecNumber,
+ SQLSMALLINT DiagIdentifier,
+ SQLPOINTER DiagInfoPtr,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * StringLengthPtr);
+
+ #define N3SQLGetDiagField(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLGetDiagField>(getOdbcFunction(ODBC3SQLFunctionId::GetDiagField)))(a,b,c,d,e,f,g)*/
+
+ typedef SQLRETURN (SQL_API *T3SQLGetDiagRec) ( SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT RecNumber,
+ SQLCHAR * Sqlstate,
+ SQLINTEGER * NativeErrorPtr,
+ SQLCHAR * MessageText,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * TextLengthPtr);
+
+
+ #define N3SQLGetDiagRec(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLGetDiagRec>(getOdbcFunction(ODBC3SQLFunctionId::GetDiagRec)))(a,b,c,d,e,f,g,h)
+
+ // Obtaining information about the data source's system tables (catalog functions)
+ typedef SQLRETURN (SQL_API *T3SQLColumnPrivileges) (SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT NameLength4);
+
+ #define N3SQLColumnPrivileges(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLColumnPrivileges>(getOdbcFunction(ODBC3SQLFunctionId::ColumnPrivileges)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLColumns) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT NameLength4);
+
+ #define N3SQLColumns(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLColumns>(getOdbcFunction(ODBC3SQLFunctionId::Columns)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLForeignKeys) ( SQLHSTMT StatementHandle,
+ SQLCHAR * PKCatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * PKSchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * PKTableName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * FKCatalogName,
+ SQLSMALLINT NameLength4,
+ SQLCHAR * FKSchemaName,
+ SQLSMALLINT NameLength5,
+ SQLCHAR * FKTableName,
+ SQLSMALLINT NameLength6);
+
+ #define N3SQLForeignKeys(a,b,c,d,e,f,g,h,i,j,k,l,m) (*reinterpret_cast<T3SQLForeignKeys>(getOdbcFunction(ODBC3SQLFunctionId::ForeignKeys)))(a,b,c,d,e,f,g,h,i,j,k,l,m)
+
+ typedef SQLRETURN (SQL_API *T3SQLPrimaryKeys) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3);
+
+ #define N3SQLPrimaryKeys(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLPrimaryKeys>(getOdbcFunction(ODBC3SQLFunctionId::PrimaryKeys)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLProcedureColumns) (SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * ProcName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT NameLength4);
+
+ #define N3SQLProcedureColumns(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLProcedureColumns>(getOdbcFunction(ODBC3SQLFunctionId::ProcedureColumns)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLProcedures) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * ProcName,
+ SQLSMALLINT NameLength3);
+
+ #define N3SQLProcedures(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLProcedures>(getOdbcFunction(ODBC3SQLFunctionId::Procedures)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLSpecialColumns) (SQLHSTMT StatementHandle,
+ SQLUSMALLINT IdentifierType,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLUSMALLINT Scope,
+ SQLUSMALLINT Nullable);
+
+ #define N3SQLSpecialColumns(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLSpecialColumns>(getOdbcFunction(ODBC3SQLFunctionId::SpecialColumns)))(a,b,c,d,e,f,g,h,i,j)
+
+ typedef SQLRETURN (SQL_API *T3SQLStatistics) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLUSMALLINT Unique,
+ SQLUSMALLINT Reserved);
+
+ #define N3SQLStatistics(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLStatistics>(getOdbcFunction(ODBC3SQLFunctionId::Statistics)))(a,b,c,d,e,f,g,h,i)
+
+ typedef SQLRETURN (SQL_API *T3SQLTablePrivileges) (SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3);
+
+ #define N3SQLTablePrivileges(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLTablePrivileges>(getOdbcFunction(ODBC3SQLFunctionId::TablePrivileges)))(a,b,c,d,e,f,g)
+
+ typedef SQLRETURN (SQL_API *T3SQLTables) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CatalogName,
+ SQLSMALLINT NameLength1,
+ SQLCHAR * SchemaName,
+ SQLSMALLINT NameLength2,
+ SQLCHAR * TableName,
+ SQLSMALLINT NameLength3,
+ SQLCHAR * TableType,
+ SQLSMALLINT NameLength4);
+
+ #define N3SQLTables(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLTables>(getOdbcFunction(ODBC3SQLFunctionId::Tables)))(a,b,c,d,e,f,g,h,i)
+
+ // Terminating a statement
+ typedef SQLRETURN (SQL_API *T3SQLFreeStmt) ( SQLHSTMT StatementHandle,
+ SQLUSMALLINT Option);
+
+ #define N3SQLFreeStmt(a,b) (*reinterpret_cast<T3SQLFreeStmt>(getOdbcFunction(ODBC3SQLFunctionId::FreeStmt)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLCloseCursor) (SQLHSTMT StatementHandle);
+
+ #define N3SQLCloseCursor(a) (*reinterpret_cast<T3SQLCloseCursor>(getOdbcFunction(ODBC3SQLFunctionId::CloseCursor)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLCancel) ( SQLHSTMT StatementHandle);
+
+ #define N3SQLCancel(a) (*reinterpret_cast<T3SQLCancel>(getOdbcFunction(ODBC3SQLFunctionId::Cancel)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLEndTran) ( SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT CompletionType);
+
+ #define N3SQLEndTran(a,b,c) (*reinterpret_cast<T3SQLEndTran>(getOdbcFunction(ODBC3SQLFunctionId::EndTran)))(a,b,c)
+
+ // Terminating a connection
+ typedef SQLRETURN (SQL_API *T3SQLDisconnect) (SQLHDBC ConnectionHandle);
+
+ #define N3SQLDisconnect(a) (*reinterpret_cast<T3SQLDisconnect>(getOdbcFunction(ODBC3SQLFunctionId::Disconnect)))(a)
+
+ typedef SQLRETURN (SQL_API *T3SQLFreeHandle) (SQLSMALLINT HandleType,
+ SQLHANDLE Handle);
+
+ #define N3SQLFreeHandle(a,b) (*reinterpret_cast<T3SQLFreeHandle>(getOdbcFunction(ODBC3SQLFunctionId::FreeHandle)))(a,b)
+
+ typedef SQLRETURN (SQL_API *T3SQLGetCursorName) ( SQLHSTMT StatementHandle,
+ SQLCHAR * CursorName,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT* NameLength2);
+
+ #define N3SQLGetCursorName(a,b,c,d) (*reinterpret_cast<T3SQLGetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::GetCursorName)))(a,b,c,d)
+
+ typedef SQLRETURN (SQL_API *T3SQLNativeSql) ( SQLHDBC ConnectionHandle,
+ SQLCHAR * InStatementText,
+ SQLINTEGER TextLength1,
+ SQLCHAR * OutStatementText,
+ SQLINTEGER BufferLength,
+ SQLINTEGER * TextLength2Ptr);
+
+ #define N3SQLNativeSql(a,b,c,d,e,f) (*reinterpret_cast<T3SQLNativeSql>(getOdbcFunction(ODBC3SQLFunctionId::NativeSql)))(a,b,c,d,e,f)
+
+ // extern declaration of the function pointer
+ extern T3SQLAllocHandle pODBC3SQLAllocHandle;
+ extern T3SQLConnect pODBC3SQLConnect;
+ extern T3SQLDriverConnect pODBC3SQLDriverConnect;
+ extern T3SQLBrowseConnect pODBC3SQLBrowseConnect;
+ extern T3SQLDataSources pODBC3SQLDataSources;
+ extern T3SQLDrivers pODBC3SQLDrivers;
+ extern T3SQLGetInfo pODBC3SQLGetInfo;
+ extern T3SQLGetFunctions pODBC3SQLGetFunctions;
+ extern T3SQLGetTypeInfo pODBC3SQLGetTypeInfo;
+ extern T3SQLSetConnectAttr pODBC3SQLSetConnectAttr;
+ extern T3SQLGetConnectAttr pODBC3SQLGetConnectAttr;
+ extern T3SQLSetEnvAttr pODBC3SQLSetEnvAttr;
+ extern T3SQLGetEnvAttr pODBC3SQLGetEnvAttr;
+ extern T3SQLSetStmtAttr pODBC3SQLSetStmtAttr;
+ extern T3SQLGetStmtAttr pODBC3SQLGetStmtAttr;
+ //extern T3SQLSetDescField pODBC3SQLSetDescField;
+ //extern T3SQLGetDescField pODBC3SQLGetDescField;
+ //extern T3SQLGetDescRec pODBC3SQLGetDescRec;
+ //extern T3SQLSetDescRec pODBC3SQLSetDescRec;
+ extern T3SQLPrepare pODBC3SQLPrepare;
+ extern T3SQLBindParameter pODBC3SQLBindParameter;
+ //extern T3SQLGetCursorName pODBC3SQLGetCursorName;
+ extern T3SQLSetCursorName pODBC3SQLSetCursorName;
+ extern T3SQLExecute pODBC3SQLExecute;
+ extern T3SQLExecDirect pODBC3SQLExecDirect;
+ //extern T3SQLNativeSql pODBC3SQLNativeSql;
+ extern T3SQLDescribeParam pODBC3SQLDescribeParam;
+ extern T3SQLNumParams pODBC3SQLNumParams;
+ extern T3SQLParamData pODBC3SQLParamData;
+ extern T3SQLPutData pODBC3SQLPutData;
+ extern T3SQLRowCount pODBC3SQLRowCount;
+ extern T3SQLNumResultCols pODBC3SQLNumResultCols;
+ extern T3SQLDescribeCol pODBC3SQLDescribeCol;
+ extern T3SQLColAttribute pODBC3SQLColAttribute;
+ extern T3SQLBindCol pODBC3SQLBindCol;
+ extern T3SQLFetch pODBC3SQLFetch;
+ extern T3SQLFetchScroll pODBC3SQLFetchScroll;
+ extern T3SQLGetData pODBC3SQLGetData;
+ extern T3SQLSetPos pODBC3SQLSetPos;
+ extern T3SQLBulkOperations pODBC3SQLBulkOperations;
+ extern T3SQLMoreResults pODBC3SQLMoreResults;
+ //extern T3SQLGetDiagField pODBC3SQLGetDiagField;
+ extern T3SQLGetDiagRec pODBC3SQLGetDiagRec;
+ extern T3SQLColumnPrivileges pODBC3SQLColumnPrivileges;
+ extern T3SQLColumns pODBC3SQLColumns;
+ extern T3SQLForeignKeys pODBC3SQLForeignKeys;
+ extern T3SQLPrimaryKeys pODBC3SQLPrimaryKeys;
+ extern T3SQLProcedureColumns pODBC3SQLProcedureColumns;
+ extern T3SQLProcedures pODBC3SQLProcedures;
+ extern T3SQLSpecialColumns pODBC3SQLSpecialColumns;
+ extern T3SQLStatistics pODBC3SQLStatistics;
+ extern T3SQLTablePrivileges pODBC3SQLTablePrivileges;
+ extern T3SQLTables pODBC3SQLTables;
+ extern T3SQLFreeStmt pODBC3SQLFreeStmt;
+ extern T3SQLCloseCursor pODBC3SQLCloseCursor;
+ extern T3SQLCancel pODBC3SQLCancel;
+ extern T3SQLEndTran pODBC3SQLEndTran;
+ extern T3SQLDisconnect pODBC3SQLDisconnect;
+ extern T3SQLFreeHandle pODBC3SQLFreeHandle;
+ extern T3SQLGetCursorName pODBC3SQLGetCursorName;
+ extern T3SQLNativeSql pODBC3SQLNativeSql;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OPreparedStatement.hxx b/connectivity/source/inc/odbc/OPreparedStatement.hxx
new file mode 100644
index 000000000..37e29db9c
--- /dev/null
+++ b/connectivity/source/inc/odbc/OPreparedStatement.hxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <odbc/odbcbasedllapi.hxx>
+#include <odbc/OStatement.hxx>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <cppuhelper/implbase5.hxx>
+
+namespace connectivity::odbc
+ {
+
+ class OBoundParam;
+ typedef ::cppu::ImplHelper5< css::sdbc::XPreparedStatement,
+ css::sdbc::XParameters,
+ css::sdbc::XPreparedBatchExecution,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::lang::XServiceInfo> OPreparedStatement_BASE;
+
+ class OOO_DLLPUBLIC_ODBCBASE OPreparedStatement final :
+ public OStatement_BASE2,
+ public OPreparedStatement_BASE
+ {
+ static const short invalid_scale = -1;
+
+ // Data attributes
+
+ SQLSMALLINT numParams; // Number of parameter markers for the prepared statement
+
+ std::unique_ptr<OBoundParam[]> boundParams;
+ // Array of bound parameter objects. Each parameter marker will have a
+ // corresponding object to hold bind information, and resulting data.
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData;
+ bool m_bPrepared;
+
+ void FreeParams();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void putParamData (sal_Int32 index);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setStream (sal_Int32 ParameterIndex,const css::uno::Reference< css::io::XInputStream>& x,
+ SQLLEN length,sal_Int32 SQLtype);
+ SQLLEN* getLengthBuf (sal_Int32 index);
+ void* allocBindBuf ( sal_Int32 index, sal_Int32 bufLen);
+ /// @throws css::sdbc::SQLException
+ void initBoundParam ();
+ void setParameterPre(sal_Int32 parameterIndex);
+ template <typename T> void setScalarParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, const T i_Value);
+ template <typename T> void setScalarParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, sal_Int32 _nScale, const T i_Value);
+ void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, sal_Int32 _nScale, const void* _pData, SQLULEN _nDataLen, SQLLEN _nDataAllocLen);
+ // Wrappers for special cases
+ void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, sal_Int16 _nScale, const OUString &_sData);
+ void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, const css::uno::Sequence< sal_Int8 > &Data);
+
+ bool isPrepared() const { return m_bPrepared;}
+ void prepareStatement();
+ void checkParameterIndex(sal_Int32 _parameterIndex);
+
+ /**
+ creates the driver specific resultset (factory)
+ */
+ virtual rtl::Reference<OResultSet> createResultSet() override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // A ctor, needed to return the object
+ OPreparedStatement( OConnection* _pConnection,const OUString& sql);
+ virtual ~OPreparedStatement() override;
+ OPreparedStatement& operator=( OPreparedStatement const & ) = delete; // MSVC2015 workaround
+ OPreparedStatement( OPreparedStatement const & ) = delete; // MSVC2015 workaround
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ // XPreparedBatchExecution
+ virtual void SAL_CALL addBatch( ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ public:
+ using OStatement_Base::executeQuery;
+ using OStatement_Base::executeUpdate;
+ using OStatement_Base::execute;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OResultSet.hxx b/connectivity/source/inc/odbc/OResultSet.hxx
new file mode 100644
index 000000000..6de7adc28
--- /dev/null
+++ b/connectivity/source/inc/odbc/OResultSet.hxx
@@ -0,0 +1,354 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <odbc/OFunctions.hxx>
+#include <odbc/OStatement.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <TSkipDeletedSet.hxx>
+#include <memory>
+
+namespace connectivity::odbc
+ {
+
+ /*
+ ** java_sql_ResultSet
+ */
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::util::XCancellable,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XDeleteRows,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::lang::XServiceInfo> OResultSet_BASE;
+
+
+ typedef std::pair<sal_Int64,sal_Int32> TVoidPtr;
+ typedef std::allocator< TVoidPtr > TVoidAlloc;
+ typedef std::vector<TVoidPtr> TVoidVector;
+ /// Functor object for class ZZ returntype is void
+ struct OOO_DLLPUBLIC_ODBCBASE TBookmarkPosMapCompare
+ {
+ bool operator()( const css::uno::Sequence<sal_Int8>& _rLH,
+ const css::uno::Sequence<sal_Int8>& _rRH) const
+ {
+ if(_rLH.getLength() == _rRH.getLength())
+ {
+ sal_Int32 nCount = _rLH.getLength();
+ if(nCount != 4)
+ {
+ const sal_Int8* pLHBack = _rLH.getConstArray() + nCount - 1;
+ const sal_Int8* pRHBack = _rRH.getConstArray() + nCount - 1;
+
+ sal_Int32 i;
+ for(i=0;i < nCount;++i,--pLHBack,--pRHBack)
+ {
+ if(!(*pLHBack) && *pRHBack)
+ return true;
+ else if(*pLHBack && !(*pRHBack))
+ return false;
+ }
+ for(i=0,++pLHBack,++pRHBack;i < nCount;++pLHBack,++pRHBack,++i)
+ if(*pLHBack < *pRHBack)
+ return true;
+ return false;
+ }
+ else
+ return *reinterpret_cast<const sal_Int32*>(_rLH.getConstArray()) < *reinterpret_cast<const sal_Int32*>(_rRH.getConstArray());
+
+ }
+ else
+ return _rLH.getLength() < _rRH.getLength();
+ }
+ };
+
+ typedef std::map< css::uno::Sequence<sal_Int8>, sal_Int32,TBookmarkPosMapCompare > TBookmarkPosMap;
+
+ class OOO_DLLPUBLIC_ODBCBASE OResultSet :
+ public cppu::BaseMutex,
+ public ::connectivity::IResultSetHelper,
+ public OResultSet_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OResultSet>
+ {
+ protected:
+ TBookmarkPosMap m_aPosToBookmarks;
+ // used top hold the information about the value and the datatype to save calls to metadata
+ typedef std::vector<ORowSetValue> TDataRow;
+
+ TVoidVector m_aBindVector;
+ std::vector<SQLLEN> m_aLengthVector;
+ std::map<sal_Int32,SWORD> m_aODBCColumnTypes;
+
+ // In baseline ODBC, SQLGetData can only be called on monotonically increasing column numbers.
+ // additionally, any variable-length data can be fetched only once (possibly in parts);
+ // after that, SQLGetData returns SQL_NO_DATA.
+ // In order to insulate our callers from these restrictions,
+ // we cache the current row in m_aRow.
+ // If the driver claims to support the GD_ANY_ORDER extension,
+ // we read and cache only the columns requested by a caller.
+ // Else, we read and cache all columns whose number is <= a requested column.
+ // m_aRow[colNumber].getBound() says if it contains an up-to-date value or not.
+ TDataRow m_aRow;
+ bool m_bFetchDataInOrder;
+ SQLHANDLE m_aStatementHandle;
+ SQLHANDLE m_aConnectionHandle;
+ OStatement_Base* m_pStatement;
+ std::unique_ptr<OSkipDeletedSet> m_pSkipDeletedSet;
+ css::uno::Reference< css::uno::XInterface> m_xStatement;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData;
+ std::unique_ptr<SQLUSMALLINT[]> m_pRowStatusArray;
+ rtl_TextEncoding m_nTextEncoding;
+ sal_Int32 m_nRowPos;
+ mutable sal_uInt32 m_nUseBookmarks;
+ SQLRETURN m_nCurrentFetchState;
+ bool m_bWasNull;
+ bool m_bEOF; // after last record
+ bool m_bRowInserted;
+ bool m_bRowDeleted;
+ bool m_bUseFetchScroll;
+
+ bool isBookmarkable() const;
+ sal_Int32 getResultSetConcurrency() const;
+ sal_Int32 getResultSetType() const;
+ static sal_Int32 getFetchDirection() { return css::sdbc::FetchDirection::FORWARD; }
+ sal_Int32 getFetchSize() const;
+ OUString getCursorName() const;
+ template < typename T, SQLINTEGER BufferLength > T getStmtOption (SQLINTEGER fOption) const;
+
+ void setFetchDirection(sal_Int32 _par0);
+ void setFetchSize(sal_Int32 _par0);
+ template < typename T, SQLINTEGER BufferLength > SQLRETURN setStmtOption (SQLINTEGER fOption, T value) const;
+
+
+ void ensureCacheForColumn(sal_Int32 columnIndex);
+ void invalidateCache();
+ void fillColumn(sal_Int32 _nToColumn);
+ void allocBuffer();
+ void releaseBuffer();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void updateValue(sal_Int32 columnIndex, SQLSMALLINT _nType, void const * _pValue);
+ void fillNeededData(SQLRETURN _nRet);
+ bool moveImpl(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset);
+ TVoidPtr allocBindColumn(sal_Int32 _nType,sal_Int32 _nColumnIndex);
+ SQLRETURN unbind(bool _bUnbindHandle = true);
+ SWORD impl_getColumnType_nothrow(sal_Int32 columnIndex);
+
+ // helper to implement XRow::getXXX in simple cases
+ template < typename T > T getValue( sal_Int32 columnIndex );
+ // impl_getXXX are the functions that do the actual fetching from ODBC, ignoring the cache
+ // for simple cases
+ template < typename T > T impl_getValue( const sal_Int32 _nColumnIndex, SQLSMALLINT nType );
+ // these cases need some special treatment
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool impl_getBoolean( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence< sal_Int8 > impl_getBytes( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::util::Date impl_getDate( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::util::Time impl_getTime( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::util::DateTime impl_getTimestamp( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int64 impl_getLong( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString impl_getString( sal_Int32 columnIndex );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence<sal_Int8> impl_getBookmark( );
+
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ public:
+ DECLARE_SERVICE_INFO();
+ // A ctor that is needed for returning the object
+ OResultSet( SQLHANDLE _pStatementHandle,OStatement_Base* pStmt);
+ virtual ~OResultSet() override;
+
+ void construct();
+
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+ {
+ return m_pStatement->getOdbcFunction(_nIndex);
+ }
+
+ css::uno::Reference< css::uno::XInterface > operator *()
+ {
+ return css::uno::Reference< css::uno::XInterface >(*static_cast<OResultSet_BASE*>(this));
+ }
+
+ void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;}
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+ // XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+ // XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+ // XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+ // XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+ // XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ // IResultSetHelper
+ virtual bool move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) override;
+ virtual sal_Int32 getDriverPos() const override;
+ virtual bool isRowDeleted() const override;
+
+ protected:
+ using OPropertySetHelper::getFastPropertyValue;
+ };
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OResultSetMetaData.hxx b/connectivity/source/inc/odbc/OResultSetMetaData.hxx
new file mode 100644
index 000000000..ea32a453e
--- /dev/null
+++ b/connectivity/source/inc/odbc/OResultSetMetaData.hxx
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <odbc/OFunctions.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <vector>
+#include <odbc/OConnection.hxx>
+
+namespace connectivity::odbc
+ {
+
+ //************ Class: ResultSetMetaData
+
+ typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
+
+ class OOO_DLLPUBLIC_ODBCBASE OResultSetMetaData final :
+ public OResultSetMetaData_BASE
+ {
+ std::vector<sal_Int32> m_vMapping; // when not every column is needed
+ std::map<sal_Int32,sal_Int32> m_aColumnTypes;
+
+ SQLHANDLE m_aStatementHandle;
+ OConnection* m_pConnection;
+ sal_Int32 m_nColCount;
+ bool m_bUseODBC2Types;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ OUString getCharColAttrib(sal_Int32 column,sal_Int32 ident);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getNumColAttrib(sal_Int32 column,sal_Int32 ident);
+ public:
+ // A ctor that is needed for returning the object
+ OResultSetMetaData(OConnection* _pConnection, SQLHANDLE _pStmt )
+ :m_aStatementHandle( _pStmt )
+ ,m_pConnection(_pConnection)
+ ,m_nColCount(-1)
+ ,m_bUseODBC2Types(false)
+ {}
+ OResultSetMetaData(OConnection* _pConnection, SQLHANDLE _pStmt, std::vector<sal_Int32>&& _vMapping)
+ :m_vMapping(std::move(_vMapping))
+ ,m_aStatementHandle( _pStmt )
+ ,m_pConnection(_pConnection)
+ ,m_nColCount(m_vMapping.size()-1)
+ ,m_bUseODBC2Types(false)
+ {}
+ virtual ~OResultSetMetaData() override;
+
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static SQLLEN getNumColAttrib(OConnection const * _pConnection
+ ,SQLHANDLE _aStatementHandle
+ ,const css::uno::Reference< css::uno::XInterface >& _xInterface
+ ,sal_Int32 _column
+ ,sal_Int32 ident);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static SQLSMALLINT getColumnODBCType(OConnection const * _pConnection
+ ,SQLHANDLE _aStatementHandle
+ ,const css::uno::Reference< css::uno::XInterface >& _xInterface
+ ,sal_Int32 column);
+
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+ {
+ return m_pConnection->getOdbcFunction(_nIndex);
+ }
+
+ virtual sal_Int32 SAL_CALL getColumnCount( ) override;
+ virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getTableName( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override;
+ virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override;
+ virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OStatement.hxx b/connectivity/source/inc/odbc/OStatement.hxx
new file mode 100644
index 000000000..1e4831087
--- /dev/null
+++ b/connectivity/source/inc/odbc/OStatement.hxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/SQLWarning.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <odbc/OFunctions.hxx>
+#include <odbc/OConnection.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <string_view>
+#include <vector>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace connectivity::odbc
+ {
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement,
+ css::sdbc::XWarningsSupplier,
+ css::util::XCancellable,
+ css::sdbc::XCloseable,
+ css::sdbc::XGeneratedResultSet,
+ css::sdbc::XMultipleResults> OStatement_BASE;
+
+ class OResultSet;
+
+ //************ Class: java.sql.Statement
+
+ class OOO_DLLPUBLIC_ODBCBASE OStatement_Base :
+ public cppu::BaseMutex,
+ public OStatement_BASE,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base>
+
+ {
+ css::sdbc::SQLWarning m_aLastWarning;
+ protected:
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created
+ css::uno::Reference< css::sdbc::XStatement> m_xGeneratedStatement;
+ // for this Statement
+
+ std::vector< OUString> m_aBatchVector;
+ OUString m_sSqlStatement;
+
+ rtl::Reference<OConnection> m_pConnection;// The owning Connection object
+ SQLHANDLE m_aStatementHandle;
+ SQLUSMALLINT* m_pRowStatusArray;
+
+ protected:
+
+ sal_Int64 getQueryTimeOut() const;
+ sal_Int64 getMaxFieldSize() const;
+ sal_Int64 getMaxRows() const;
+ sal_Int32 getResultSetConcurrency() const;
+ sal_Int32 getResultSetType() const;
+ sal_Int32 getFetchDirection() const;
+ sal_Int32 getFetchSize() const;
+ OUString getCursorName() const;
+ bool isUsingBookmarks() const;
+ bool getEscapeProcessing() const;
+ template < typename T, SQLINTEGER BufferLength > T getStmtOption (SQLINTEGER fOption) const;
+
+ void setQueryTimeOut(sal_Int64 _par0) ;
+ void setMaxFieldSize(sal_Int64 _par0) ;
+ void setMaxRows(sal_Int64 _par0) ;
+ void setFetchDirection(sal_Int32 _par0) ;
+ void setFetchSize(sal_Int32 _par0) ;
+ void setCursorName(std::u16string_view _par0);
+ void setEscapeProcessing( const bool _bEscapeProc );
+ template < typename T, SQLINTEGER BufferLength > SQLRETURN setStmtOption (SQLINTEGER fOption, T value) const;
+
+ void setResultSetConcurrency(sal_Int32 _par0) ;
+ void setResultSetType(sal_Int32 _par0) ;
+ void setUsingBookmarks(bool _bUseBookmark) ;
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void reset();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void clearMyResultSet();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void setWarning (const css::sdbc::SQLWarning &ex);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool lockIfNecessary (const OUString& sql);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getColumnCount();
+
+
+ // getResultSet
+ // getResultSet returns the current result as a ResultSet. It
+ // returns NULL if the current result is not a ResultSet.
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference<css::sdbc::XResultSet> getResultSet(bool checkCount);
+ /**
+ creates the driver specific resultset (factory)
+ */
+ virtual rtl::Reference<OResultSet> createResultSet();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ SQLLEN getRowCount();
+
+
+ void disposeResultSet();
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual ~OStatement_Base() override;
+
+ public:
+ OStatement_Base(OConnection* _pConnection );
+ using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >;
+
+ oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const
+ {
+ return m_pConnection->getOdbcFunction(_nIndex);
+ }
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ // XInterface
+ virtual void SAL_CALL release() noexcept override;
+ virtual void SAL_CALL acquire() noexcept override;
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ;
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+ // XCancellable
+ virtual void SAL_CALL cancel( ) override;
+ // XCloseable
+ virtual void SAL_CALL close( ) override;
+ // XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+ //XGeneratedResultSet
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues( ) override;
+
+ // other methods
+ SQLHANDLE getConnectionHandle() { return m_pConnection->getConnection(); }
+ OConnection* getOwnConnection() const { return m_pConnection.get();}
+ /** getCursorProperties return the properties for a specific cursor type
+ @param _nCursorType the CursorType
+ @param bFirst when true the first property set is returned
+
+ @return the cursor properties
+ */
+ SQLUINTEGER getCursorProperties(SQLINTEGER _nCursorType, bool bFirst);
+
+ protected:
+ using OPropertySetHelper::getFastPropertyValue;
+ };
+
+ class OOO_DLLPUBLIC_ODBCBASE OStatement_BASE2 : public OStatement_Base
+ {
+ public:
+ OStatement_BASE2(OConnection* _pConnection ) :
+ OStatement_Base(_pConnection )
+ {}
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ };
+
+ class OOO_DLLPUBLIC_ODBCBASE OStatement :
+ public OStatement_BASE2,
+ public css::sdbc::XBatchExecution,
+ public css::lang::XServiceInfo
+ {
+ protected:
+ virtual ~OStatement() override {}
+ public:
+ // A ctor that is needed for returning the object
+ OStatement( OConnection* _pConnection) : OStatement_BASE2( _pConnection){}
+ DECLARE_SERVICE_INFO();
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ // XBatchExecution
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/OTools.hxx b/connectivity/source/inc/odbc/OTools.hxx
new file mode 100644
index 000000000..b03db91dc
--- /dev/null
+++ b/connectivity/source/inc/odbc/OTools.hxx
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <connectivity/odbc.hxx>
+#include <odbc/odbcbasedllapi.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <osl/thread.h>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <rtl/textenc.h>
+
+enum class ODBC3SQLFunctionId
+{
+ AllocHandle = 1,
+ Connect = 2,
+ DriverConnect = 3,
+ BrowseConnect = 4,
+ DataSources = 5,
+ Drivers = 6,
+ GetInfo = 7,
+ GetFunctions = 8,
+ GetTypeInfo = 9,
+ SetConnectAttr = 10,
+ GetConnectAttr = 11,
+ SetEnvAttr = 12,
+ GetEnvAttr = 13,
+ SetStmtAttr = 14,
+ GetStmtAttr = 15,
+ Prepare = 16,
+ BindParameter = 17,
+ SetCursorName = 18,
+ Execute = 19,
+ ExecDirect = 20,
+ DescribeParam = 21,
+ NumParams = 22,
+ ParamData = 23,
+ PutData = 24,
+ RowCount = 25,
+ NumResultCols = 26,
+ DescribeCol = 27,
+ ColAttribute = 28,
+ BindCol = 29,
+ Fetch = 30,
+ FetchScroll = 31,
+ GetData = 32,
+ SetPos = 33,
+ BulkOperations = 34,
+ MoreResults = 35,
+ GetDiagRec = 36,
+ ColumnPrivileges = 37,
+ Columns = 38,
+ ForeignKeys = 39,
+ PrimaryKeys = 40,
+ ProcedureColumns = 41,
+ Procedures = 42,
+ SpecialColumns = 43,
+ Statistics = 44,
+ TablePrivileges = 45,
+ Tables = 46,
+ FreeStmt = 47,
+ CloseCursor = 48,
+ Cancel = 49,
+ EndTran = 50,
+ Disconnect = 51,
+ FreeHandle = 52,
+ GetCursorName = 53,
+ NativeSql = 54,
+};
+
+namespace connectivity::odbc
+ {
+ class OConnection;
+
+ const sal_Int32 MAX_PUT_DATA_LENGTH = 2000;
+
+ class OOO_DLLPUBLIC_ODBCBASE OTools
+ {
+ public:
+ /// @throws css::sdbc::SQLException
+ static void ThrowException( const OConnection* _pConnection,
+ SQLRETURN _rRetCode,
+ SQLHANDLE _pContext,
+ SQLSMALLINT _nHandleType,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ bool _bNoFound=true);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ OUString &_rValue,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ rtl_TextEncoding _nTextEncoding);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ sal_Int32 &_rValue,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ SQLUSMALLINT &_rValue,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void GetInfo(OConnection const * _pConnection,
+ SQLHANDLE _aConnectionHandle,
+ SQLUSMALLINT _nInfo,
+ SQLUINTEGER &_rValue,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface);
+
+ static sal_Int32 MapOdbcType2Jdbc(SQLSMALLINT _nType);
+ static SQLSMALLINT jdbcTypeToOdbc(sal_Int32 jdbcType);
+
+ static DATE_STRUCT DateToOdbcDate(const css::util::Date& x)
+ {
+ DATE_STRUCT aVal;
+ aVal.year = x.Year;
+ aVal.month = x.Month;
+ aVal.day = x.Day;
+ return aVal;
+ }
+ static TIME_STRUCT TimeToOdbcTime(const css::util::Time& x)
+ {
+ TIME_STRUCT aVal;
+ aVal.hour = x.Hours;
+ aVal.minute = x.Minutes;
+ aVal.second = x.Seconds;
+ return aVal;
+ }
+ static TIMESTAMP_STRUCT DateTimeToTimestamp(const css::util::DateTime& x)
+ {
+ TIMESTAMP_STRUCT aVal;
+ aVal.year = x.Year;
+ aVal.month = x.Month;
+ aVal.day = x.Day;
+ aVal.hour = x.Hours;
+ aVal.minute = x.Minutes;
+ aVal.second = x.Seconds;
+ aVal.fraction = x.NanoSeconds;
+ return aVal;
+ }
+ /**
+ getBindTypes set the ODBC type for C
+ @param _bUseWChar true when Unicode should be used
+ @param _bUseOldTimeDate true when the old datetime format should be used
+ @param _nOdbcType the ODBC sql type
+ @param fCType the C type for the ODBC type
+ @param fSqlType the SQL type for the ODBC type
+ */
+ static void getBindTypes(bool _bUseWChar,
+ bool _bUseOldTimeDate,
+ SQLSMALLINT _nOdbcType,
+ SQLSMALLINT& fCType,
+ SQLSMALLINT& fSqlType);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static OUString getStringValue( OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _fSqlType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ rtl_TextEncoding _nTextEncoding);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static css::uno::Sequence<sal_Int8> getBytesValue(const OConnection* _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _fSqlType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void getValue( OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _nType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ void* _pValue,
+ SQLLEN _nSize);
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ static void bindValue( OConnection const * _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _nType,
+ SQLSMALLINT _nMaxLen,
+ const void* _pValue,
+ void* _pData,
+ SQLLEN *pLen,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ rtl_TextEncoding _nTextEncoding,
+ bool _bUseOldTimeDate);
+ };
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ template <class T> void getValue( const OConnection* _pConnection,
+ SQLHANDLE _aStatementHandle,
+ sal_Int32 columnIndex,
+ SQLSMALLINT _nType,
+ bool &_bWasNull,
+ const css::uno::Reference< css::uno::XInterface >& _xInterface,
+ T& _rValue)
+ {
+ OTools::getValue(_pConnection,_aStatementHandle,columnIndex,_nType,_bWasNull,_xInterface,&_rValue,sizeof _rValue);
+ }
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/odbc/odbcbasedllapi.hxx b/connectivity/source/inc/odbc/odbcbasedllapi.hxx
new file mode 100644
index 000000000..bf7f5a486
--- /dev/null
+++ b/connectivity/source/inc/odbc/odbcbasedllapi.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+#if defined OOO_DLLIMPLEMENTATION_ODBCBASE
+#define OOO_DLLPUBLIC_ODBCBASE SAL_DLLPUBLIC_EXPORT
+#else
+#define OOO_DLLPUBLIC_ODBCBASE SAL_DLLPUBLIC_IMPORT
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/propertyids.hxx b/connectivity/source/inc/propertyids.hxx
new file mode 100644
index 000000000..1a9e3720f
--- /dev/null
+++ b/connectivity/source/inc/propertyids.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// this define has to be set to split the names into different dll's or so's
+// every dll has his own set of property names
+#include <rtl/ustring.hxx>
+#include <map>
+#include <connectivity/dbtoolsdllapi.hxx>
+
+namespace dbtools
+{
+ class OOO_DLLPUBLIC_DBTOOLS OPropertyMap
+ {
+ std::map<sal_Int32, OUString> m_aPropertyMap;
+ public:
+ OPropertyMap();
+ const OUString& getNameByIndex(sal_Int32 _nIndex) const;
+ };
+}
+
+#define PROPERTY_ID_QUERYTIMEOUT 1
+#define PROPERTY_ID_MAXFIELDSIZE 2
+#define PROPERTY_ID_MAXROWS 3
+#define PROPERTY_ID_CURSORNAME 4
+#define PROPERTY_ID_RESULTSETCONCURRENCY 5
+#define PROPERTY_ID_RESULTSETTYPE 6
+#define PROPERTY_ID_FETCHDIRECTION 7
+#define PROPERTY_ID_FETCHSIZE 8
+#define PROPERTY_ID_ESCAPEPROCESSING 9
+#define PROPERTY_ID_USEBOOKMARKS 10
+// Column
+#define PROPERTY_ID_NAME 11
+#define PROPERTY_ID_TYPE 12
+#define PROPERTY_ID_TYPENAME 13
+#define PROPERTY_ID_PRECISION 14
+#define PROPERTY_ID_SCALE 15
+#define PROPERTY_ID_ISNULLABLE 16
+#define PROPERTY_ID_ISAUTOINCREMENT 17
+#define PROPERTY_ID_ISROWVERSION 18
+#define PROPERTY_ID_DESCRIPTION 19
+#define PROPERTY_ID_DEFAULTVALUE 20
+
+#define PROPERTY_ID_REFERENCEDTABLE 21
+#define PROPERTY_ID_UPDATERULE 22
+#define PROPERTY_ID_DELETERULE 23
+#define PROPERTY_ID_CATALOG 24
+#define PROPERTY_ID_ISUNIQUE 25
+#define PROPERTY_ID_ISPRIMARYKEYINDEX 26
+#define PROPERTY_ID_ISCLUSTERED 27
+#define PROPERTY_ID_ISASCENDING 28
+#define PROPERTY_ID_SCHEMANAME 29
+#define PROPERTY_ID_CATALOGNAME 30
+
+#define PROPERTY_ID_COMMAND 31
+#define PROPERTY_ID_CHECKOPTION 32
+#define PROPERTY_ID_PASSWORD 33
+#define PROPERTY_ID_RELATEDCOLUMN 34
+
+#define PROPERTY_ID_FUNCTION 35
+#define PROPERTY_ID_TABLENAME 36
+#define PROPERTY_ID_REALNAME 37
+#define PROPERTY_ID_DBASEPRECISIONCHANGED 38
+#define PROPERTY_ID_ISCURRENCY 39
+#define PROPERTY_ID_ISBOOKMARKABLE 40
+
+#define PROPERTY_ID_INVALID_INDEX 41
+#define PROPERTY_ID_HY010 43
+#define PROPERTY_ID_LABEL 44
+#define PROPERTY_ID_DELIMITER 45
+#define PROPERTY_ID_FORMATKEY 46
+#define PROPERTY_ID_LOCALE 47
+#define PROPERTY_ID_IM001 48
+
+#define PROPERTY_ID_AUTOINCREMENTCREATION 49
+
+#define PROPERTY_ID_PRIVILEGES 50
+#define PROPERTY_ID_HAVINGCLAUSE 51
+
+#define PROPERTY_ID_ISSIGNED 52
+#define PROPERTY_ID_AGGREGATEFUNCTION 53
+#define PROPERTY_ID_ISSEARCHABLE 54
+
+#define PROPERTY_ID_APPLYFILTER 55
+#define PROPERTY_ID_FILTER 56
+#define PROPERTY_ID_MASTERFIELDS 57
+#define PROPERTY_ID_DETAILFIELDS 58
+#define PROPERTY_ID_FIELDTYPE 59
+#define PROPERTY_ID_VALUE 60
+#define PROPERTY_ID_ACTIVE_CONNECTION 61
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/resource/sharedresources.hxx b/connectivity/source/inc/resource/sharedresources.hxx
new file mode 100644
index 000000000..0c439cdf2
--- /dev/null
+++ b/connectivity/source/inc/resource/sharedresources.hxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <vector>
+#include <connectivity/dbtoolsdllapi.hxx>
+#include <unotools/resmgr.hxx>
+
+namespace connectivity
+{
+
+
+ typedef sal_uInt16 ResourceId;
+
+ /** helper class for accessing resources shared by different libraries
+ in the connectivity module
+ */
+ class OOO_DLLPUBLIC_DBTOOLS SharedResources
+ {
+ public:
+ SharedResources();
+ ~SharedResources();
+
+ /** loads a string from the shared resource file
+ @param pResId
+ the resource ID of the string
+ @return
+ the string from the resource file
+ */
+ OUString
+ getResourceString(
+ TranslateId pResId
+ ) const;
+
+ /** loads a string from the shared resource file, and replaces
+ a given ASCII pattern with a given string
+
+ @param pResId
+ the resource ID of the string to load
+ @param _pAsciiPatternToReplace
+ the ASCII string which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute
+ the String which should substitute the ASCII pattern.
+
+ @return
+ the string from the resource file, with applied string substitution
+ */
+ OUString
+ getResourceStringWithSubstitution(
+ TranslateId pResId,
+ const char* _pAsciiPatternToReplace,
+ const OUString& _rStringToSubstitute
+ ) const;
+
+ /** loads a string from the shared resource file, and replaces
+ a given ASCII pattern with a given string
+
+ @param pResId
+ the resource ID of the string to load
+ @param _pAsciiPatternToReplace1
+ the ASCII string (1) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute1
+ the String which should substitute the ASCII pattern (1)
+ @param _pAsciiPatternToReplace2
+ the ASCII string (2) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute2
+ the String which should substitute the ASCII pattern (2)
+
+ @return
+ the string from the resource file, with applied string substitution
+ */
+ OUString
+ getResourceStringWithSubstitution(
+ TranslateId pResId,
+ const char* _pAsciiPatternToReplace1,
+ const OUString& _rStringToSubstitute1,
+ const char* _pAsciiPatternToReplace2,
+ const OUString& _rStringToSubstitute2
+ ) const;
+
+ /** loads a string from the shared resource file, and replaces
+ a given ASCII pattern with a given string
+
+ @param pResId
+ the resource ID of the string to load
+ @param _pAsciiPatternToReplace1
+ the ASCII string (1) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute1
+ the String which should substitute the ASCII pattern (1)
+ @param _pAsciiPatternToReplace2
+ the ASCII string (2) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute2
+ the String which should substitute the ASCII pattern (2)
+ @param _pAsciiPatternToReplace3
+ the ASCII string (3) which is to search in the string. Must not be <NULL/>.
+ @param _rStringToSubstitute3
+ the String which should substitute the ASCII pattern (3)
+
+ @return
+ the string from the resource file, with applied string substitution
+ */
+ OUString
+ getResourceStringWithSubstitution(
+ TranslateId pResId,
+ const char* _pAsciiPatternToReplace1,
+ const OUString& _rStringToSubstitute1,
+ const char* _pAsciiPatternToReplace2,
+ const OUString& _rStringToSubstitute2,
+ const char* _pAsciiPatternToReplace3,
+ const OUString& _rStringToSubstitute3
+ ) const;
+
+ /** loads a string from the shared resource file, and replaces a given ASCII pattern with a given string
+
+ @param pResId
+ the resource ID of the string to load
+ @param _aStringToSubstitutes
+ A list of substitutions.
+
+ @return
+ the string from the resource file, with applied string substitution
+ */
+ OUString getResourceStringWithSubstitution( TranslateId pResId,
+ const std::vector< std::pair<const char* , OUString > >& _rStringToSubstitutes) const;
+ };
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WCatalog.hxx b/connectivity/source/inc/writer/WCatalog.hxx
new file mode 100644
index 000000000..be61dbabd
--- /dev/null
+++ b/connectivity/source/inc/writer/WCatalog.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FCatalog.hxx>
+
+namespace connectivity::writer
+{
+class OWriterConnection;
+class OWriterCatalog : public file::OFileCatalog
+{
+public:
+ void refreshTables() override;
+
+ OWriterCatalog(OWriterConnection* pConnection);
+};
+
+} // namespace connectivity::writer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WConnection.hxx b/connectivity/source/inc/writer/WConnection.hxx
new file mode 100644
index 000000000..768518a97
--- /dev/null
+++ b/connectivity/source/inc/writer/WConnection.hxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <file/FConnection.hxx>
+#include <com/sun/star/frame/XDesktop2.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <rtl/ref.hxx>
+#include <unotools/closeveto.hxx>
+
+namespace com::sun::star::text
+{
+class XTextDocument;
+}
+namespace utl
+{
+class CloseVeto;
+}
+
+namespace connectivity::writer
+{
+class ODriver;
+class OWriterConnection : public file::OConnection
+{
+ // the spreadsheet document:
+ css::uno::Reference<css::text::XTextDocument> m_xDoc;
+ OUString m_sPassword;
+ OUString m_aFileName;
+ oslInterlockedCount m_nDocCount;
+
+ class CloseVetoButTerminateListener
+ : public cppu::WeakComponentImplHelper<css::frame::XTerminateListener>
+ {
+ private:
+ /// close listener that vetoes so nobody else disposes m_xDoc
+ std::unique_ptr<utl::CloseVeto> m_pCloseListener;
+ /// but also listen to XDesktop and if app is terminating anyway, dispose m_xDoc while
+ /// its still possible to do so properly
+ css::uno::Reference<css::frame::XDesktop2> m_xDesktop;
+ osl::Mutex m_aMutex;
+
+ public:
+ CloseVetoButTerminateListener()
+ : cppu::WeakComponentImplHelper<css::frame::XTerminateListener>(m_aMutex)
+ {
+ }
+
+ void start(const css::uno::Reference<css::uno::XInterface>& rCloseable,
+ const css::uno::Reference<css::frame::XDesktop2>& rDesktop)
+ {
+ m_xDesktop = rDesktop;
+ m_xDesktop->addTerminateListener(this);
+ m_pCloseListener = std::make_unique<utl::CloseVeto>(rCloseable, true);
+ }
+
+ void stop()
+ {
+ m_pCloseListener.reset();
+ if (!m_xDesktop.is())
+ return;
+ m_xDesktop->removeTerminateListener(this);
+ m_xDesktop.clear();
+ }
+
+ // XTerminateListener
+ void SAL_CALL queryTermination(const css::lang::EventObject& /*rEvent*/) override {}
+
+ void SAL_CALL notifyTermination(const css::lang::EventObject& /*rEvent*/) override
+ {
+ stop();
+ }
+
+ void SAL_CALL disposing() override
+ {
+ stop();
+ cppu::WeakComponentImplHelperBase::disposing();
+ }
+
+ void SAL_CALL disposing(const css::lang::EventObject& rEvent) override
+ {
+ const bool bShutDown = (rEvent.Source == m_xDesktop);
+ if (bShutDown)
+ stop();
+ }
+ };
+
+ rtl::Reference<CloseVetoButTerminateListener> m_xCloseVetoButTerminateListener;
+
+public:
+ OWriterConnection(ODriver* _pDriver);
+ ~OWriterConnection() override;
+
+ void construct(const OUString& rURL,
+ const css::uno::Sequence<css::beans::PropertyValue>& rInfo) override;
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // OComponentHelper
+ void SAL_CALL disposing() override;
+
+ // XConnection
+ css::uno::Reference<css::sdbc::XDatabaseMetaData> SAL_CALL getMetaData() override;
+ css::uno::Reference<css::sdbcx::XTablesSupplier> createCatalog() override;
+ css::uno::Reference<css::sdbc::XStatement> SAL_CALL createStatement() override;
+ css::uno::Reference<css::sdbc::XPreparedStatement>
+ SAL_CALL prepareStatement(const OUString& sql) override;
+ css::uno::Reference<css::sdbc::XPreparedStatement>
+ SAL_CALL prepareCall(const OUString& sql) override;
+
+ // no interface methods
+ css::uno::Reference<css::text::XTextDocument> const& acquireDoc();
+ void releaseDoc();
+
+ class ODocHolder
+ {
+ OWriterConnection* m_pConnection;
+ css::uno::Reference<css::text::XTextDocument> m_xDoc;
+
+ public:
+ ODocHolder(OWriterConnection* _pConnection)
+ : m_pConnection(_pConnection)
+ {
+ m_xDoc = m_pConnection->acquireDoc();
+ }
+ ~ODocHolder()
+ {
+ m_xDoc.clear();
+ m_pConnection->releaseDoc();
+ }
+ const css::uno::Reference<css::text::XTextDocument>& getDoc() const { return m_xDoc; }
+ };
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WDatabaseMetaData.hxx b/connectivity/source/inc/writer/WDatabaseMetaData.hxx
new file mode 100644
index 000000000..b464be11c
--- /dev/null
+++ b/connectivity/source/inc/writer/WDatabaseMetaData.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <component/CDatabaseMetaData.hxx>
+
+namespace connectivity::writer
+{
+class OWriterDatabaseMetaData : public component::OComponentDatabaseMetaData
+{
+ OUString SAL_CALL getURL() override;
+ css::uno::Reference<css::sdbc::XResultSet>
+ SAL_CALL getTables(const css::uno::Any& catalog, const OUString& schemaPattern,
+ const OUString& tableNamePattern,
+ const css::uno::Sequence<OUString>& types) override;
+
+protected:
+ ~OWriterDatabaseMetaData() override;
+
+public:
+ OWriterDatabaseMetaData(file::OConnection* pConnection);
+};
+
+} // namespace connectivity::writer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WDriver.hxx b/connectivity/source/inc/writer/WDriver.hxx
new file mode 100644
index 000000000..b43168eac
--- /dev/null
+++ b/connectivity/source/inc/writer/WDriver.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FDriver.hxx>
+
+namespace com::sun::star::lang
+{
+class XMultiServiceFactory;
+}
+
+namespace connectivity::writer
+{
+class ODriver : public file::OFileDriver
+{
+public:
+ ODriver(const css::uno::Reference<css::uno::XComponentContext>& _rxContext)
+ : file::OFileDriver(_rxContext)
+ {
+ }
+
+ /// @throws css::uno::RuntimeException
+ OUString SAL_CALL getImplementationName() override;
+
+ // XDriver
+ css::uno::Reference<css::sdbc::XConnection>
+ SAL_CALL connect(const OUString& url,
+ const css::uno::Sequence<css::beans::PropertyValue>& info) override;
+ sal_Bool SAL_CALL acceptsURL(const OUString& url) override;
+ css::uno::Sequence<css::sdbc::DriverPropertyInfo> SAL_CALL getPropertyInfo(
+ const OUString& url, const css::uno::Sequence<css::beans::PropertyValue>& info) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WTable.hxx b/connectivity/source/inc/writer/WTable.hxx
new file mode 100644
index 000000000..90cdc2494
--- /dev/null
+++ b/connectivity/source/inc/writer/WTable.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <component/CTable.hxx>
+
+namespace com::sun::star::text
+{
+class XTextTable;
+}
+namespace com::sun::star::util
+{
+class XNumberFormats;
+}
+
+namespace connectivity::writer
+{
+using OWriterTable_BASE = component::OComponentTable;
+class OWriterConnection;
+
+class OWriterTable : public OWriterTable_BASE
+{
+private:
+ css::uno::Reference<css::text::XTextTable> m_xTable;
+ OWriterConnection* m_pWriterConnection;
+ sal_Int32 m_nStartCol;
+ sal_Int32 m_nDataCols;
+ bool m_bHasHeaders;
+
+ void fillColumns();
+
+public:
+ OWriterTable(sdbcx::OCollection* _pTables, OWriterConnection* _pConnection,
+ const OUString& Name, const OUString& Type);
+
+ bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override;
+
+ void SAL_CALL disposing() override;
+
+ // css::lang::XUnoTunnel
+ sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8>& rId) override;
+ static const css::uno::Sequence<sal_Int8>& getUnoTunnelId();
+
+ void construct() override;
+};
+
+} // namespace connectivity::writer
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/inc/writer/WTables.hxx b/connectivity/source/inc/writer/WTables.hxx
new file mode 100644
index 000000000..df39cc1c2
--- /dev/null
+++ b/connectivity/source/inc/writer/WTables.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <file/FTables.hxx>
+
+namespace connectivity::writer
+{
+using OWriterTables_BASE = file::OTables;
+
+class OWriterTables : public OWriterTables_BASE
+{
+protected:
+ sdbcx::ObjectType createObject(const OUString& rName) override;
+
+public:
+ OWriterTables(const css::uno::Reference<css::sdbc::XDatabaseMetaData>& _rMetaData,
+ ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const ::std::vector<OUString>& _rVector)
+ : OWriterTables_BASE(_rMetaData, _rParent, _rMutex, _rVector)
+ {
+ }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/manager/mdrivermanager.cxx b/connectivity/source/manager/mdrivermanager.cxx
new file mode 100644
index 000000000..e7e0adf5e
--- /dev/null
+++ b/connectivity/source/manager/mdrivermanager.cxx
@@ -0,0 +1,665 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_fuzzers.h>
+
+#include "mdrivermanager.hxx"
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/sdbc/XDriver.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/logging/LogLevel.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <osl/diagnose.h>
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace drivermanager
+{
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::logging;
+using namespace ::osl;
+
+constexpr OUStringLiteral SERVICE_SDBC_DRIVER = u"com.sun.star.sdbc.Driver";
+
+/// @throws NoSuchElementException
+static void throwNoSuchElementException()
+{
+ throw NoSuchElementException();
+}
+
+class ODriverEnumeration : public ::cppu::WeakImplHelper< XEnumeration >
+{
+ friend class OSDBCDriverManager;
+
+ typedef std::vector< Reference< XDriver > > DriverArray;
+ DriverArray m_aDrivers;
+ DriverArray::const_iterator m_aPos;
+ // order matters!
+
+protected:
+ virtual ~ODriverEnumeration() override;
+public:
+ explicit ODriverEnumeration(DriverArray&& _rDriverSequence);
+
+// XEnumeration
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override;
+ virtual Any SAL_CALL nextElement( ) override;
+};
+
+
+ODriverEnumeration::ODriverEnumeration(DriverArray&& _rDriverSequence)
+ :m_aDrivers( std::move(_rDriverSequence) )
+ ,m_aPos( m_aDrivers.begin() )
+{
+}
+
+
+ODriverEnumeration::~ODriverEnumeration()
+{
+}
+
+
+sal_Bool SAL_CALL ODriverEnumeration::hasMoreElements( )
+{
+ return m_aPos != m_aDrivers.end();
+}
+
+
+Any SAL_CALL ODriverEnumeration::nextElement( )
+{
+ if ( !hasMoreElements() )
+ throwNoSuchElementException();
+
+ return Any( *m_aPos++ );
+}
+
+namespace
+{
+ /// an STL functor which ensures that a SdbcDriver described by a DriverAccess is loaded
+ struct EnsureDriver
+ {
+ explicit EnsureDriver( const Reference< XComponentContext > &rxContext )
+ : mxContext( rxContext ) {}
+
+ const DriverAccess& operator()( const DriverAccess& _rDescriptor ) const
+ {
+ // we did not load this driver, yet
+ if (_rDescriptor.xDriver.is())
+ return _rDescriptor;
+
+ // we have a factory for it
+ if (_rDescriptor.xComponentFactory.is())
+ {
+ DriverAccess& rDesc = const_cast<DriverAccess&>(_rDescriptor);
+ try
+ {
+ //load driver
+ rDesc.xDriver.set(
+ rDesc.xComponentFactory->createInstanceWithContext(mxContext), css::uno::UNO_QUERY);
+ }
+ catch (const Exception&)
+ {
+ //failure, abandon driver
+ rDesc.xComponentFactory.clear();
+ }
+ }
+ return _rDescriptor;
+ }
+
+ private:
+ Reference< XComponentContext > mxContext;
+ };
+
+ /// an STL functor which extracts a SdbcDriver from a DriverAccess
+ struct ExtractDriverFromAccess
+ {
+ const Reference<XDriver>& operator()( const DriverAccess& _rAccess ) const
+ {
+ return _rAccess.xDriver;
+ }
+ };
+
+ struct ExtractDriverFromCollectionElement
+ {
+ const Reference<XDriver>& operator()( const DriverCollection::value_type& _rElement ) const
+ {
+ return _rElement.second;
+ }
+ };
+
+ // predicate for checking whether or not a driver accepts a given URL
+ class AcceptsURL
+ {
+ protected:
+ const OUString& m_rURL;
+
+ public:
+ // ctor
+ explicit AcceptsURL( const OUString& _rURL ) : m_rURL( _rURL ) { }
+
+
+ bool operator()( const Reference<XDriver>& _rDriver ) const
+ {
+ // ask the driver
+ return _rDriver.is() && _rDriver->acceptsURL( m_rURL );
+ }
+ };
+
+#if !ENABLE_FUZZERS
+ sal_Int32 lcl_getDriverPrecedence( const Reference<XComponentContext>& _rContext, Sequence< OUString >& _rPrecedence )
+ {
+ _rPrecedence.realloc( 0 );
+ try
+ {
+ // create a configuration provider
+ Reference< XMultiServiceFactory > xConfigurationProvider(
+ css::configuration::theDefaultProvider::get( _rContext ) );
+
+ // one argument for creating the node access: the path to the configuration node
+ Sequence< Any > aCreationArgs{ Any(NamedValue(
+ "nodepath", Any( OUString("org.openoffice.Office.DataAccess/DriverManager") ) )) };
+
+ // create the node access
+ Reference< XNameAccess > xDriverManagerNode(
+ xConfigurationProvider->createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", aCreationArgs),
+ UNO_QUERY);
+
+ OSL_ENSURE(xDriverManagerNode.is(), "lcl_getDriverPrecedence: could not open my configuration node!");
+ if (xDriverManagerNode.is())
+ {
+ // obtain the preference list
+ Any aPreferences = xDriverManagerNode->getByName("DriverPrecedence");
+ bool bSuccess = aPreferences >>= _rPrecedence;
+ OSL_ENSURE(bSuccess || !aPreferences.hasValue(), "lcl_getDriverPrecedence: invalid value for the preferences node (no string sequence but not NULL)!");
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.manager");
+ }
+
+ return _rPrecedence.getLength();
+ }
+#endif
+
+ /// an STL algorithm compatible predicate comparing two DriverAccess instances by their implementation names
+ struct CompareDriverAccessByName
+ {
+
+ bool operator()( const DriverAccess& lhs, const DriverAccess& rhs )
+ {
+ return lhs.sImplementationName < rhs.sImplementationName;
+ }
+ };
+
+ /// and an STL algorithm compatible predicate comparing the impl name of a DriverAccess to a string
+ struct EqualDriverAccessToName
+ {
+ OUString m_sImplName;
+ explicit EqualDriverAccessToName(const OUString& _sImplName) : m_sImplName(_sImplName){}
+
+ bool operator()( const DriverAccess& lhs)
+ {
+ return lhs.sImplementationName == m_sImplName;
+ }
+ };
+}
+
+OSDBCDriverManager::OSDBCDriverManager( const Reference< XComponentContext >& _rxContext )
+ :OSDBCDriverManager_Base(m_aMutex)
+ ,m_xContext( _rxContext )
+ ,m_aEventLogger( _rxContext, "org.openoffice.logging.sdbc.DriverManager" )
+ ,m_aDriverConfig(m_xContext)
+ ,m_nLoginTimeout(0)
+{
+ // bootstrap all objects supporting the .sdb.Driver service
+ bootstrapDrivers();
+
+ // initialize the drivers order
+ initializeDriverPrecedence();
+}
+
+
+OSDBCDriverManager::~OSDBCDriverManager()
+{
+}
+
+void OSDBCDriverManager::bootstrapDrivers()
+{
+ Reference< XContentEnumerationAccess > xEnumAccess( m_xContext->getServiceManager(), UNO_QUERY );
+ Reference< XEnumeration > xEnumDrivers;
+ if (xEnumAccess.is())
+ xEnumDrivers = xEnumAccess->createContentEnumeration(SERVICE_SDBC_DRIVER);
+
+ OSL_ENSURE( xEnumDrivers.is(), "OSDBCDriverManager::bootstrapDrivers: no enumeration for the drivers available!" );
+ if (!xEnumDrivers.is())
+ return;
+
+ Reference< XSingleComponentFactory > xFactory;
+ Reference< XServiceInfo > xSI;
+ while (xEnumDrivers->hasMoreElements())
+ {
+ xFactory.set(xEnumDrivers->nextElement(), css::uno::UNO_QUERY);
+ OSL_ENSURE( xFactory.is(), "OSDBCDriverManager::bootstrapDrivers: no factory extracted" );
+
+ if ( xFactory.is() )
+ {
+ // we got a factory for the driver
+ DriverAccess aDriverDescriptor;
+ bool bValidDescriptor = false;
+
+ // can it tell us something about the implementation name?
+ xSI.set(xFactory, css::uno::UNO_QUERY);
+ if ( xSI.is() )
+ { // yes -> no need to load the driver immediately (load it later when needed)
+ aDriverDescriptor.sImplementationName = xSI->getImplementationName();
+ aDriverDescriptor.xComponentFactory = xFactory;
+ bValidDescriptor = true;
+
+ m_aEventLogger.log( LogLevel::CONFIG,
+ "found SDBC driver $1$, no need to load it",
+ aDriverDescriptor.sImplementationName
+ );
+ }
+ else
+ {
+ // no -> create the driver
+ Reference< XDriver > xDriver( xFactory->createInstanceWithContext( m_xContext ), UNO_QUERY );
+ OSL_ENSURE( xDriver.is(), "OSDBCDriverManager::bootstrapDrivers: a driver which is no driver?!" );
+
+ if ( xDriver.is() )
+ {
+ aDriverDescriptor.xDriver = xDriver;
+ // and obtain its implementation name
+ xSI.set(xDriver, css::uno::UNO_QUERY);
+ OSL_ENSURE( xSI.is(), "OSDBCDriverManager::bootstrapDrivers: a driver without service info?" );
+ if ( xSI.is() )
+ {
+ aDriverDescriptor.sImplementationName = xSI->getImplementationName();
+ bValidDescriptor = true;
+
+ m_aEventLogger.log( LogLevel::CONFIG,
+ "found SDBC driver $1$, needed to load it",
+ aDriverDescriptor.sImplementationName
+ );
+ }
+ }
+ }
+
+ if ( bValidDescriptor )
+ {
+ m_aDriversBS.push_back( aDriverDescriptor );
+ }
+ }
+ }
+}
+
+
+void OSDBCDriverManager::initializeDriverPrecedence()
+{
+#if !ENABLE_FUZZERS
+ if ( m_aDriversBS.empty() )
+ // nothing to do
+ return;
+
+ try
+ {
+ // get the precedence of the drivers from the configuration
+ Sequence< OUString > aDriverOrder;
+ if ( 0 == lcl_getDriverPrecedence( m_xContext, aDriverOrder ) )
+ // nothing to do
+ return;
+
+ // aDriverOrder now is the list of driver implementation names in the order they should be used
+
+ if ( m_aEventLogger.isLoggable( LogLevel::CONFIG ) )
+ {
+ sal_Int32 nOrderedCount = aDriverOrder.getLength();
+ for ( sal_Int32 i=0; i<nOrderedCount; ++i )
+ m_aEventLogger.log( LogLevel::CONFIG,
+ "configuration's driver order: driver $1$ of $2$: $3$",
+ static_cast<sal_Int32>(i + 1), nOrderedCount, aDriverOrder[i]
+ );
+ }
+
+ // sort our bootstrapped drivers
+ std::sort( m_aDriversBS.begin(), m_aDriversBS.end(), CompareDriverAccessByName() );
+
+ // the first driver for which there is no preference
+ DriverAccessArray::iterator aNoPrefDriversStart = m_aDriversBS.begin();
+ // at the moment this is the first of all drivers we know
+
+ // loop through the names in the precedence order
+ for ( const OUString& rDriverOrder : std::as_const(aDriverOrder) )
+ {
+ if (aNoPrefDriversStart == m_aDriversBS.end())
+ break;
+
+ DriverAccess driver_order;
+ driver_order.sImplementationName = rDriverOrder;
+
+ // look for the impl name in the DriverAccess array
+ std::pair< DriverAccessArray::iterator, DriverAccessArray::iterator > aPos =
+ std::equal_range( aNoPrefDriversStart, m_aDriversBS.end(), driver_order, CompareDriverAccessByName() );
+
+ if ( aPos.first != aPos.second )
+ { // we have a DriverAccess with this impl name
+
+ OSL_ENSURE( std::distance( aPos.first, aPos.second ) == 1,
+ "OSDBCDriverManager::initializeDriverPrecedence: more than one driver with this impl name? How this?" );
+ // move the DriverAccess pointed to by aPos.first to the position pointed to by aNoPrefDriversStart
+
+ if ( aPos.first != aNoPrefDriversStart )
+ { // if this does not hold, the DriverAccess already has the correct position
+
+ // rotate the range [aNoPrefDriversStart, aPos.second) right 1 element
+ std::rotate( aNoPrefDriversStart, aPos.second - 1, aPos.second );
+ }
+
+ // next round we start searching and pos right
+ ++aNoPrefDriversStart;
+ }
+ }
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "OSDBCDriverManager::initializeDriverPrecedence: caught an exception while sorting the drivers!");
+ }
+#endif
+}
+
+
+Reference< XConnection > SAL_CALL OSDBCDriverManager::getConnection( const OUString& _rURL )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "connection requested for URL $1$",
+ _rURL
+ );
+
+ Reference< XConnection > xConnection;
+ Reference< XDriver > xDriver = implGetDriverForURL(_rURL);
+ if (xDriver.is())
+ {
+ // TODO : handle the login timeout
+ xConnection = xDriver->connect(_rURL, Sequence< PropertyValue >());
+ // may throw an exception
+ m_aEventLogger.log( LogLevel::INFO,
+ "connection retrieved for URL $1$",
+ _rURL
+ );
+ }
+
+ return xConnection;
+}
+
+
+Reference< XConnection > SAL_CALL OSDBCDriverManager::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "connection with info requested for URL $1$",
+ _rURL
+ );
+
+ Reference< XConnection > xConnection;
+ Reference< XDriver > xDriver = implGetDriverForURL(_rURL);
+ if (xDriver.is())
+ {
+ // TODO : handle the login timeout
+ xConnection = xDriver->connect(_rURL, _rInfo);
+ // may throw an exception
+ m_aEventLogger.log( LogLevel::INFO,
+ "connection with info retrieved for URL $1$",
+ _rURL
+ );
+ }
+
+ return xConnection;
+}
+
+
+void SAL_CALL OSDBCDriverManager::setLoginTimeout( sal_Int32 seconds )
+{
+ MutexGuard aGuard(m_aMutex);
+ m_nLoginTimeout = seconds;
+}
+
+
+sal_Int32 SAL_CALL OSDBCDriverManager::getLoginTimeout( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_nLoginTimeout;
+}
+
+
+Reference< XEnumeration > SAL_CALL OSDBCDriverManager::createEnumeration( )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ ODriverEnumeration::DriverArray aDrivers;
+
+ // ensure that all our bootstrapped drivers are instantiated
+ std::for_each( m_aDriversBS.begin(), m_aDriversBS.end(), EnsureDriver( m_xContext ) );
+
+ // copy the bootstrapped drivers
+ std::transform(
+ m_aDriversBS.begin(), // "copy from" start
+ m_aDriversBS.end(), // "copy from" end
+ std::back_inserter( aDrivers ), // insert into
+ ExtractDriverFromAccess() // transformation to apply (extract a driver from a driver access)
+ );
+
+ // append the runtime drivers
+ std::transform(
+ m_aDriversRT.begin(), // "copy from" start
+ m_aDriversRT.end(), // "copy from" end
+ std::back_inserter( aDrivers ), // insert into
+ ExtractDriverFromCollectionElement() // transformation to apply (extract a driver from a driver access)
+ );
+
+ return new ODriverEnumeration( std::move(aDrivers) );
+}
+
+
+css::uno::Type SAL_CALL OSDBCDriverManager::getElementType( )
+{
+ return cppu::UnoType<XDriver>::get();
+}
+
+
+sal_Bool SAL_CALL OSDBCDriverManager::hasElements( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return !(m_aDriversBS.empty() && m_aDriversRT.empty());
+}
+
+
+OUString SAL_CALL OSDBCDriverManager::getImplementationName( )
+{
+ return "com.sun.star.comp.sdbc.OSDBCDriverManager";
+}
+
+sal_Bool SAL_CALL OSDBCDriverManager::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Sequence< OUString > SAL_CALL OSDBCDriverManager::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.DriverManager" };
+}
+
+
+Reference< XInterface > SAL_CALL OSDBCDriverManager::getRegisteredObject( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+ DriverCollection::const_iterator aSearch = m_aDriversRT.find(_rName);
+ if (aSearch == m_aDriversRT.end())
+ throwNoSuchElementException();
+
+ return aSearch->second;
+}
+
+
+void SAL_CALL OSDBCDriverManager::registerObject( const OUString& _rName, const Reference< XInterface >& _rxObject )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "attempt to register new driver for name $1$",
+ _rName
+ );
+
+ DriverCollection::const_iterator aSearch = m_aDriversRT.find(_rName);
+ if (aSearch != m_aDriversRT.end())
+ throw ElementExistException();
+ Reference< XDriver > xNewDriver(_rxObject, UNO_QUERY);
+ if (!xNewDriver.is())
+ throw IllegalArgumentException();
+
+ m_aDriversRT.emplace(_rName, xNewDriver);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "new driver registered for name $1$",
+ _rName
+ );
+}
+
+
+void SAL_CALL OSDBCDriverManager::revokeObject( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "attempt to revoke driver for name $1$",
+ _rName
+ );
+
+ DriverCollection::iterator aSearch = m_aDriversRT.find(_rName);
+ if (aSearch == m_aDriversRT.end())
+ throwNoSuchElementException();
+
+ m_aDriversRT.erase(aSearch); // we already have the iterator so we could use it
+
+ m_aEventLogger.log( LogLevel::INFO,
+ "driver revoked for name $1$",
+ _rName
+ );
+}
+
+
+Reference< XDriver > SAL_CALL OSDBCDriverManager::getDriverByURL( const OUString& _rURL )
+{
+ m_aEventLogger.log( LogLevel::INFO,
+ "driver requested for URL $1$",
+ _rURL
+ );
+
+ Reference< XDriver > xDriver( implGetDriverForURL( _rURL ) );
+
+ if ( xDriver.is() )
+ m_aEventLogger.log( LogLevel::INFO,
+ "driver obtained for URL $1$",
+ _rURL
+ );
+
+ return xDriver;
+}
+
+
+Reference< XDriver > OSDBCDriverManager::implGetDriverForURL(const OUString& _rURL)
+{
+ Reference< XDriver > xReturn;
+
+ {
+ const OUString sDriverFactoryName = m_aDriverConfig.getDriverFactoryName(_rURL);
+
+ EqualDriverAccessToName aEqual(sDriverFactoryName);
+ DriverAccessArray::const_iterator aFind = std::find_if(m_aDriversBS.begin(),m_aDriversBS.end(),aEqual);
+ if ( aFind == m_aDriversBS.end() )
+ {
+ // search all bootstrapped drivers
+ aFind = std::find_if(
+ m_aDriversBS.begin(), // begin of search range
+ m_aDriversBS.end(), // end of search range
+ [&_rURL, this] (const DriverAccessArray::value_type& driverAccess) {
+ // extract the driver from the access, then ask the resulting driver for acceptance
+ const DriverAccess& ensuredAccess = EnsureDriver(m_xContext)(driverAccess);
+ const Reference<XDriver> driver = ExtractDriverFromAccess()(ensuredAccess);
+ return AcceptsURL(_rURL)(driver);
+ });
+ } // if ( m_aDriversBS.find(sDriverFactoryName ) == m_aDriversBS.end() )
+ else
+ {
+ EnsureDriver aEnsure( m_xContext );
+ aEnsure(*aFind);
+ }
+
+ // found something?
+ if ( m_aDriversBS.end() != aFind && aFind->xDriver.is() && aFind->xDriver->acceptsURL(_rURL) )
+ xReturn = aFind->xDriver;
+ }
+
+ if ( !xReturn.is() )
+ {
+ // no -> search the runtime drivers
+ DriverCollection::const_iterator aPos = std::find_if(
+ m_aDriversRT.begin(), // begin of search range
+ m_aDriversRT.end(), // end of search range
+ [&_rURL] (const DriverCollection::value_type& element) {
+ // extract the driver from the collection element, then ask the resulting driver for acceptance
+ const Reference<XDriver> driver = ExtractDriverFromCollectionElement()(element);
+ return AcceptsURL(_rURL)(driver);
+ });
+
+ if ( m_aDriversRT.end() != aPos )
+ xReturn = aPos->second;
+ }
+
+ return xReturn;
+}
+
+} // namespace drivermanager
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+connectivity_OSDBCDriverManager_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new drivermanager::OSDBCDriverManager(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/manager/mdrivermanager.hxx b/connectivity/source/manager/mdrivermanager.hxx
new file mode 100644
index 000000000..239116f1c
--- /dev/null
+++ b/connectivity/source/manager/mdrivermanager.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <vector>
+
+#include <com/sun/star/sdbc/XDriverManager2.hpp>
+#include <com/sun/star/uno/XNamingService.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/logging.hxx>
+#include <connectivity/DriversConfig.hxx>
+
+namespace drivermanager
+{
+
+ typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > DriverCollection;
+
+ struct DriverAccess
+ {
+ OUString sImplementationName; /// the implementation name of the driver
+ css::uno::Reference< css::sdbc::XDriver > xDriver; /// the driver itself
+ css::uno::Reference< css::lang::XSingleComponentFactory > xComponentFactory; /// the factory to create the driver component (if not already done so)
+ };
+
+
+ // OSDBCDriverManager - the one-instance service for managing SDBC drivers
+
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriverManager2
+ , css::lang::XServiceInfo
+ , css::uno::XNamingService
+ > OSDBCDriverManager_Base;
+
+ class OSDBCDriverManager final : public cppu::BaseMutex, public OSDBCDriverManager_Base
+ {
+ friend class ODriverEnumeration;
+
+ css::uno::Reference<css::uno::XComponentContext> m_xContext;
+ ::comphelper::EventLogger m_aEventLogger;
+
+ typedef std::vector<DriverAccess> DriverAccessArray;
+ DriverAccessArray m_aDriversBS;
+
+ // for drivers registered at runtime (not bootstrapped) we don't require an XServiceInfo interface,
+ // so we have to remember their impl-name in another way
+ typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > DriverCollection;
+ DriverCollection m_aDriversRT;
+
+ ::connectivity::DriversConfig m_aDriverConfig;
+ sal_Int32 m_nLoginTimeout;
+
+ public:
+
+ explicit OSDBCDriverManager(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext );
+ virtual ~OSDBCDriverManager() override;
+
+ // XDriverManager
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& url ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override;
+ virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override;
+ virtual sal_Int32 SAL_CALL getLoginTimeout( ) override;
+
+ // XDriverAccess
+ virtual css::uno::Reference< css::sdbc::XDriver > SAL_CALL getDriverByURL( const OUString& url ) override;
+
+ // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XNamingService
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getRegisteredObject( const OUString& Name ) override;
+ virtual void SAL_CALL registerObject( const OUString& Name, const css::uno::Reference< css::uno::XInterface >& Object ) override;
+ virtual void SAL_CALL revokeObject( const OUString& Name ) override;
+
+ private:
+ css::uno::Reference< css::sdbc::XDriver > implGetDriverForURL(const OUString& _rURL);
+
+ /** retrieve the driver order preferences from the configuration and
+ sort m_aDriversBS accordingly.
+ */
+ void initializeDriverPrecedence();
+
+ void bootstrapDrivers();
+ };
+
+} // namespace drivermanager
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/manager/sdbc2.component b/connectivity/source/manager/sdbc2.component
new file mode 100644
index 000000000..b9433256a
--- /dev/null
+++ b/connectivity/source/manager/sdbc2.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.sdbc.OSDBCDriverManager"
+ constructor="connectivity_OSDBCDriverManager_get_implementation" single-instance="true">
+ <service name="com.sun.star.sdbc.DriverManager"/>
+ </implementation>
+</component>
diff --git a/connectivity/source/parse/PColumn.cxx b/connectivity/source/parse/PColumn.cxx
new file mode 100644
index 000000000..5ada4136c
--- /dev/null
+++ b/connectivity/source/parse/PColumn.cxx
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <connectivity/PColumn.hxx>
+#include <TConnection.hxx>
+
+#include <comphelper/types.hxx>
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace dbtools;
+using namespace connectivity::parse;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+
+OParseColumn::OParseColumn(const Reference<XPropertySet>& _xColumn, bool _bCase)
+ : connectivity::sdbcx::OColumn( getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
+ , getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)))
+ , false
+ , getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))
+ , _bCase
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)))
+ )
+ , m_bFunction(false)
+ , m_bDbasePrecisionChanged(false)
+ , m_bAggregateFunction(false)
+ , m_bIsSearchable( true )
+{
+ construct();
+}
+
+
+OParseColumn::OParseColumn( const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ const OUString& Description,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool IsAutoIncrement,
+ bool IsCurrency,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName
+ ) : connectivity::sdbcx::OColumn(Name,
+ TypeName,
+ DefaultValue,
+ Description,
+ IsNullable,
+ Precision,
+ Scale,
+ Type,
+ IsAutoIncrement,
+ false,
+ IsCurrency,
+ _bCase,
+ CatalogName,
+ SchemaName,
+ TableName)
+ , m_bFunction(false)
+ , m_bDbasePrecisionChanged(false)
+ , m_bAggregateFunction(false)
+ , m_bIsSearchable( true )
+{
+ construct();
+}
+
+
+::rtl::Reference< OSQLColumns > OParseColumn::createColumnsForResultSet( const Reference< XResultSetMetaData >& _rxResMetaData,
+ const Reference< XDatabaseMetaData >& _rxDBMetaData,const Reference< XNameAccess>& i_xQueryColumns )
+{
+ sal_Int32 nColumnCount = _rxResMetaData->getColumnCount();
+ ::rtl::Reference aReturn( new OSQLColumns ); aReturn->reserve( nColumnCount );
+
+ StringMap aColumnMap;
+ for ( sal_Int32 i = 1; i <= nColumnCount; ++i )
+ {
+ rtl::Reference<OParseColumn> pColumn = createColumnForResultSet( _rxResMetaData, _rxDBMetaData, i,aColumnMap );
+ aReturn->push_back( pColumn );
+ if ( i_xQueryColumns.is() && i_xQueryColumns->hasByName(pColumn->getRealName()) )
+ {
+ Reference<XPropertySet> xColumn(i_xQueryColumns->getByName(pColumn->getRealName()),UNO_QUERY_THROW);
+ OUString sLabel;
+ xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LABEL)) >>= sLabel;
+ if ( !sLabel.isEmpty() )
+ pColumn->setLabel(sLabel);
+ }
+ }
+
+ return aReturn;
+}
+
+
+rtl::Reference<OParseColumn> OParseColumn::createColumnForResultSet( const Reference< XResultSetMetaData >& _rxResMetaData,
+ const Reference< XDatabaseMetaData >& _rxDBMetaData, sal_Int32 _nColumnPos, StringMap& _rColumns )
+{
+ OUString sLabel = _rxResMetaData->getColumnLabel( _nColumnPos );
+ // retrieve the name of the column
+ // check for duplicate entries
+ if(_rColumns.find(sLabel) != _rColumns.end())
+ {
+ OUString sAlias(sLabel);
+ sal_Int32 searchIndex=1;
+ while(_rColumns.find(sAlias) != _rColumns.end())
+ {
+ sAlias = sLabel + OUString::number(searchIndex++);
+ }
+ sLabel = sAlias;
+ }
+ _rColumns.emplace(sLabel,0);
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(
+ sLabel,
+ _rxResMetaData->getColumnTypeName( _nColumnPos ),
+ OUString(),
+ OUString(),
+ _rxResMetaData->isNullable( _nColumnPos ),
+ _rxResMetaData->getPrecision( _nColumnPos ),
+ _rxResMetaData->getScale( _nColumnPos ),
+ _rxResMetaData->getColumnType( _nColumnPos ),
+ _rxResMetaData->isAutoIncrement( _nColumnPos ),
+ _rxResMetaData->isCurrency( _nColumnPos ),
+ _rxDBMetaData->supportsMixedCaseQuotedIdentifiers(),
+ _rxResMetaData->getCatalogName( _nColumnPos ),
+ _rxResMetaData->getSchemaName( _nColumnPos ),
+ _rxResMetaData->getTableName( _nColumnPos )
+ );
+ pColumn->setIsSearchable( _rxResMetaData->isSearchable( _nColumnPos ) );
+ pColumn->setRealName(_rxResMetaData->getColumnName( _nColumnPos ));
+ pColumn->setLabel(sLabel);
+ return pColumn;
+}
+
+
+OParseColumn::~OParseColumn()
+{
+}
+
+void OParseColumn::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION), PROPERTY_ID_FUNCTION, 0, &m_bFunction, cppu::UnoType<decltype(m_bFunction)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AGGREGATEFUNCTION), PROPERTY_ID_AGGREGATEFUNCTION, 0, &m_bAggregateFunction, cppu::UnoType<decltype(m_bAggregateFunction)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME), PROPERTY_ID_REALNAME, 0, &m_aRealName, cppu::UnoType<decltype(m_aRealName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DBASEPRECISIONCHANGED), PROPERTY_ID_DBASEPRECISIONCHANGED, 0, &m_bDbasePrecisionChanged, cppu::UnoType<decltype(m_bDbasePrecisionChanged)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSEARCHABLE), PROPERTY_ID_ISSEARCHABLE, 0, &m_bIsSearchable, cppu::UnoType<decltype(m_bIsSearchable)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LABEL), PROPERTY_ID_LABEL, 0, &m_sLabel, cppu::UnoType<decltype(m_sLabel)>::get());
+}
+
+::cppu::IPropertyArrayHelper* OParseColumn::createArrayHelper() const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL OParseColumn::getInfoHelper()
+{
+ OSL_ENSURE( !isNew(), "OParseColumn::getInfoHelper: a *new* ParseColumn?" );
+ return *OParseColumn_PROP::getArrayHelper();
+}
+
+
+OOrderColumn::OOrderColumn( const Reference<XPropertySet>& _xColumn, const OUString& i_rOriginatingTableName,
+ bool _bCase, bool _bAscending )
+ : connectivity::sdbcx::OColumn(
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))),
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))),
+ false,
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))),
+ _bCase,
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))),
+ i_rOriginatingTableName
+ )
+ ,m_bAscending(_bAscending)
+{
+ construct();
+}
+
+
+OOrderColumn::OOrderColumn( const Reference<XPropertySet>& _xColumn, bool _bCase, bool _bAscending )
+ : connectivity::sdbcx::OColumn(
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))),
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))),
+ false,
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))),
+ _bCase,
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)))
+ )
+ ,m_bAscending(_bAscending)
+{
+ construct();
+}
+
+
+OOrderColumn::~OOrderColumn()
+{
+}
+
+
+void OOrderColumn::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING,
+ PropertyAttribute::READONLY, const_cast< bool* >( &m_bAscending ), cppu::UnoType<decltype(m_bAscending)>::get() );
+}
+
+::cppu::IPropertyArrayHelper* OOrderColumn::createArrayHelper() const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL OOrderColumn::getInfoHelper()
+{
+ OSL_ENSURE( !isNew(), "OOrderColumn::getInfoHelper: a *new* OrderColumn?" );
+ return *OOrderColumn_PROP::getArrayHelper();
+}
+
+css::uno::Sequence< OUString > SAL_CALL OOrderColumn::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.OrderColumn" };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/internalnode.cxx b/connectivity/source/parse/internalnode.cxx
new file mode 100644
index 000000000..1906ad3d4
--- /dev/null
+++ b/connectivity/source/parse/internalnode.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/internalnode.hxx>
+
+using namespace connectivity;
+
+
+OSQLInternalNode::OSQLInternalNode(const char* pNewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ : OSQLParseNode(pNewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::OSQLInternalNode(std::string_view NewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ :OSQLParseNode(NewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::OSQLInternalNode(const OUString &NewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ :OSQLParseNode(NewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::~OSQLInternalNode()
+{
+ // remove the node from the garbage list
+
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->erase(this);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/sqlbison.y b/connectivity/source/parse/sqlbison.y
new file mode 100644
index 000000000..e0e9969ab
--- /dev/null
+++ b/connectivity/source/parse/sqlbison.y
@@ -0,0 +1,4835 @@
+%glr-parser
+%token-table
+%{
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vector>
+#include <string.h>
+
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqlbison_exports.hxx>
+#include <connectivity/sqlscan.hxx>
+#include <connectivity/internalnode.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/i18n/KParseType.hpp>
+#include <com/sun/star/i18n/KParseTokens.hpp>
+
+#include <osl/diagnose.h>
+#include "connectivity/dbconversion.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <sal/macros.h>
+#include <sal/log.hxx>
+
+#if defined _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to alignment specifier
+#pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels
+#pragma warning(disable: 4702) // unreachable code
+#endif
+
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wwrite-strings"
+# pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+inline connectivity::OSQLInternalNode* newNode(const char* pNewValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+inline connectivity::OSQLInternalNode* newNode(const OString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+inline connectivity::OSQLInternalNode* newNode(const OUString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+
+// yyi is the internal number of the rule that is currently being reduced
+// This can be mapped to external rule number via the yyrmap.
+#if defined YYBISON && YYBISON >= 30800
+#define SQL_NEW_RULE newNode("", SQLNodeType::Rule, yyr1[yyrule])
+#define SQL_NEW_LISTRULE newNode("", SQLNodeType::ListRule, yyr1[yyrule])
+#define SQL_NEW_COMMALISTRULE newNode("", SQLNodeType::CommaListRule, yyr1[yyrule])
+#else
+#define SQL_NEW_RULE newNode("", SQLNodeType::Rule, yyr1[yyn])
+#define SQL_NEW_LISTRULE newNode("", SQLNodeType::ListRule, yyr1[yyn])
+#define SQL_NEW_COMMALISTRULE newNode("", SQLNodeType::CommaListRule, yyr1[yyn])
+#endif
+
+
+extern connectivity::OSQLParser* xxx_pGLOBAL_SQLPARSER;
+
+#define YYERROR_VERBOSE
+
+#define SQLyyerror(s) \
+{ \
+ xxx_pGLOBAL_SQLPARSER->error(s); \
+}
+
+using namespace connectivity;
+#define SQLyylex xxx_pGLOBAL_SQLPARSER->SQLlex
+%}
+ /* symbolic tokens */
+
+%union {
+ connectivity::OSQLParseNode * pParseNode;
+}
+%type <pParseNode> '(' ')' ',' ':' ';' '?' '[' ']' '{' '}' '.' 'K' 'M' 'G' 'T' 'P'
+
+%token <pParseNode> SQL_TOKEN_STRING SQL_TOKEN_ACCESS_DATE SQL_TOKEN_INT SQL_TOKEN_REAL_NUM
+%token <pParseNode> SQL_TOKEN_INTNUM SQL_TOKEN_APPROXNUM SQL_TOKEN_NOT SQL_TOKEN_NAME
+
+
+%nonassoc <pParseNode> SQL_TOKEN_UMINUS
+
+
+
+ /* literal keyword tokens */
+
+%token <pParseNode> SQL_TOKEN_ALL SQL_TOKEN_ALTER SQL_TOKEN_AMMSC SQL_TOKEN_ANY SQL_TOKEN_AS SQL_TOKEN_ASC SQL_TOKEN_AT SQL_TOKEN_AUTHORIZATION SQL_TOKEN_AVG
+
+%token <pParseNode> SQL_TOKEN_BETWEEN SQL_TOKEN_BIT SQL_TOKEN_BOTH SQL_TOKEN_BY
+
+%token <pParseNode> SQL_TOKEN_CAST SQL_TOKEN_CHARACTER SQL_TOKEN_CHECK SQL_TOKEN_COLLATE SQL_TOKEN_COMMIT SQL_TOKEN_CONTINUE SQL_TOKEN_CONVERT SQL_TOKEN_COUNT SQL_TOKEN_CREATE SQL_TOKEN_CROSS
+%token <pParseNode> SQL_TOKEN_CURRENT SQL_TOKEN_CURSOR
+
+%token <pParseNode> SQL_TOKEN_DATE SQL_TOKEN_DATEVALUE SQL_TOKEN_DAY SQL_TOKEN_DEC SQL_TOKEN_DECIMAL SQL_TOKEN_DECLARE SQL_TOKEN_DEFAULT SQL_TOKEN_DELETE SQL_TOKEN_DESC
+%token <pParseNode> SQL_TOKEN_DISTINCT SQL_TOKEN_DOUBLE SQL_TOKEN_DROP
+
+%token <pParseNode> SQL_TOKEN_ESCAPE SQL_TOKEN_EXCEPT SQL_TOKEN_EXISTS SQL_TOKEN_FALSE SQL_TOKEN_FETCH SQL_TOKEN_FLOAT SQL_TOKEN_FOR SQL_TOKEN_FOREIGN SQL_TOKEN_FOUND SQL_TOKEN_FROM SQL_TOKEN_FULL
+
+%token <pParseNode> SQL_TOKEN_GRANT SQL_TOKEN_GROUP SQL_TOKEN_HAVING SQL_TOKEN_IN SQL_TOKEN_INDICATOR SQL_TOKEN_INNER SQL_TOKEN_INTEGER SQL_TOKEN_INTO SQL_TOKEN_IS SQL_TOKEN_INTERSECT
+
+%left <pParseNode> SQL_TOKEN_JOIN
+%token <pParseNode> SQL_TOKEN_KEY SQL_TOKEN_LEADING SQL_TOKEN_LIKE SQL_TOKEN_LOCAL SQL_TOKEN_LOWER
+%token <pParseNode> SQL_TOKEN_MAX SQL_TOKEN_MIN SQL_TOKEN_NATURAL SQL_TOKEN_NCHAR SQL_TOKEN_NULL SQL_TOKEN_NUMERIC
+
+%token <pParseNode> SQL_TOKEN_OCTET_LENGTH SQL_TOKEN_OF SQL_TOKEN_ON SQL_TOKEN_OPTION SQL_TOKEN_ORDER SQL_TOKEN_OUTER
+
+%token <pParseNode> SQL_TOKEN_PRECISION SQL_TOKEN_PRIMARY SQL_TOKEN_PRIVILEGES SQL_TOKEN_PROCEDURE SQL_TOKEN_PUBLIC
+%token <pParseNode> SQL_TOKEN_REAL SQL_TOKEN_REFERENCES SQL_TOKEN_ROLLBACK
+
+%token <pParseNode> SQL_TOKEN_SCHEMA SQL_TOKEN_SELECT SQL_TOKEN_SET SQL_TOKEN_SIZE SQL_TOKEN_SMALLINT SQL_TOKEN_SOME SQL_TOKEN_SQLCODE SQL_TOKEN_SQLERROR SQL_TOKEN_SUM
+
+%token <pParseNode> SQL_TOKEN_TABLE SQL_TOKEN_TIME SQL_TOKEN_TIMESTAMP SQL_TOKEN_TIMEZONE_HOUR SQL_TOKEN_TIMEZONE_MINUTE SQL_TOKEN_TO SQL_TOKEN_TRAILING SQL_TOKEN_TRANSLATE SQL_TOKEN_TRIM SQL_TOKEN_TRUE SQL_TOKEN_UNION
+%token <pParseNode> SQL_TOKEN_UNIQUE SQL_TOKEN_UNKNOWN SQL_TOKEN_UPDATE SQL_TOKEN_UPPER SQL_TOKEN_USAGE SQL_TOKEN_USER SQL_TOKEN_USING SQL_TOKEN_VALUES SQL_TOKEN_VIEW
+%token <pParseNode> SQL_TOKEN_WHERE SQL_TOKEN_WITH SQL_TOKEN_WORK SQL_TOKEN_ZONE
+
+/* ODBC KEYWORDS */
+%token <pParseNode> SQL_TOKEN_CALL SQL_TOKEN_D SQL_TOKEN_FN SQL_TOKEN_T SQL_TOKEN_TS SQL_TOKEN_OJ
+/* string functions */
+%token <pParseNode> SQL_TOKEN_ASCII SQL_TOKEN_BIT_LENGTH SQL_TOKEN_CHAR SQL_TOKEN_CHAR_LENGTH SQL_TOKEN_SQL_TOKEN_INTNUM
+%token <pParseNode> SQL_TOKEN_CONCAT
+%token <pParseNode> SQL_TOKEN_DIFFERENCE SQL_TOKEN_INSERT SQL_TOKEN_LCASE SQL_TOKEN_LEFT SQL_TOKEN_LENGTH SQL_TOKEN_LOCATE
+%token <pParseNode> SQL_TOKEN_LOCATE_2 SQL_TOKEN_LTRIM SQL_TOKEN_POSITION SQL_TOKEN_REPEAT SQL_TOKEN_REPLACE
+%token <pParseNode> SQL_TOKEN_RIGHT SQL_TOKEN_RTRIM SQL_TOKEN_SOUNDEX SQL_TOKEN_SPACE SQL_TOKEN_SUBSTRING SQL_TOKEN_UCASE
+
+/* time and date functions */
+%token <pParseNode> SQL_TOKEN_CURRENT_DATE SQL_TOKEN_CURRENT_TIME SQL_TOKEN_CURRENT_TIMESTAMP SQL_TOKEN_CURDATE SQL_TOKEN_CURTIME
+%token <pParseNode> SQL_TOKEN_DAYNAME SQL_TOKEN_DAYOFMONTH SQL_TOKEN_DAYOFWEEK SQL_TOKEN_DAYOFYEAR SQL_TOKEN_EXTRACT
+%token <pParseNode> SQL_TOKEN_HOUR SQL_TOKEN_MILLISECOND SQL_TOKEN_MINUTE SQL_TOKEN_MONTH SQL_TOKEN_MONTHNAME SQL_TOKEN_NOW SQL_TOKEN_QUARTER SQL_TOKEN_DATEDIFF
+%token <pParseNode> SQL_TOKEN_SECOND SQL_TOKEN_TIMESTAMPADD SQL_TOKEN_TIMESTAMPDIFF SQL_TOKEN_TIMEVALUE SQL_TOKEN_WEEK SQL_TOKEN_WEEKDAY SQL_TOKEN_YEAR SQL_TOKEN_YEARDAY
+
+/* numeric functions */
+%token <pParseNode> SQL_TOKEN_ABS SQL_TOKEN_ACOS SQL_TOKEN_ASIN SQL_TOKEN_ATAN SQL_TOKEN_ATAN2 SQL_TOKEN_CEILING
+%token <pParseNode> SQL_TOKEN_COS SQL_TOKEN_COT SQL_TOKEN_DEGREES SQL_TOKEN_EXP SQL_TOKEN_FLOOR SQL_TOKEN_LOGF SQL_TOKEN_LOG SQL_TOKEN_LN
+%token <pParseNode> SQL_TOKEN_LOG10 SQL_TOKEN_MOD SQL_TOKEN_PI SQL_TOKEN_POWER SQL_TOKEN_RADIANS SQL_TOKEN_RAND SQL_TOKEN_ROUNDMAGIC
+%token <pParseNode> SQL_TOKEN_ROUND SQL_TOKEN_SIGN SQL_TOKEN_SIN SQL_TOKEN_SQRT SQL_TOKEN_TAN SQL_TOKEN_TRUNCATE
+
+// computational operation
+%token <pParseNode> SQL_TOKEN_EVERY SQL_TOKEN_INTERSECTION SQL_TOKEN_FUSION SQL_TOKEN_COLLECT SQL_TOKEN_VAR_POP SQL_TOKEN_VAR_SAMP
+%token <pParseNode> SQL_TOKEN_STDDEV_SAMP SQL_TOKEN_STDDEV_POP
+
+%token <pParseNode> SQL_TOKEN_RANK SQL_TOKEN_DENSE_RANK SQL_TOKEN_PERCENT_RANK SQL_TOKEN_CUME_DIST SQL_TOKEN_PERCENTILE_CONT SQL_TOKEN_PERCENTILE_DISC SQL_TOKEN_WITHIN SQL_TOKEN_ARRAY_AGG
+%token <pParseNode> SQL_TOKEN_CASE SQL_TOKEN_THEN SQL_TOKEN_END SQL_TOKEN_NULLIF SQL_TOKEN_COALESCE SQL_TOKEN_WHEN SQL_TOKEN_ELSE
+%token <pParseNode> SQL_TOKEN_BEFORE SQL_TOKEN_AFTER SQL_TOKEN_INSTEAD SQL_TOKEN_EACH SQL_TOKEN_REFERENCING SQL_TOKEN_BEGIN SQL_TOKEN_ATOMIC SQL_TOKEN_TRIGGER SQL_TOKEN_ROW SQL_TOKEN_STATEMENT
+%token <pParseNode> SQL_TOKEN_NEW SQL_TOKEN_OLD
+%token <pParseNode> SQL_TOKEN_VALUE SQL_TOKEN_CURRENT_CATALOG SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP SQL_TOKEN_CURRENT_PATH SQL_TOKEN_CURRENT_ROLE SQL_TOKEN_CURRENT_SCHEMA SQL_TOKEN_CURRENT_USER
+%token <pParseNode> SQL_TOKEN_SESSION_USER SQL_TOKEN_SYSTEM_USER SQL_TOKEN_VARCHAR SQL_TOKEN_VARBINARY SQL_TOKEN_VARYING SQL_TOKEN_OBJECT SQL_TOKEN_NCLOB SQL_TOKEN_NATIONAL
+%token <pParseNode> SQL_TOKEN_LARGE SQL_TOKEN_CLOB SQL_TOKEN_BLOB SQL_TOKEN_BIGINT SQL_TOKEN_BINARY SQL_TOKEN_WITHOUT SQL_TOKEN_BOOLEAN SQL_TOKEN_INTERVAL
+// window function
+%token <pParseNode> SQL_TOKEN_OVER SQL_TOKEN_ROW_NUMBER SQL_TOKEN_NTILE SQL_TOKEN_LEAD SQL_TOKEN_LAG SQL_TOKEN_RESPECT SQL_TOKEN_IGNORE SQL_TOKEN_NULLS
+%token <pParseNode> SQL_TOKEN_FIRST_VALUE SQL_TOKEN_LAST_VALUE SQL_TOKEN_NTH_VALUE SQL_TOKEN_FIRST SQL_TOKEN_LAST
+%token <pParseNode> SQL_TOKEN_EXCLUDE SQL_TOKEN_OTHERS SQL_TOKEN_TIES SQL_TOKEN_FOLLOWING SQL_TOKEN_UNBOUNDED SQL_TOKEN_PRECEDING SQL_TOKEN_RANGE SQL_TOKEN_ROWS
+%token <pParseNode> SQL_TOKEN_PARTITION SQL_TOKEN_WINDOW SQL_TOKEN_NO
+// LIMIT and OFFSEt
+%token <pParseNode> SQL_TOKEN_LIMIT SQL_TOKEN_OFFSET SQL_TOKEN_NEXT SQL_TOKEN_ONLY
+
+ /* operators */
+%left SQL_TOKEN_NAME
+%left <pParseNode> SQL_TOKEN_OR
+%left <pParseNode> SQL_TOKEN_AND
+
+%left <pParseNode> SQL_LESSEQ SQL_GREATEQ SQL_NOTEQUAL SQL_LESS SQL_GREAT SQL_EQUAL /* '<' '>' = <> < > <= >= != */
+%left <pParseNode> '+' '-' SQL_CONCAT
+%left <pParseNode> '*' '/'
+%left SQL_TOKEN_NATURAL SQL_TOKEN_CROSS SQL_TOKEN_FULL SQL_TOKEN_LEFT SQL_TOKEN_RIGHT
+%left ')'
+%right '='
+%right '.'
+%right '('
+
+
+%token <pParseNode> SQL_TOKEN_INVALIDSYMBOL
+
+/*%type <pParseNode> sql_single_statement */
+
+%type <pParseNode> sql /*schema */
+%type <pParseNode> column_def_opt_list column_def_opt table_constraint_def column_commalist
+%type <pParseNode> view_def opt_with_check_option opt_column_commalist privilege_def
+%type <pParseNode> opt_with_grant_option privileges operation_commalist operation
+%type <pParseNode> grantee_commalist grantee opt_order_by_clause ordering_spec_commalist
+%type <pParseNode> ordering_spec opt_asc_desc manipulative_statement commit_statement
+%type <pParseNode> /*delete_statement_positioned*/ delete_statement_searched fetch_statement
+%type <pParseNode> insert_statement values_or_query_spec
+%type <pParseNode> rollback_statement select_statement_into opt_all_distinct
+%type <pParseNode> /*update_statement_positioned*/ assignment_commalist assignment
+%type <pParseNode> update_statement_searched target_commalist target opt_where_clause
+%type <pParseNode> select_statement selection table_exp from_clause table_ref_commalist table_ref
+%type <pParseNode> where_clause opt_group_by_clause column_ref_commalist opt_having_clause
+%type <pParseNode> search_condition predicate comparison_predicate comparison_predicate_part_2 between_predicate between_predicate_part_2
+%type <pParseNode> like_predicate opt_escape test_for_null null_predicate_part_2 in_predicate in_predicate_part_2 character_like_predicate_part_2 other_like_predicate_part_2
+%type <pParseNode> all_or_any_predicate any_all_some existence_test subquery quantified_comparison_predicate_part_2
+%type <pParseNode> scalar_exp_commalist parameter_ref literal parenthesized_boolean_value_expression
+%type <pParseNode> column_ref data_type column cursor parameter range_variable user /*like_check*/
+/* new rules at OJ */
+%type <pParseNode> derived_column as_clause table_name num_primary term num_value_exp
+%type <pParseNode> value_exp_primary num_value_fct unsigned_value_spec cast_spec set_fct_spec scalar_subquery
+%type <pParseNode> position_exp extract_exp length_exp general_value_spec
+%type <pParseNode> general_set_fct set_fct_type query_exp non_join_query_exp joined_table
+%type <pParseNode> non_join_query_term non_join_query_primary simple_table
+%type <pParseNode> table_value_const_list row_value_constructor /*row_value_const_list*/ row_value_constructor_elem
+%type <pParseNode> qualified_join value_exp query_term join_type outer_join_type join_condition boolean_term
+%type <pParseNode> boolean_factor boolean_primary named_columns_join join_spec
+%type <pParseNode> cast_operand cast_target factor datetime_value_exp /*interval_value_exp*/ datetime_term datetime_factor
+%type <pParseNode> datetime_primary datetime_value_fct time_zone time_zone_specifier /*interval_term*/ interval_qualifier
+%type <pParseNode> start_field non_second_datetime_field end_field single_datetime_field extract_field datetime_field time_zone_field
+%type <pParseNode> char_length_exp octet_length_exp bit_length_exp select_sublist string_value_exp
+%type <pParseNode> char_value_exp concatenation char_factor char_primary string_value_fct char_substring_fct fold
+%type <pParseNode> form_conversion char_translation trim_fct trim_operands trim_spec bit_value_fct bit_substring_fct op_column_commalist
+%type <pParseNode> /*bit_concatenation*/ bit_value_exp bit_factor bit_primary collate_clause char_value_fct unique_spec value_exp_commalist in_predicate_value unique_test update_source
+%type <pParseNode> function_arg_commalist3 string_function_3Argument function_arg_commalist4 string_function_4Argument function_arg_commalist2 string_function_1Argument string_function_2Argument
+%type <pParseNode> date_function_0Argument date_function_1Argument function_name12 function_name23 function_name1 function_name2 function_name3 function_name0 numeric_function_0Argument numeric_function_1Argument numeric_function_2Argument
+%type <pParseNode> all query_primary sql_not for_length upper_lower comparison column_val cross_union /*opt_schema_element_list*/
+%type <pParseNode> /*op_authorization op_schema*/ nil_fkt schema_element base_table_def base_table_element base_table_element_commalist
+%type <pParseNode> column_def odbc_fct_spec odbc_call_spec odbc_fct_type op_parameter union_statement
+%type <pParseNode> op_odbc_call_parameter odbc_parameter_commalist odbc_parameter function_args_commalist function_arg
+%type <pParseNode> catalog_name schema_name table_node numeric_function string_function function_name date_function table_primary_as_range_column opt_as
+%type <pParseNode> ordered_set_function inverse_distribution_function hypothetical_set_function hypothetical_set_function_value_expression_list rank_function_type within_group_specification inverse_distribution_function_type array_aggregate_function inverse_distribution_function_argument
+%type <pParseNode> case_expression else_clause result_expression result case_abbreviation case_specification searched_when_clause simple_when_clause searched_case simple_case
+%type <pParseNode> when_operand_list when_operand case_operand
+%type <pParseNode> trigger_definition trigger_name trigger_action_time trigger_event transition_table_or_variable_list triggered_action trigger_column_list triggered_when_clause triggered_SQL_statement SQL_procedure_statement old_transition_variable_name new_transition_variable_name
+%type <pParseNode> op_referencing op_trigger_columnlist op_triggered_action_for opt_row trigger_for SQL_procedure_statement_list transition_table_or_variable old_transition_table_name new_transition_table_name transition_table_name
+%type <pParseNode> searched_when_clause_list simple_when_clause_list predefined_type opt_char_set_spec opt_collate_clause character_string_type national_character_string_type
+%type <pParseNode> binary_string_type numeric_type boolean_type datetime_type interval_type opt_paren_precision paren_char_length opt_paren_char_large_length paren_character_large_object_length
+%type <pParseNode> large_object_length opt_multiplier character_large_object_type national_character_large_object_type binary_large_object_string_type opt_with_or_without_time_zone
+%type <pParseNode> approximate_numeric_type exact_numeric_type opt_paren_precision_scale
+/* window function rules */
+%type <pParseNode> window_function window_function_type ntile_function number_of_tiles lead_or_lag_function lead_or_lag lead_or_lag_extent offset default_expression null_treatment
+%type <pParseNode> first_or_last_value_function first_or_last_value nth_value_function nth_row from_first_or_last window_name_or_specification in_line_window_specification opt_lead_or_lag_function
+%type <pParseNode> opt_null_treatment opt_from_first_or_last simple_value_specification dynamic_parameter_specification window_name window_clause window_definition_list window_definition
+%type <pParseNode> new_window_name existing_window_name window_partition_clause window_partition_column_reference_list window_partition_column_reference window_frame_clause
+%type <pParseNode> window_frame_units window_frame_extent window_frame_start window_frame_preceding window_frame_between window_frame_bound_1 window_frame_bound_2 window_frame_bound window_frame_following window_frame_exclusion
+%type <pParseNode> opt_window_frame_clause opt_window_partition_clause opt_existing_window_name window_specification opt_window_frame_exclusion opt_window_clause opt_offset
+%type <pParseNode> opt_fetch_first_row_count fetch_first_clause offset_row_count fetch_first_row_count first_or_next row_or_rows opt_result_offset_clause result_offset_clause
+/* LIMIT and OFFSET */
+%type <pParseNode> opt_limit_offset_clause limit_offset_clause opt_fetch_first_clause
+%%
+
+/* Return Parse Tree to OSQLParser
+ * (the access over yyval after calling the parser fails,
+ *
+ */
+sql_single_statement:
+ sql
+ { xxx_pGLOBAL_SQLPARSER->setParseTree( $1 ); }
+ | sql ';'
+ { xxx_pGLOBAL_SQLPARSER->setParseTree( $1 ); }
+ ;
+
+ /* schema definition language */
+ /* Note: other ``sql:sal_Unicode() rules appear later in the grammar */
+
+sql:
+ manipulative_statement
+ | schema_element
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+
+/***
+
+op_authorization:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AUTHORIZATION user
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+op_schema:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_NAME
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+
+schema:
+ SQL_TOKEN_CREATE SQL_TOKEN_SCHEMA op_schema op_authorization opt_schema_element_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+
+opt_schema_element_list:
+ {$$ = SQL_NEW_RULE;}
+ | schema_glement_list
+ ;
+
+schema_element_list:
+ schema_element
+ {$$ = SQL_NEW_LISTRULE;
+ $$->append($1);}
+ | schema_element_list schema_element
+ {$1->append($2);
+ $$ = $1;}
+ ;
+*/
+
+schema_element:
+ base_table_def
+ | view_def
+ | privilege_def
+ | trigger_definition
+ ;
+
+base_table_def:
+ SQL_TOKEN_CREATE SQL_TOKEN_TABLE table_node '(' base_table_element_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+base_table_element_commalist:
+ base_table_element
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | base_table_element_commalist ',' base_table_element
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+base_table_element:
+ column_def
+ | table_constraint_def
+ ;
+
+column_def:
+ column data_type column_def_opt_list
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+
+column_def_opt_list:
+ /* empty */ {$$ = SQL_NEW_LISTRULE;}
+ | column_def_opt_list column_def_opt
+ {$1->append($2);
+ $$ = $1;}
+ ;
+
+nil_fkt:
+ datetime_value_fct
+ ;
+unique_spec:
+ SQL_TOKEN_UNIQUE
+ | SQL_TOKEN_PRIMARY SQL_TOKEN_KEY
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+column_def_opt:
+ SQL_TOKEN_NOT SQL_TOKEN_NULL
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | unique_spec
+ | SQL_TOKEN_DEFAULT literal
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT SQL_TOKEN_NULL
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT SQL_TOKEN_USER
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT nil_fkt
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHECK
+ | SQL_TOKEN_CHECK '(' search_condition ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_REFERENCES table_node
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_REFERENCES table_node '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+table_constraint_def:
+ unique_spec '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_FOREIGN SQL_TOKEN_KEY '(' column_commalist ')' SQL_TOKEN_REFERENCES table_node
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ $$->append($7);}
+ | SQL_TOKEN_FOREIGN SQL_TOKEN_KEY '(' column_commalist ')' SQL_TOKEN_REFERENCES table_node '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ $$->append($7);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($9);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_CHECK '(' search_condition ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+op_column_commalist:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+column_commalist:
+ column_commalist ',' column
+ {$1->append($3);
+ $$ = $1;}
+ | column
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+
+view_def:
+ SQL_TOKEN_CREATE SQL_TOKEN_VIEW table_node opt_column_commalist SQL_TOKEN_AS select_statement opt_with_check_option
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+
+opt_with_check_option:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_CHECK SQL_TOKEN_OPTION
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+opt_column_commalist:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+privilege_def:
+ SQL_TOKEN_GRANT privileges SQL_TOKEN_ON table_node SQL_TOKEN_TO grantee_commalist
+ opt_with_grant_option
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+
+opt_with_grant_option:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_GRANT SQL_TOKEN_OPTION
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+privileges:
+ SQL_TOKEN_ALL SQL_TOKEN_PRIVILEGES
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | operation_commalist
+ ;
+
+operation_commalist:
+ operation
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | operation_commalist ',' operation
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+operation:
+ SQL_TOKEN_SELECT
+ | SQL_TOKEN_INSERT opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DELETE
+ | SQL_TOKEN_UPDATE opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_REFERENCES opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_USAGE
+ ;
+
+
+grantee_commalist:
+ grantee
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | grantee_commalist ',' grantee
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+grantee:
+ SQL_TOKEN_PUBLIC
+ | user
+ ;
+
+ /* module language */
+
+opt_order_by_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ORDER SQL_TOKEN_BY ordering_spec_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+ordering_spec_commalist:
+ ordering_spec
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | ordering_spec_commalist ',' ordering_spec
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+ordering_spec:
+/* SQL_TOKEN_INTNUM opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+*/
+ predicate opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+
+ | row_value_constructor_elem opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+opt_asc_desc:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ASC
+ | SQL_TOKEN_DESC
+ ;
+
+
+/***
+manipulative_statement_list:
+ manipulative_statement
+ {$$ = SQL_NEW_LISTRULE;
+ $$->append($1);}
+ | manipulative_statement_list manipulative_statement
+ {$1->append($2);
+ $$ = $1;}
+ ;
+***/
+
+sql_not:
+/* vide */
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_NOT
+ ;
+
+/* manipulative statements */
+
+manipulative_statement:
+ commit_statement
+/* | delete_statement_positioned*/
+ | delete_statement_searched
+ | fetch_statement
+ | insert_statement
+ | rollback_statement
+ | select_statement_into
+/* | update_statement_positioned*/
+ | update_statement_searched
+ | union_statement
+ | '{' odbc_call_spec '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ ;
+
+union_statement:
+ select_statement
+ | union_statement SQL_TOKEN_UNION all select_statement
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+commit_statement:
+ SQL_TOKEN_COMMIT SQL_TOKEN_WORK
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+/*
+delete_statement_positioned:
+ SQL_TOKEN_DELETE SQL_TOKEN_FROM table_node SQL_TOKEN_WHERE SQL_TOKEN_CURRENT SQL_TOKEN_OF cursor
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+*/
+delete_statement_searched:
+ SQL_TOKEN_DELETE SQL_TOKEN_FROM table_node opt_where_clause
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);}
+ ;
+
+fetch_statement:
+ SQL_TOKEN_FETCH cursor SQL_TOKEN_INTO target_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);}
+ ;
+
+insert_statement:
+ SQL_TOKEN_INSERT SQL_TOKEN_INTO table_node opt_column_commalist query_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);}
+ ;
+values_or_query_spec:
+ SQL_TOKEN_VALUES '(' table_value_const_list ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+table_value_const_list:
+ row_value_constructor
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | table_value_const_list ',' row_value_constructor
+ {$1->append($3);
+ $$ = $1;}
+ ;
+/*
+row_value_const_list:
+ row_value_constructor_elem
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | row_value_const_list ',' row_value_constructor_elem
+ {$1->append($3);
+ $$ = $1;}
+ ;
+*/
+row_value_constructor:
+ row_value_constructor_elem
+/* | '(' row_value_const_list ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ */
+ ;
+row_value_constructor_elem:
+ value_exp /*[^')']*/
+ | SQL_TOKEN_DEFAULT
+ ;
+
+
+rollback_statement:
+ SQL_TOKEN_ROLLBACK SQL_TOKEN_WORK
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+
+ /* INTO target_commalist herausgenommen */
+select_statement_into:
+ SQL_TOKEN_SELECT opt_all_distinct selection SQL_TOKEN_INTO target_commalist table_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6); }
+ ;
+
+opt_all_distinct:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ALL
+ | SQL_TOKEN_DISTINCT
+
+ ;
+/*
+update_statement_positioned:
+ SQL_TOKEN_UPDATE table_node SQL_TOKEN_SET assignment_commalist
+ SQL_TOKEN_WHERE SQL_TOKEN_CURRENT SQL_TOKEN_OF cursor
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);}
+ ;
+*/
+assignment_commalist:
+ assignment
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | assignment_commalist ',' assignment
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+assignment:
+ column SQL_EQUAL update_source
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+update_source:
+ value_exp
+ | SQL_TOKEN_DEFAULT
+ ;
+update_statement_searched:
+ SQL_TOKEN_UPDATE table_node SQL_TOKEN_SET assignment_commalist opt_where_clause
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);}
+ ;
+
+target_commalist:
+ target
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | target_commalist ',' target
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+target:
+ parameter_ref
+ ;
+
+opt_where_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | where_clause
+ ;
+
+ /* query expressions */
+
+query_term:
+ non_join_query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/* SELECT STATEMENT */
+select_statement:
+ SQL_TOKEN_SELECT opt_all_distinct selection table_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+selection:
+ '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+ | scalar_exp_commalist
+ ;
+opt_result_offset_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | result_offset_clause
+ ;
+result_offset_clause:
+ SQL_TOKEN_OFFSET offset_row_count row_or_rows
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_fetch_first_row_count:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | fetch_first_row_count
+ ;
+first_or_next:
+ SQL_TOKEN_FIRST
+ | SQL_TOKEN_NEXT
+ ;
+row_or_rows:
+ SQL_TOKEN_ROW
+ | SQL_TOKEN_ROWS
+ ;
+opt_fetch_first_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | fetch_first_clause
+ ;
+fetch_first_clause:
+ SQL_TOKEN_FETCH first_or_next opt_fetch_first_row_count row_or_rows SQL_TOKEN_ONLY
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+offset_row_count:
+ literal
+ ;
+fetch_first_row_count:
+ literal
+ ;
+
+opt_limit_offset_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | limit_offset_clause
+ ;
+opt_offset:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_OFFSET SQL_TOKEN_INTNUM
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+limit_offset_clause:
+ SQL_TOKEN_LIMIT SQL_TOKEN_INTNUM opt_offset
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+table_exp:
+ from_clause opt_where_clause opt_group_by_clause opt_having_clause opt_window_clause opt_order_by_clause opt_limit_offset_clause opt_result_offset_clause opt_fetch_first_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);
+ $$->append($9);
+ }
+ ;
+
+from_clause:
+ SQL_TOKEN_FROM table_ref_commalist
+ { $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2); }
+ ;
+
+table_ref_commalist:
+
+ table_ref
+ { $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1); }
+ | table_ref_commalist ',' table_ref
+ { $1->append($3);
+ $$ = $1; }
+ ;
+
+opt_as:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AS
+ ;
+opt_row:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ROW
+ ;
+table_primary_as_range_column:
+ {$$ = SQL_NEW_RULE;}
+ | opt_as SQL_TOKEN_NAME op_column_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+table_ref:
+ table_node table_primary_as_range_column
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | subquery range_variable op_column_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | joined_table
+ | '{' SQL_TOKEN_OJ joined_table '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ | '(' joined_table ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+where_clause:
+ SQL_TOKEN_WHERE search_condition
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+opt_group_by_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_GROUP SQL_TOKEN_BY column_ref_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+column_ref_commalist:
+ column_ref
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | set_fct_spec
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | column_ref_commalist ',' column_ref
+ {$1->append($3);
+ $$ = $1;}
+ | column_ref_commalist ',' set_fct_spec
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+opt_having_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_HAVING search_condition
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+ /* search conditions */
+boolean_primary:
+ predicate
+ | '(' search_condition ')'
+ { // boolean_primary: rule 2
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | row_value_constructor_elem /*[^')' ',']*/
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck())// boolean_primary: rule 3
+ {
+ $$ = SQL_NEW_RULE;
+ sal_Int16 nErg = 0;
+ if ( SQL_ISTOKEN( $1, NULL))
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+ OSQLParseNode* pTFN = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::test_for_null));
+ pTFN->append(pColumnRef);
+
+ OSQLParseNode* pNPP2 = new OSQLInternalNode("", SQLNodeType::Rule, OSQLParser::RuleID(OSQLParseNode::null_predicate_part_2));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_IS));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Rule, OSQLParser::RuleID(OSQLParseNode::sql_not)));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_NULL));
+ pTFN->append(pNPP2);
+
+ $$->append(pTFN);
+
+ nErg = 1;
+ }
+ else
+ {
+ nErg = xxx_pGLOBAL_SQLPARSER->buildComparisonRule($$,$1);
+ }
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ delete pTemp;
+ }
+ else
+ {
+ delete $$;
+ if(nErg)
+ YYERROR;
+ else
+ YYABORT;
+ }
+ }
+ else
+ YYERROR;
+ }
+ ;
+parenthesized_boolean_value_expression:
+ '(' search_condition ')'
+ { // boolean_primary: rule 2
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+boolean_factor:
+ boolean_primary %dprec 2
+ | SQL_TOKEN_NOT boolean_primary %dprec 1
+ { // boolean_factor: rule 1
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+boolean_term:
+ boolean_factor
+ | boolean_term SQL_TOKEN_AND boolean_factor
+ {
+ $$ = SQL_NEW_RULE; // boolean_term: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+search_condition:
+ boolean_term
+ | search_condition SQL_TOKEN_OR boolean_term
+ {
+ $$ = SQL_NEW_RULE; // search_condition
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+predicate:
+ comparison_predicate %dprec 1
+ | between_predicate
+ | all_or_any_predicate
+ | existence_test
+ | unique_test
+ | test_for_null %dprec 2
+ | in_predicate
+ | like_predicate
+ ;
+comparison_predicate_part_2:
+ comparison row_value_constructor
+ {
+ $$ = SQL_NEW_RULE; // comparison_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+comparison_predicate:
+ row_value_constructor comparison row_value_constructor
+ {
+ $$ = SQL_NEW_RULE; // comparison_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | comparison row_value_constructor
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // comparison_predicate: rule 2
+ {
+ $$ = SQL_NEW_RULE;
+ sal_Int16 nErg = xxx_pGLOBAL_SQLPARSER->buildPredicateRule($$,$2,$1);
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ delete pTemp;
+ }
+ else
+ {
+ delete $$;
+ YYABORT;
+ }
+ }
+ else
+ {
+ YYERROR;
+ }
+ }
+ ;
+comparison:
+ SQL_LESS
+ | SQL_NOTEQUAL
+ | SQL_EQUAL
+ | SQL_GREAT
+ | SQL_LESSEQ
+ | SQL_GREATEQ
+ | SQL_TOKEN_IS sql_not SQL_TOKEN_DISTINCT SQL_TOKEN_FROM
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_IS sql_not
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+between_predicate_part_2:
+ sql_not SQL_TOKEN_BETWEEN row_value_constructor SQL_TOKEN_AND row_value_constructor
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // between_predicate: rule 2
+ {
+ $$ = SQL_NEW_RULE;
+
+ sal_Int16 nErg = xxx_pGLOBAL_SQLPARSER->buildPredicateRule($$,$3,$2,$5);
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ OSQLParseNode* pColumnRef = $$->removeAt((sal_uInt32)0);
+ $$->insert(0,$1);
+ OSQLParseNode* pBetween_predicate = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::between_predicate));
+ pBetween_predicate->append(pColumnRef);
+ pBetween_predicate->append($$);
+ $$ = pBetween_predicate;
+
+ delete pTemp;
+ delete $4;
+ }
+ else
+ {
+ delete $$;
+ YYABORT;
+ }
+ }
+ else
+ {
+ $$ = SQL_NEW_RULE; // between_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ }
+between_predicate:
+ row_value_constructor between_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // between_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | between_predicate_part_2
+ ;
+character_like_predicate_part_2:
+ sql_not SQL_TOKEN_LIKE string_value_exp opt_escape
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+other_like_predicate_part_2:
+ sql_not SQL_TOKEN_LIKE value_exp_primary opt_escape
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+like_predicate:
+ row_value_constructor character_like_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | row_value_constructor other_like_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 3
+ $$->append($1);
+ $$->append($2);
+ }
+ | character_like_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // like_predicate: rule 5
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ OSQLParseNode* p2nd = $1->removeAt(2);
+ OSQLParseNode* p3rd = $1->removeAt(2);
+ if ( !xxx_pGLOBAL_SQLPARSER->buildLikeRule($1,p2nd,p3rd) )
+ {
+ delete $$;
+ YYABORT;
+ }
+ $1->append(p3rd);
+ }
+ else
+ YYERROR;
+ }
+ | other_like_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // like_predicate: rule 6
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ OSQLParseNode* p2nd = $1->removeAt(2);
+ OSQLParseNode* p3rd = $1->removeAt(2);
+ if ( !xxx_pGLOBAL_SQLPARSER->buildLikeRule($1,p2nd,p3rd) )
+ {
+ delete $$;
+ YYABORT;
+ }
+ $1->append(p3rd);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+opt_escape:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ESCAPE string_value_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | '{' SQL_TOKEN_ESCAPE SQL_TOKEN_STRING '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ ;
+
+null_predicate_part_2:
+ SQL_TOKEN_IS sql_not SQL_TOKEN_NULL
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_IS sql_not SQL_TOKEN_UNKNOWN
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+test_for_null:
+ row_value_constructor null_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | null_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())// test_for_null: rule 2
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+in_predicate_value:
+ subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | '(' value_exp_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+in_predicate_part_2:
+ sql_not SQL_TOKEN_IN in_predicate_value
+ {
+ $$ = SQL_NEW_RULE;// in_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+in_predicate:
+ row_value_constructor in_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE;// in_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | in_predicate_part_2
+ {
+ if ( xxx_pGLOBAL_SQLPARSER->inPredicateCheck() )// in_predicate: rule 2
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+quantified_comparison_predicate_part_2:
+ comparison any_all_some subquery
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+all_or_any_predicate:
+ row_value_constructor quantified_comparison_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | quantified_comparison_predicate_part_2
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+any_all_some:
+ SQL_TOKEN_ANY
+ | SQL_TOKEN_ALL
+ | SQL_TOKEN_SOME
+ ;
+
+existence_test:
+ SQL_TOKEN_EXISTS subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+unique_test:
+ SQL_TOKEN_UNIQUE subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+subquery:
+ '(' query_exp ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+ /* scalar expressions */
+scalar_exp_commalist:
+ select_sublist
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ }
+ | scalar_exp_commalist ',' select_sublist
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+select_sublist:
+/* table_node '.' '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+*/
+ derived_column
+
+ ;
+
+parameter_ref:
+ parameter
+ ;
+
+/*
+op_like:
+ '*'
+ {
+ $$ = newNode("*", SQLNodeType::Punctuation);
+ }
+ | '?'
+ {
+ $$ = newNode("?", SQLNodeType::Punctuation);
+ }
+ | op_like '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ xxx_pGLOBAL_SQLPARSER->reduceLiteral($$, sal_False);
+ }
+ | op_like '?'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("?", SQLNodeType::Punctuation));
+ xxx_pGLOBAL_SQLPARSER->reduceLiteral($$, sal_False);
+ }
+ ;
+*/
+
+literal:
+/* SQL_TOKEN_STRING
+ | */SQL_TOKEN_INT
+ | SQL_TOKEN_REAL_NUM
+ | SQL_TOKEN_INTNUM
+ | SQL_TOKEN_APPROXNUM
+ | SQL_TOKEN_ACCESS_DATE
+/* rules for predicate check */
+ | literal SQL_TOKEN_STRING
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_INT
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_REAL_NUM
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_APPROXNUM
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+ /* miscellaneous */
+as_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AS column
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | column
+ ;
+position_exp:
+ SQL_TOKEN_POSITION '(' value_exp SQL_TOKEN_IN value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_POSITION '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+num_value_fct:
+ position_exp
+ | extract_exp
+ | length_exp
+ ;
+char_length_exp:
+ SQL_TOKEN_CHAR_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_SQL_TOKEN_INTNUM '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+
+ ;
+octet_length_exp:
+ SQL_TOKEN_OCTET_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+bit_length_exp:
+ SQL_TOKEN_BIT_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+length_exp:
+ char_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | octet_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | bit_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+datetime_field:
+ non_second_datetime_field
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_SECOND
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+extract_field:
+ time_zone_field
+ | datetime_field
+ | value_exp
+ ;
+time_zone_field:
+ SQL_TOKEN_TIMEZONE_HOUR
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_TIMEZONE_MINUTE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+extract_exp:
+ SQL_TOKEN_EXTRACT '(' extract_field SQL_TOKEN_FROM value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+unsigned_value_spec:
+ general_value_spec
+ | literal
+ ;
+general_value_spec:
+ parameter
+ | SQL_TOKEN_USER
+ | SQL_TOKEN_NULL
+ | SQL_TOKEN_FALSE
+ | SQL_TOKEN_TRUE
+ | SQL_TOKEN_VALUE
+ | SQL_TOKEN_CURRENT_CATALOG
+ | SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP
+ | SQL_TOKEN_CURRENT_PATH
+ | SQL_TOKEN_CURRENT_ROLE
+ | SQL_TOKEN_CURRENT_SCHEMA
+ | SQL_TOKEN_CURRENT_USER
+ | SQL_TOKEN_SESSION_USER
+ | SQL_TOKEN_SYSTEM_USER
+ ;
+set_fct_spec:
+ general_set_fct
+ | '{' odbc_fct_spec '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ | function_name '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name0 '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name1 '(' function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name2 '(' function_arg_commalist2 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name3 '(' function_arg_commalist3 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | string_function_4Argument '(' function_arg_commalist4 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name '(' function_args_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name12 '(' function_args_commalist ')'
+ {
+ if ( $3->count() == 1 || $3->count() == 2 )
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ else
+ YYERROR;
+ }
+ | function_name23 '(' function_args_commalist ')'
+ {
+ if ( $3->count() == 2 || $3->count() == 3)
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ else
+ YYERROR;
+ }
+ ;
+function_name0:
+ date_function_0Argument
+ | numeric_function_0Argument
+ ;
+function_name1:
+ string_function_1Argument
+ | date_function_1Argument
+ | numeric_function_1Argument
+ ;
+function_name2:
+ string_function_2Argument
+ | numeric_function_2Argument
+ ;
+function_name12:
+ SQL_TOKEN_ROUND
+ | SQL_TOKEN_WEEK
+ | SQL_TOKEN_LOGF
+ | SQL_TOKEN_LOG
+ ;
+function_name23:
+ SQL_TOKEN_LOCATE
+ | SQL_TOKEN_DATEDIFF
+ ;
+function_name3:
+ string_function_3Argument
+ ;
+function_name:
+ string_function
+ | date_function
+ | numeric_function
+ | SQL_TOKEN_NAME
+ ;
+string_function_1Argument:
+ SQL_TOKEN_LENGTH
+ | SQL_TOKEN_ASCII
+ | SQL_TOKEN_LCASE
+ | SQL_TOKEN_LTRIM
+ | SQL_TOKEN_RTRIM
+ | SQL_TOKEN_SPACE
+ | SQL_TOKEN_UCASE
+ ;
+
+string_function_2Argument:
+ SQL_TOKEN_REPEAT
+ | SQL_TOKEN_LEFT
+ | SQL_TOKEN_RIGHT
+ ;
+string_function_3Argument:
+ SQL_TOKEN_REPLACE
+ ;
+string_function_4Argument:
+ SQL_TOKEN_INSERT
+ ;
+
+string_function:
+ SQL_TOKEN_CHAR
+ | SQL_TOKEN_CONCAT
+ | SQL_TOKEN_DIFFERENCE
+ | SQL_TOKEN_LOCATE_2
+ | SQL_TOKEN_SOUNDEX
+ ;
+date_function_0Argument:
+ SQL_TOKEN_CURDATE
+ | SQL_TOKEN_CURTIME
+ | SQL_TOKEN_NOW
+ ;
+date_function_1Argument:
+ SQL_TOKEN_DAYOFWEEK
+ | SQL_TOKEN_DAYOFMONTH
+ | SQL_TOKEN_DAYOFYEAR
+ | SQL_TOKEN_MONTH
+ | SQL_TOKEN_DAYNAME
+ | SQL_TOKEN_MONTHNAME
+ | SQL_TOKEN_QUARTER
+ | SQL_TOKEN_HOUR
+ | SQL_TOKEN_MINUTE
+ | SQL_TOKEN_SECOND
+ | SQL_TOKEN_YEAR
+ | SQL_TOKEN_DAY
+ | SQL_TOKEN_TIMEVALUE
+ | SQL_TOKEN_DATEVALUE
+ ;
+
+date_function:
+ SQL_TOKEN_TIMESTAMPADD
+ | SQL_TOKEN_TIMESTAMPDIFF
+ ;
+numeric_function_0Argument:
+ SQL_TOKEN_PI
+ ;
+numeric_function_1Argument:
+ SQL_TOKEN_ABS
+ | SQL_TOKEN_ACOS
+ | SQL_TOKEN_ASIN
+ | SQL_TOKEN_ATAN
+ | SQL_TOKEN_CEILING
+ | SQL_TOKEN_COS
+ | SQL_TOKEN_COT
+ | SQL_TOKEN_DEGREES
+ | SQL_TOKEN_FLOOR
+ | SQL_TOKEN_SIGN
+ | SQL_TOKEN_SIN
+ | SQL_TOKEN_SQRT
+ | SQL_TOKEN_TAN
+ | SQL_TOKEN_EXP
+ | SQL_TOKEN_LOG10
+ | SQL_TOKEN_LN
+ | SQL_TOKEN_RADIANS
+ | SQL_TOKEN_ROUNDMAGIC
+ ;
+numeric_function_2Argument:
+ SQL_TOKEN_ATAN2
+ | SQL_TOKEN_MOD
+ | SQL_TOKEN_POWER
+ ;
+numeric_function:
+ SQL_TOKEN_RAND
+ | SQL_TOKEN_TRUNCATE
+ ;
+
+window_function:
+ window_function_type SQL_TOKEN_OVER window_name_or_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_function_type :
+ rank_function_type '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_ROW_NUMBER '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | general_set_fct
+ | ntile_function
+ | lead_or_lag_function
+ | first_or_last_value_function
+ | nth_value_function
+;
+ntile_function :
+ SQL_TOKEN_NTILE '(' number_of_tiles ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+dynamic_parameter_specification:
+ parameter
+ ;
+simple_value_specification:
+ literal
+ ;
+number_of_tiles :
+ simple_value_specification
+ | dynamic_parameter_specification
+ ;
+opt_lead_or_lag_function:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | ',' offset
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ | ',' offset ',' default_expression
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($4);
+ }
+ ;
+opt_null_treatment:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | null_treatment
+ ;
+
+lead_or_lag_function:
+ lead_or_lag '(' lead_or_lag_extent opt_lead_or_lag_function ')' opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ }
+ ;
+lead_or_lag:
+ SQL_TOKEN_LEAD
+ | SQL_TOKEN_LAG
+ ;
+lead_or_lag_extent:
+ value_exp
+ ;
+offset:
+ SQL_TOKEN_INTNUM
+ ;
+default_expression:
+ value_exp
+ ;
+null_treatment:
+ SQL_TOKEN_RESPECT SQL_TOKEN_NULLS
+ | SQL_TOKEN_IGNORE SQL_TOKEN_NULLS
+ ;
+first_or_last_value_function:
+ first_or_last_value '(' value_exp ')' opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ ;
+first_or_last_value :
+ SQL_TOKEN_FIRST_VALUE
+ | SQL_TOKEN_LAST_VALUE
+ ;
+opt_from_first_or_last:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | from_first_or_last
+ ;
+nth_value_function:
+ SQL_TOKEN_NTH_VALUE '(' value_exp ',' nth_row ')' opt_from_first_or_last opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($7);
+ $$->append($8);
+ }
+ ;
+nth_row:
+ simple_value_specification
+ | dynamic_parameter_specification
+ ;
+from_first_or_last:
+ SQL_TOKEN_FROM SQL_TOKEN_FIRST
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_FROM SQL_TOKEN_LAST
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_name:
+ SQL_TOKEN_NAME
+ ;
+window_name_or_specification:
+ window_name
+ | in_line_window_specification
+ ;
+in_line_window_specification:
+ window_specification
+ ;
+opt_window_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_clause
+ ;
+window_clause:
+ SQL_TOKEN_WINDOW window_definition_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_definition_list:
+ window_definition_list ',' window_definition
+ {$1->append($3);
+ $$ = $1;}
+ | window_definition
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+window_definition:
+ new_window_name SQL_TOKEN_AS window_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+new_window_name:
+ window_name
+ ;
+window_specification:
+ '('
+ opt_existing_window_name
+ opt_window_partition_clause
+ opt_order_by_clause
+ opt_window_frame_clause
+ ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+opt_existing_window_name:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | existing_window_name
+ ;
+opt_window_partition_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_partition_clause
+ ;
+opt_window_frame_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_frame_clause
+ ;
+existing_window_name:
+ window_name
+ ;
+window_partition_clause:
+ SQL_TOKEN_PARTITION SQL_TOKEN_BY window_partition_column_reference_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_partition_column_reference_list:
+ window_partition_column_reference_list ',' window_partition_column_reference
+ {$1->append($3);
+ $$ = $1;}
+ | window_partition_column_reference
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+window_partition_column_reference:
+ column_ref opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+opt_window_frame_exclusion:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_frame_exclusion
+ ;
+window_frame_clause:
+ window_frame_units window_frame_extent opt_window_frame_exclusion
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_frame_units:
+ SQL_TOKEN_ROWS
+ | SQL_TOKEN_RANGE
+ ;
+window_frame_extent:
+ window_frame_start
+ | window_frame_between
+ ;
+window_frame_start:
+ SQL_TOKEN_UNBOUNDED SQL_TOKEN_PRECEDING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | window_frame_preceding
+ | SQL_TOKEN_CURRENT SQL_TOKEN_ROW
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_preceding:
+ unsigned_value_spec SQL_TOKEN_PRECEDING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_between:
+ SQL_TOKEN_BETWEEN window_frame_bound_1 SQL_TOKEN_AND window_frame_bound_2
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+window_frame_bound_1:
+ window_frame_bound
+ ;
+window_frame_bound_2:
+ window_frame_bound
+ ;
+window_frame_bound:
+ window_frame_start
+ | SQL_TOKEN_UNBOUNDED SQL_TOKEN_FOLLOWING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | window_frame_following
+ ;
+window_frame_following:
+ unsigned_value_spec SQL_TOKEN_FOLLOWING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_exclusion:
+ SQL_TOKEN_EXCLUDE SQL_TOKEN_CURRENT SQL_TOKEN_ROW
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_GROUP
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_TIES
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_NO SQL_TOKEN_OTHERS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+op_parameter:
+ {$$ = SQL_NEW_RULE;}
+ | '?' SQL_EQUAL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("?", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ ;
+odbc_call_spec:
+ op_parameter SQL_TOKEN_CALL table_node op_odbc_call_parameter
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+op_odbc_call_parameter:
+ {$$ = SQL_NEW_RULE;}
+ | '(' odbc_parameter_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+odbc_parameter_commalist:
+ odbc_parameter
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | odbc_parameter_commalist ',' odbc_parameter
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+odbc_parameter:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | literal
+ | parameter
+ ;
+
+odbc_fct_spec:
+ odbc_fct_type SQL_TOKEN_STRING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_FN set_fct_spec
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+odbc_fct_type:
+ SQL_TOKEN_D
+ | SQL_TOKEN_T
+ | SQL_TOKEN_TS
+ ;
+
+general_set_fct:
+ set_fct_type '(' opt_all_distinct function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COUNT '(' '*' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COUNT '(' opt_all_distinct function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | ordered_set_function
+ | array_aggregate_function
+ ;
+set_fct_type:
+ SQL_TOKEN_AVG
+ | SQL_TOKEN_MAX
+ | SQL_TOKEN_MIN
+ | SQL_TOKEN_SUM
+ | SQL_TOKEN_EVERY
+ | SQL_TOKEN_ANY
+ | SQL_TOKEN_SOME
+ | SQL_TOKEN_STDDEV_POP
+ | SQL_TOKEN_STDDEV_SAMP
+ | SQL_TOKEN_VAR_SAMP
+ | SQL_TOKEN_VAR_POP
+ | SQL_TOKEN_COLLECT
+ | SQL_TOKEN_FUSION
+ | SQL_TOKEN_INTERSECTION
+ ;
+
+ordered_set_function:
+ hypothetical_set_function
+ | inverse_distribution_function
+ ;
+hypothetical_set_function:
+ rank_function_type '(' hypothetical_set_function_value_expression_list ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ | rank_function_type '(' hypothetical_set_function_value_expression_list SQL_TOKEN_BY value_exp_commalist ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+ ;
+
+within_group_specification:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_WITHIN SQL_TOKEN_GROUP '(' opt_order_by_clause ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+hypothetical_set_function_value_expression_list:
+ value_exp_commalist
+ ;
+
+inverse_distribution_function:
+ inverse_distribution_function_type '('inverse_distribution_function_argument ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+inverse_distribution_function_argument:
+ num_value_exp
+ ;
+inverse_distribution_function_type:
+ SQL_TOKEN_PERCENTILE_CONT
+ | SQL_TOKEN_PERCENTILE_DISC
+ ;
+
+array_aggregate_function:
+ SQL_TOKEN_ARRAY_AGG '(' value_exp opt_order_by_clause ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+rank_function_type:
+ SQL_TOKEN_RANK
+ | SQL_TOKEN_DENSE_RANK
+ | SQL_TOKEN_PERCENT_RANK
+ | SQL_TOKEN_CUME_DIST
+ ;
+outer_join_type:
+ SQL_TOKEN_LEFT %prec SQL_TOKEN_LEFT
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_RIGHT %prec SQL_TOKEN_RIGHT
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_FULL %prec SQL_TOKEN_FULL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+join_condition:
+ SQL_TOKEN_ON search_condition
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+join_spec:
+ join_condition
+ | named_columns_join
+ ;
+join_type:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_INNER
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | outer_join_type
+ | outer_join_type SQL_TOKEN_OUTER
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+cross_union:
+ table_ref SQL_TOKEN_CROSS SQL_TOKEN_JOIN table_ref
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+qualified_join:
+ /* when SQL_TOKEN_NATURAL, then no join_spec */
+ table_ref SQL_TOKEN_NATURAL join_type SQL_TOKEN_JOIN table_ref
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | table_ref join_type SQL_TOKEN_JOIN table_ref join_spec
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | cross_union
+ ;
+joined_table:
+ qualified_join
+ ;
+named_columns_join:
+ SQL_TOKEN_USING '(' column_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+simple_table:
+ select_statement
+ | values_or_query_spec
+ ;
+
+non_join_query_primary:
+ simple_table
+ | '(' non_join_query_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+non_join_query_term:
+ non_join_query_primary
+ | query_term SQL_TOKEN_INTERSECT all query_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+query_primary:
+ non_join_query_primary
+ ;
+non_join_query_exp:
+ non_join_query_term
+ | query_exp SQL_TOKEN_UNION all query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | query_exp SQL_TOKEN_EXCEPT all query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+all:
+ /* empty*/ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ALL
+ ;
+query_exp:
+ non_join_query_exp /*[^')']*/
+ ;
+scalar_subquery:
+ subquery
+ ;
+cast_operand:
+ value_exp
+ ;
+cast_target:
+ table_node
+ | data_type
+ ;
+cast_spec:
+ SQL_TOKEN_CAST '(' cast_operand SQL_TOKEN_AS cast_target ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+value_exp_primary:
+ unsigned_value_spec
+ | column_ref
+ | set_fct_spec
+ | scalar_subquery
+ | case_expression
+ | window_function
+ | '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | cast_spec
+ ;
+
+num_primary:
+ value_exp_primary
+ | num_value_fct
+ ;
+factor:
+ num_primary
+ | '-' num_primary %prec SQL_TOKEN_UMINUS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ | '+' num_primary %prec SQL_TOKEN_UMINUS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ ;
+
+term:
+ factor
+ | term '*' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | term '/' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("/", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+
+num_value_exp:
+ term
+ | num_value_exp '+' term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | num_value_exp '-' term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+datetime_primary:
+/* value_exp_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ |*/ datetime_value_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+datetime_value_fct:
+ SQL_TOKEN_CURRENT_DATE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_CURRENT_TIME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_CURRENT_TIMESTAMP
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+time_zone:
+ SQL_TOKEN_AT time_zone_specifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+time_zone_specifier:
+ SQL_TOKEN_LOCAL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+/* | SQL_TOKEN_TIME SQL_TOKEN_ZONE interval_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }*/
+ ;
+datetime_factor:
+ datetime_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | datetime_primary time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+datetime_term:
+ datetime_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/*
+interval_term:
+ literal
+ | interval_term '*' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | interval_term '/' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("/", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+*/
+datetime_value_exp:
+ datetime_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+/* | interval_value_exp '+' datetime_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | datetime_value_exp '+' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | datetime_value_exp '-' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+*/ ;
+/*
+interval_value_exp:
+ interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | interval_value_exp '+' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | interval_value_exp '-' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | '(' datetime_value_exp '-' datetime_term ')' interval_qualifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ }
+ ;
+*/
+non_second_datetime_field:
+ SQL_TOKEN_YEAR
+ | SQL_TOKEN_MONTH
+ | SQL_TOKEN_DAY
+ | SQL_TOKEN_HOUR
+ | SQL_TOKEN_MINUTE
+ ;
+start_field:
+ non_second_datetime_field opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+end_field:
+ non_second_datetime_field
+ | SQL_TOKEN_SECOND opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+single_datetime_field:
+ non_second_datetime_field opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_SECOND opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+interval_qualifier:
+ start_field SQL_TOKEN_TO end_field
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | single_datetime_field
+ ;
+
+function_arg_commalist2:
+ function_arg ',' function_arg
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);}
+ ;
+function_arg_commalist3:
+ function_arg ',' function_arg ',' function_arg
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);
+ $$->append($5);
+ }
+ ;
+function_arg_commalist4:
+ function_arg ',' function_arg ',' function_arg ',' function_arg
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);
+ $$->append($5);
+ $$->append($7);
+ }
+ ;
+value_exp_commalist:
+ value_exp
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | value_exp_commalist ',' value_exp
+ {$1->append($3);
+ $$ = $1;}
+ /* this rule is only valid if we check predicates */
+ | value_exp_commalist ';' value_exp
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ else
+ YYERROR;
+ }
+ ;
+function_arg:
+ result
+ | value_exp comparison value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | value_exp SQL_TOKEN_USING value_exp comparison value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | value_exp SQL_TOKEN_BY value_exp_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+function_args_commalist:
+ function_arg
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | function_args_commalist ',' function_arg
+ {$1->append($3);
+ $$ = $1;}
+ /* this rule is only valid if we check predicates */
+ | function_args_commalist ';' function_arg
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+value_exp:
+ num_value_exp /*[^')']*/
+ | string_value_exp
+ | datetime_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+string_value_exp:
+ char_value_exp
+/* | bit_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+*/ ;
+char_value_exp:
+ char_factor
+ | concatenation
+ ;
+concatenation:
+ char_value_exp '+' char_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | value_exp SQL_CONCAT value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+
+char_primary:
+ SQL_TOKEN_STRING
+ | string_value_fct
+ ;
+collate_clause:
+ SQL_TOKEN_COLLATE table_node
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+char_factor:
+ char_primary
+ | char_primary collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+string_value_fct:
+ char_value_fct
+ | bit_value_fct
+ ;
+bit_value_fct:
+ bit_substring_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+bit_substring_fct:
+ SQL_TOKEN_SUBSTRING '(' bit_value_exp SQL_TOKEN_FROM string_value_exp for_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+bit_value_exp:
+ bit_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/*
+ bit_concatenation
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ |
+bit_concatenation:
+ bit_value_exp '+' bit_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+*/
+bit_factor:
+ bit_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+bit_primary:
+ {$$ = SQL_NEW_RULE;}
+/* value_exp_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | string_value_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }*/
+ ;
+char_value_fct:
+ char_substring_fct
+ | fold
+ | form_conversion
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | char_translation
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | trim_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+for_length:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_FOR value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+char_substring_fct:
+ SQL_TOKEN_SUBSTRING '(' value_exp SQL_TOKEN_FROM value_exp for_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_SUBSTRING '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+upper_lower:
+ SQL_TOKEN_UPPER
+ | SQL_TOKEN_LOWER
+ ;
+fold:
+ upper_lower '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+form_conversion:
+ SQL_TOKEN_CONVERT '(' string_value_exp SQL_TOKEN_USING table_node ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_CONVERT '(' cast_operand ',' cast_target ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+char_translation:
+ SQL_TOKEN_TRANSLATE '(' string_value_exp SQL_TOKEN_USING table_node ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+trim_fct:
+ SQL_TOKEN_TRIM '(' trim_operands ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+trim_operands:
+ trim_spec value_exp SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | trim_spec SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | value_exp SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | value_exp
+ ;
+
+trim_spec:
+ SQL_TOKEN_BOTH
+ | SQL_TOKEN_LEADING
+ | SQL_TOKEN_TRAILING
+ ;
+
+derived_column:
+ value_exp as_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+/* Tabellenname */
+table_node:
+ table_name
+ | schema_name
+ | catalog_name
+;
+catalog_name:
+ SQL_TOKEN_NAME '.' schema_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | SQL_TOKEN_NAME ':' schema_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+;
+schema_name:
+ SQL_TOKEN_NAME '.' table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+;
+
+table_name:
+ SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+;
+/* Columns */
+column_ref:
+ column
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+/* | table_node '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);}
+*/
+ | SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);}
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+ | SQL_TOKEN_NAME ':' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+/* | SQL_TOKEN_NAME ';' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(";", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+*/ ;
+
+ /* data types */
+column_val:
+ column
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ | '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+ ;
+data_type:
+ predefined_type
+ ;
+opt_char_set_spec:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_CHARACTER SQL_TOKEN_SET SQL_TOKEN_NAME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_collate_clause:
+ {$$ = SQL_NEW_RULE;}
+ | collate_clause
+ ;
+predefined_type:
+ character_string_type opt_char_set_spec opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | national_character_string_type opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | binary_string_type
+ | numeric_type
+ | boolean_type
+ | datetime_type
+ | interval_type
+ ;
+character_string_type:
+ SQL_TOKEN_CHARACTER opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHARACTER SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_CHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_VARCHAR paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | character_large_object_type
+ ;
+opt_paren_precision:
+ {$$ = SQL_NEW_RULE;}
+ | paren_char_length
+ ;
+paren_char_length:
+ '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+opt_paren_char_large_length:
+ {$$ = SQL_NEW_RULE;}
+ | paren_character_large_object_length
+ ;
+paren_character_large_object_length:
+ '(' large_object_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+large_object_length:
+ SQL_TOKEN_INTNUM opt_multiplier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+opt_multiplier:
+ {$$ = SQL_NEW_RULE;}
+ | 'K'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("K", SQLNodeType::Punctuation));
+ }
+ | 'M'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("M", SQLNodeType::Punctuation));
+ }
+ | 'G'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("G", SQLNodeType::Punctuation));
+ }
+ | 'T'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("T", SQLNodeType::Punctuation));
+ }
+ | 'P'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("P", SQLNodeType::Punctuation));
+ }
+ ;
+character_large_object_type:
+ SQL_TOKEN_CHARACTER SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_CHAR SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_CLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+national_character_string_type:
+ SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_NCHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NCHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | national_character_large_object_type
+ ;
+national_character_large_object_type:
+ SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | SQL_TOKEN_NCHAR SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NCLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+binary_string_type:
+ SQL_TOKEN_BINARY opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_BINARY SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_VARBINARY paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | binary_large_object_string_type
+ ;
+binary_large_object_string_type:
+ SQL_TOKEN_BINARY SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_BLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+numeric_type:
+ exact_numeric_type
+ | approximate_numeric_type
+ ;
+opt_paren_precision_scale:
+ {$$ = SQL_NEW_RULE;}
+ | '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | '(' SQL_TOKEN_INTNUM ',' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+exact_numeric_type:
+ SQL_TOKEN_NUMERIC opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_DECIMAL opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_DEC opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_SMALLINT
+ | SQL_TOKEN_INTEGER
+ | SQL_TOKEN_INT
+ | SQL_TOKEN_BIGINT
+ ;
+approximate_numeric_type:
+ SQL_TOKEN_FLOAT '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_FLOAT
+ | SQL_TOKEN_REAL
+ | SQL_TOKEN_DOUBLE
+ | SQL_TOKEN_DOUBLE SQL_TOKEN_PRECISION
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+boolean_type:
+ SQL_TOKEN_BOOLEAN
+;
+datetime_type:
+ SQL_TOKEN_DATE
+ | SQL_TOKEN_TIME opt_paren_precision opt_with_or_without_time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_TIMESTAMP opt_paren_precision opt_with_or_without_time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_with_or_without_time_zone:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_TIME SQL_TOKEN_ZONE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_WITHOUT SQL_TOKEN_TIME SQL_TOKEN_ZONE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+interval_type:
+ SQL_TOKEN_INTERVAL interval_qualifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+ /* the various things you can name */
+
+column:
+ SQL_TOKEN_NAME
+ | SQL_TOKEN_POSITION
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ | SQL_TOKEN_CHAR_LENGTH
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ | SQL_TOKEN_EXTRACT
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ ;
+case_expression:
+ case_abbreviation
+ | case_specification
+ ;
+case_abbreviation:
+ SQL_TOKEN_NULLIF '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COALESCE '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COALESCE '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+case_specification:
+ simple_case
+ | searched_case
+ ;
+simple_case:
+ SQL_TOKEN_CASE case_operand simple_when_clause_list else_clause SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+searched_case:
+ SQL_TOKEN_CASE searched_when_clause_list else_clause SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+simple_when_clause_list:
+ simple_when_clause
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | searched_when_clause_list simple_when_clause
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+simple_when_clause:
+ SQL_TOKEN_WHEN when_operand_list SQL_TOKEN_THEN result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+when_operand_list:
+ when_operand
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | when_operand_list ',' when_operand
+ {$1->append($3);
+ $$ = $1;}
+ ;
+when_operand:
+ row_value_constructor_elem
+ | comparison_predicate_part_2 %dprec 1
+ | between_predicate_part_2
+ | in_predicate_part_2
+ | character_like_predicate_part_2
+ | null_predicate_part_2 %dprec 2
+;
+searched_when_clause_list:
+ searched_when_clause
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | searched_when_clause_list searched_when_clause
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+searched_when_clause:
+ SQL_TOKEN_WHEN search_condition SQL_TOKEN_THEN result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+else_clause:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ELSE result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+result:
+ result_expression
+ ;
+result_expression:
+ value_exp
+ ;
+case_operand:
+ row_value_constructor_elem
+ ;
+
+cursor: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+
+/***
+module: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+***/
+
+parameter:
+ ':' SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($2);}
+ | '?'
+ {$$ = SQL_NEW_RULE; // test
+ $$->append(newNode("?", SQLNodeType::Punctuation));}
+ | '[' SQL_TOKEN_NAME ']'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("[", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("]", SQLNodeType::Punctuation));}
+ ;
+
+/***
+procedure: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+***/
+
+range_variable:
+ {$$ = SQL_NEW_RULE;}
+ | opt_as SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+user: SQL_TOKEN_NAME
+ ;
+
+/* PREDICATECHECK RULES */
+sql:
+ search_condition /* checking predicats */
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // sql: rule 1
+ {
+ $$ = $1;
+ if ( SQL_ISRULE($$,search_condition) )
+ {
+ $$->insert(0,newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ }
+ else
+ YYERROR;
+ }
+ | '(' sql ')' /* checking predicats */
+ ;
+trigger_definition:
+ SQL_TOKEN_CREATE SQL_TOKEN_TRIGGER trigger_name trigger_action_time trigger_event SQL_TOKEN_ON table_name op_referencing triggered_action
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);
+ $$->append($9);
+ }
+ ;
+op_referencing:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_REFERENCING transition_table_or_variable_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+trigger_action_time:
+ SQL_TOKEN_BEFORE
+ | SQL_TOKEN_AFTER
+ | SQL_TOKEN_INSTEAD SQL_TOKEN_OF
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+;
+trigger_event:
+ SQL_TOKEN_INSERT
+ | SQL_TOKEN_DELETE
+ | SQL_TOKEN_UPDATE op_trigger_columnlist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+op_trigger_columnlist:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_OF trigger_column_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+trigger_column_list:
+ column_commalist
+ ;
+triggered_action:
+ op_triggered_action_for triggered_when_clause triggered_SQL_statement
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+op_triggered_action_for:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_FOR SQL_TOKEN_EACH trigger_for
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+trigger_for:
+ SQL_TOKEN_ROW
+ | SQL_TOKEN_STATEMENT
+ ;
+triggered_when_clause:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_WHEN parenthesized_boolean_value_expression
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+triggered_SQL_statement:
+ SQL_procedure_statement
+ | SQL_TOKEN_BEGIN SQL_TOKEN_ATOMIC SQL_procedure_statement_list ';' SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode(";", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ ;
+SQL_procedure_statement_list:
+ SQL_procedure_statement
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | SQL_procedure_statement_list ';' SQL_procedure_statement
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+SQL_procedure_statement:
+ sql
+ ;
+
+transition_table_or_variable_list:
+ transition_table_or_variable
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | transition_table_or_variable_list transition_table_or_variable
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+
+transition_table_or_variable:
+ SQL_TOKEN_OLD opt_row opt_as old_transition_variable_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NEW opt_row opt_as new_transition_variable_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_OLD SQL_TOKEN_TABLE opt_as old_transition_table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NEW SQL_TOKEN_TABLE opt_as new_transition_table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+;
+old_transition_table_name:
+ transition_table_name
+;
+new_transition_table_name:
+ transition_table_name
+;
+transition_table_name:
+ SQL_TOKEN_NAME
+;
+old_transition_variable_name:
+ SQL_TOKEN_NAME
+;
+new_transition_variable_name:
+ SQL_TOKEN_NAME
+;
+trigger_name:
+ SQL_TOKEN_NAME
+;
+%%
+
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::dbtools;
+
+connectivity::OSQLParser* xxx_pGLOBAL_SQLPARSER;
+
+connectivity::OSQLInternalNode* newNode(const char* pNewValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(pNewValue, eNodeType, nNodeID);
+}
+
+connectivity::OSQLInternalNode* newNode(const OString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(_newValue, eNodeType, nNodeID);
+}
+
+connectivity::OSQLInternalNode* newNode(const OUString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(_newValue, eNodeType, nNodeID);
+}
+
+OParseContext::OParseContext()
+{
+}
+
+
+OParseContext::~OParseContext()
+{
+}
+
+
+OUString OParseContext::getErrorMessage(ErrorCode _eCode) const
+{
+ OUString aMsg;
+ switch (_eCode)
+ {
+ case ErrorCode::General: aMsg = "Syntax error in SQL expression"; break;
+ case ErrorCode::ValueNoLike: aMsg = "The value #1 can not be used with LIKE."; break;
+ case ErrorCode::FieldNoLike: aMsg = "LIKE can not be used with this field."; break;
+ case ErrorCode::InvalidCompare: aMsg = "The entered criterion can not be compared with this field."; break;
+ case ErrorCode::InvalidIntCompare: aMsg = "The field can not be compared with a number."; break;
+ case ErrorCode::InvalidDateCompare: aMsg = "The field can not be compared with a date."; break;
+ case ErrorCode::InvalidRealCompare: aMsg = "The field can not be compared with a floating point number."; break;
+ case ErrorCode::InvalidTableNosuch: aMsg = "The database does not contain a table named \"#\"."; break;
+ case ErrorCode::InvalidTableOrQuery: aMsg = "The database does contain neither a table nor a query named \"#\"."; break;
+ case ErrorCode::InvalidColumn: aMsg = "The column \"#1\" is unknown in the table \"#2\"."; break;
+ case ErrorCode::InvalidTableExist: aMsg = "The database already contains a table or view with name \"#\"."; break;
+ case ErrorCode::InvalidQueryExist: aMsg = "The database already contains a query with name \"#\"."; break;
+ default:
+ OSL_FAIL( "OParseContext::getErrorMessage: unknown error code!" );
+ break;
+ }
+ return aMsg;
+}
+
+
+OString OParseContext::getIntlKeywordAscii(InternationalKeyCode _eKey) const
+{
+ OString aKeyword;
+ switch (_eKey)
+ {
+ case InternationalKeyCode::Like: aKeyword = "LIKE"; break;
+ case InternationalKeyCode::Not: aKeyword = "NOT"; break;
+ case InternationalKeyCode::Null: aKeyword = "NULL"; break;
+ case InternationalKeyCode::True: aKeyword = "True"; break;
+ case InternationalKeyCode::False: aKeyword = "False"; break;
+ case InternationalKeyCode::Is: aKeyword = "IS"; break;
+ case InternationalKeyCode::Between: aKeyword = "BETWEEN"; break;
+ case InternationalKeyCode::Or: aKeyword = "OR"; break;
+ case InternationalKeyCode::And: aKeyword = "AND"; break;
+ case InternationalKeyCode::Avg: aKeyword = "AVG"; break;
+ case InternationalKeyCode::Count: aKeyword = "COUNT"; break;
+ case InternationalKeyCode::Max: aKeyword = "MAX"; break;
+ case InternationalKeyCode::Min: aKeyword = "MIN"; break;
+ case InternationalKeyCode::Sum: aKeyword = "SUM"; break;
+ case InternationalKeyCode::Every: aKeyword = "EVERY"; break;
+ case InternationalKeyCode::Any: aKeyword = "ANY"; break;
+ case InternationalKeyCode::Some: aKeyword = "SOME"; break;
+ case InternationalKeyCode::StdDevPop: aKeyword = "STDDEV_POP"; break;
+ case InternationalKeyCode::StdDevSamp: aKeyword = "STDDEV_SAMP"; break;
+ case InternationalKeyCode::VarSamp: aKeyword = "VAR_SAMP"; break;
+ case InternationalKeyCode::VarPop: aKeyword = "VAR_POP"; break;
+ case InternationalKeyCode::Collect: aKeyword = "COLLECT"; break;
+ case InternationalKeyCode::Fusion: aKeyword = "FUSION"; break;
+ case InternationalKeyCode::Intersection:aKeyword = "INTERSECTION"; break;
+ case InternationalKeyCode::None: break;
+ default:
+ OSL_FAIL( "OParseContext::getIntlKeywordAscii: unknown key!" );
+ break;
+ }
+ return aKeyword;
+}
+
+
+IParseContext::InternationalKeyCode OParseContext::getIntlKeyCode(const OString& rToken) const
+{
+ static IParseContext::InternationalKeyCode Intl_TokenID[] =
+ {
+ InternationalKeyCode::Like, InternationalKeyCode::Not, InternationalKeyCode::Null, InternationalKeyCode::True,
+ InternationalKeyCode::False, InternationalKeyCode::Is, InternationalKeyCode::Between, InternationalKeyCode::Or,
+ InternationalKeyCode::And, InternationalKeyCode::Avg, InternationalKeyCode::Count, InternationalKeyCode::Max,
+ InternationalKeyCode::Min, InternationalKeyCode::Sum, InternationalKeyCode::Every,InternationalKeyCode::Any,InternationalKeyCode::Some,
+ InternationalKeyCode::StdDevPop,InternationalKeyCode::StdDevSamp,InternationalKeyCode::VarSamp,
+ InternationalKeyCode::VarPop,InternationalKeyCode::Collect,InternationalKeyCode::Fusion,InternationalKeyCode::Intersection
+ };
+
+ sal_uInt32 nCount = SAL_N_ELEMENTS( Intl_TokenID );
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ {
+ OString aKey = getIntlKeywordAscii(Intl_TokenID[i]);
+ if (rToken.equalsIgnoreAsciiCase(aKey))
+ return Intl_TokenID[i];
+ }
+
+ return InternationalKeyCode::None;
+}
+
+
+static Locale& impl_getLocaleInstance( )
+{
+ static Locale s_aLocale( "en", "US", "" );
+ return s_aLocale;
+}
+
+
+Locale OParseContext::getPreferredLocale( ) const
+{
+ return getDefaultLocale();
+}
+
+
+const Locale& OParseContext::getDefaultLocale()
+{
+ return impl_getLocaleInstance();
+}
+
+// The (unfortunately global) yylval for the handing over of
+// values from the Scanner to the Parser. The global variable
+// is only used for a short term, the Parser reads the variable
+// immediately after the call of the Scanner into a same named own
+// member variable.
+
+
+OUString ConvertLikeToken(const OSQLParseNode* pTokenNode, const OSQLParseNode* pEscapeNode, bool bInternational)
+{
+ OUStringBuffer aMatchStr(0);
+ if (pTokenNode->isToken())
+ {
+ sal_Unicode cEscape = 0;
+ if (pEscapeNode->count())
+ cEscape = pEscapeNode->getChild(1)->getTokenValue().toChar();
+
+ // Change place holder
+ aMatchStr = pTokenNode->getTokenValue();
+ const sal_Int32 nLen = aMatchStr.getLength();
+ OUStringBuffer sSearch,sReplace;
+ if ( bInternational )
+ {
+ sSearch.append("%_");
+ sReplace.append("*?");
+ }
+ else
+ {
+ sSearch.append("*?");
+ sReplace.append("%_");
+ }
+
+ bool wasEscape = false;
+ for (sal_Int32 i = 0; i < nLen; i++)
+ {
+ const sal_Unicode c = aMatchStr[i];
+ // SQL standard requires the escape to be followed
+ // by a meta-character ('%', '_' or itself), else error
+ // We are more lenient here and let it escape anything.
+ // Especially since some databases (e.g. Microsoft SQL Server)
+ // have more meta-characters than the standard, such as e.g. '[' and ']'
+ if (wasEscape)
+ {
+ wasEscape=false;
+ continue;
+ }
+ if (c == cEscape)
+ {
+ wasEscape=true;
+ continue;
+ }
+ int match = -1;
+ if (c == sSearch[0])
+ match=0;
+ else if (c == sSearch[1])
+ match=1;
+
+ if (match != -1)
+ {
+ aMatchStr[i] = sReplace[match];
+ }
+ }
+ }
+ return aMatchStr.makeStringAndClear();
+}
+
+sal_uInt32 OSQLParser::s_nRuleIDs[OSQLParseNode::rule_count + 1];
+OSQLParser::RuleIDMap OSQLParser::s_aReverseRuleIDLookup;
+OParseContext OSQLParser::s_aDefaultContext;
+
+sal_Int32 OSQLParser::s_nRefCount = 0;
+// ::osl::Mutex OSQLParser::s_aMutex;
+OSQLScanner* OSQLParser::s_pScanner = nullptr;
+OSQLParseNodesGarbageCollector* OSQLParser::s_pGarbageCollector = nullptr;
+css::uno::Reference< css::i18n::XLocaleData4> OSQLParser::s_xLocaleData = nullptr;
+
+void setParser(OSQLParser* _pParser)
+{
+ xxx_pGLOBAL_SQLPARSER = _pParser;
+}
+
+void OSQLParser::setParseTree(OSQLParseNode* pNewParseTree)
+{
+ ::osl::MutexGuard aGuard(getMutex());
+ m_pParseTree.reset(pNewParseTree);
+}
+
+
+/** Delete all comments in a query.
+
+ See also getComment()/concatComment() implementation for
+ OQueryController::translateStatement().
+ */
+static OUString delComment( const OUString& rQuery )
+{
+ // First a quick search if there is any "--" or "//" or "/*", if not then the whole
+ // copying loop is pointless.
+ if (rQuery.indexOf("--") < 0 && rQuery.indexOf("//") < 0 &&
+ rQuery.indexOf("/*") < 0)
+ return rQuery;
+
+ const sal_Unicode* pCopy = rQuery.getStr();
+ sal_Int32 nQueryLen = rQuery.getLength();
+ bool bIsText1 = false; // "text"
+ bool bIsText2 = false; // 'text'
+ bool bComment2 = false; // /* comment */
+ bool bComment = false; // -- or // comment
+ OUStringBuffer aBuf(nQueryLen);
+ for (sal_Int32 i=0; i < nQueryLen; ++i)
+ {
+ if (bComment2)
+ {
+ if ((i+1) < nQueryLen)
+ {
+ if (pCopy[i]=='*' && pCopy[i+1]=='/')
+ {
+ bComment2 = false;
+ ++i;
+ }
+ }
+ else
+ {
+ // comment can't close anymore, actually an error, but...
+ }
+ continue;
+ }
+ if (pCopy[i] == '\n')
+ bComment = false;
+ else if (!bComment)
+ {
+ if (pCopy[i] == '\"' && !bIsText2)
+ bIsText1 = !bIsText1;
+ else if (pCopy[i] == '\'' && !bIsText1)
+ bIsText2 = !bIsText2;
+ if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
+ {
+ if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/'))
+ bComment = true;
+ else if ((pCopy[i]=='/' && pCopy[i+1]=='*'))
+ bComment2 = true;
+ }
+ }
+ if (!bComment && !bComment2)
+ aBuf.append( &pCopy[i], 1);
+ }
+ return aBuf.makeStringAndClear();
+}
+
+std::unique_ptr<OSQLParseNode> OSQLParser::parseTree(OUString& rErrorMessage,
+ const OUString& rStatement,
+ bool bInternational)
+{
+
+
+ // Guard the parsing
+ ::osl::MutexGuard aGuard(getMutex());
+ // must be reset
+ setParser(this);
+
+ // delete comments before parsing
+ OUString sTemp = delComment(rStatement);
+
+ // defines how to scan
+ s_pScanner->SetRule(OSQLScanner::GetSQLRule()); // initial
+ s_pScanner->prepareScan(sTemp, m_pContext, bInternational);
+
+ SQLyylval.pParseNode = nullptr;
+ // SQLyypvt = NULL;
+ m_pParseTree = nullptr;
+ m_sErrorMessage = "";
+
+ // start parsing
+ if (SQLyyparse() != 0)
+ {
+ // only set the error message, if it's not already set
+ if (m_sErrorMessage.isEmpty())
+ m_sErrorMessage = s_pScanner->getErrorMessage();
+ if (m_sErrorMessage.isEmpty())
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::General);
+
+ rErrorMessage = m_sErrorMessage;
+
+ // clear the garbage collector
+ (*s_pGarbageCollector)->clearAndDelete();
+ m_pParseTree.release(); // because the garbage collector deleted it
+ return nullptr;
+ }
+ else
+ {
+ (*s_pGarbageCollector)->clear();
+
+ // return result:
+ // to work around a bug in MKS YACC return the member m_pParseTree
+ // instead of Sdbyyval.pParseNode
+
+ SAL_WARN_IF(!m_pParseTree, "connectivity.parse",
+ "OSQLParser: Parser did not create ParseTree");
+ return std::move(m_pParseTree);
+ }
+}
+
+OString OSQLParser::TokenIDToStr(sal_uInt32 nTokenID, const IParseContext* pContext)
+{
+ OString aStr;
+ if (pContext)
+ {
+ IParseContext::InternationalKeyCode eKeyCode = IParseContext::InternationalKeyCode::None;
+ switch( nTokenID )
+ {
+ case SQL_TOKEN_LIKE: eKeyCode = IParseContext::InternationalKeyCode::Like; break;
+ case SQL_TOKEN_NOT: eKeyCode = IParseContext::InternationalKeyCode::Not; break;
+ case SQL_TOKEN_NULL: eKeyCode = IParseContext::InternationalKeyCode::Null; break;
+ case SQL_TOKEN_TRUE: eKeyCode = IParseContext::InternationalKeyCode::True; break;
+ case SQL_TOKEN_FALSE: eKeyCode = IParseContext::InternationalKeyCode::False; break;
+ case SQL_TOKEN_IS: eKeyCode = IParseContext::InternationalKeyCode::Is; break;
+ case SQL_TOKEN_BETWEEN: eKeyCode = IParseContext::InternationalKeyCode::Between; break;
+ case SQL_TOKEN_OR: eKeyCode = IParseContext::InternationalKeyCode::Or; break;
+ case SQL_TOKEN_AND: eKeyCode = IParseContext::InternationalKeyCode::And; break;
+ case SQL_TOKEN_AVG: eKeyCode = IParseContext::InternationalKeyCode::Avg; break;
+ case SQL_TOKEN_COUNT: eKeyCode = IParseContext::InternationalKeyCode::Count; break;
+ case SQL_TOKEN_MAX: eKeyCode = IParseContext::InternationalKeyCode::Max; break;
+ case SQL_TOKEN_MIN: eKeyCode = IParseContext::InternationalKeyCode::Min; break;
+ case SQL_TOKEN_SUM: eKeyCode = IParseContext::InternationalKeyCode::Sum; break;
+ }
+ if ( eKeyCode != IParseContext::InternationalKeyCode::None )
+ aStr = pContext->getIntlKeywordAscii(eKeyCode);
+ }
+
+ if (aStr.isEmpty())
+ {
+ // coverity[unsigned_compare : SUPPRESS] - YYTRANSLATE is out of our control
+ aStr = yytname[YYTRANSLATE(nTokenID)];
+ if(aStr.startsWith("SQL_TOKEN_"))
+ aStr = aStr.copy(10);
+ switch( nTokenID )
+ {
+ case SQL_TOKEN_OJ:
+ case SQL_TOKEN_TS:
+ case SQL_TOKEN_T:
+ case SQL_TOKEN_D:
+ aStr = aStr.toAsciiLowerCase();
+ }
+ }
+ return aStr;
+}
+
+#if OSL_DEBUG_LEVEL > 0
+OUString OSQLParser::RuleIDToStr(sal_uInt32 nRuleID)
+{
+ OSL_ENSURE(nRuleID < SAL_N_ELEMENTS(yytname), "OSQLParser::RuleIDToStr: Invalid nRuleId!");
+ return OUString::createFromAscii(yytname[nRuleID]);
+}
+#endif
+
+
+sal_uInt32 OSQLParser::StrToRuleID(const OString & rValue)
+{
+ // Search for the given name in yytname and return the index
+ // (or UNKNOWN_RULE, if not found)
+ static sal_uInt32 nLen = SAL_N_ELEMENTS(yytname);
+ for (sal_uInt32 i = YYTRANSLATE(SQL_TOKEN_INVALIDSYMBOL); i < (nLen-1); i++)
+ {
+ if (rValue == yytname[i])
+ return i;
+ }
+
+ // Not found
+ return OSQLParseNode::UNKNOWN_RULE;
+}
+
+
+OSQLParseNode::Rule OSQLParser::RuleIDToRule( sal_uInt32 _nRule )
+{
+ OSQLParser::RuleIDMap::const_iterator i (s_aReverseRuleIDLookup.find(_nRule));
+ if (i == s_aReverseRuleIDLookup.end())
+ {
+ SAL_INFO("connectivity.parse",
+ "connectivity::OSQLParser::RuleIDToRule cannot reverse-lookup rule. "
+ "Reverse mapping incomplete? "
+ "_nRule='" << _nRule << "' "
+ "yytname[_nRule]='" << yytname[_nRule] << "'");
+ return OSQLParseNode::UNKNOWN_RULE;
+ }
+ else
+ return i->second;
+}
+
+
+sal_uInt32 OSQLParser::RuleID(OSQLParseNode::Rule eRule)
+{
+ return s_nRuleIDs[(sal_uInt16)eRule];
+}
+
+sal_Int16 OSQLParser::buildNode(OSQLParseNode*& pAppend,OSQLParseNode* pCompare,OSQLParseNode* pLiteral,OSQLParseNode* pLiteral2)
+{
+ OSQLParseNode* pColumnRef = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(new OSQLInternalNode(m_sFieldName,SQLNodeType::Name));
+ OSQLParseNode* pComp = nullptr;
+ if ( SQL_ISTOKEN( pCompare, BETWEEN) && pLiteral2 )
+ pComp = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::between_predicate_part_2));
+ else
+ pComp = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::comparison_predicate));
+
+ pComp->append(pColumnRef);
+ pComp->append(pCompare);
+ pComp->append(pLiteral);
+ if ( pLiteral2 )
+ {
+ pComp->append(new OSQLInternalNode("", SQLNodeType::Keyword,SQL_TOKEN_AND));
+ pComp->append(pLiteral2);
+ }
+ pAppend->append(pComp);
+ return 1;
+}
+
+sal_Int16 OSQLParser::buildStringNodes(OSQLParseNode*& pLiteral)
+{
+ if(!pLiteral)
+ return 1;
+
+ if(SQL_ISRULE(pLiteral,set_fct_spec) || SQL_ISRULE(pLiteral,general_set_fct) || SQL_ISRULE(pLiteral,column_ref)
+ || SQL_ISRULE(pLiteral,subquery))
+ return 1; // here I have a function that I can't transform into a string
+
+ if(pLiteral->getNodeType() == SQLNodeType::IntNum || pLiteral->getNodeType() == SQLNodeType::ApproxNum || pLiteral->getNodeType() == SQLNodeType::AccessDate)
+ {
+ OSQLParseNode* pParent = pLiteral->getParent();
+
+ OSQLParseNode* pNewNode = new OSQLInternalNode(pLiteral->getTokenValue(), SQLNodeType::String);
+ pParent->replace(pLiteral, pNewNode);
+ delete pLiteral;
+ pLiteral = nullptr;
+ return 1;
+ }
+
+ for(size_t i=0;i<pLiteral->count();++i)
+ {
+ OSQLParseNode* pChild = pLiteral->getChild(i);
+ buildStringNodes(pChild);
+ }
+ if(SQL_ISRULE(pLiteral,term) || SQL_ISRULE(pLiteral,value_exp_primary))
+ {
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
+ return 0;
+ }
+ return 1;
+}
+
+sal_Int16 OSQLParser::buildComparisonRule(OSQLParseNode*& pAppend,OSQLParseNode* pLiteral)
+{
+ OSQLParseNode* pComp = new OSQLInternalNode("=", SQLNodeType::Equal);
+ return buildPredicateRule(pAppend,pLiteral,pComp);
+}
+
+
+
+void OSQLParser::reduceLiteral(OSQLParseNode*& pLiteral, bool bAppendBlank)
+{
+ OSL_ENSURE(pLiteral->isRule(), "This is no Rule");
+ OSL_ENSURE(pLiteral->count() == 2, "OSQLParser::ReduceLiteral() Invalid count");
+ OSQLParseNode* pTemp = pLiteral;
+ OUStringBuffer aValue(pLiteral->getChild(0)->getTokenValue());
+ if (bAppendBlank)
+ {
+ aValue.append(" ");
+ }
+
+ aValue.append(pLiteral->getChild(1)->getTokenValue());
+
+ pLiteral = new OSQLInternalNode(aValue.makeStringAndClear(),SQLNodeType::String);
+ delete pTemp;
+}
+
+
+void OSQLParser::error(const char *fmt)
+{
+ if(m_sErrorMessage.isEmpty())
+ {
+ OUString sStr(fmt,strlen(fmt),RTL_TEXTENCODING_UTF8);
+ OUString sSQL_TOKEN("SQL_TOKEN_");
+
+ sal_Int32 nPos1 = sStr.indexOf(sSQL_TOKEN);
+ if(nPos1 != -1)
+ {
+ OUString sFirst = sStr.copy(0,nPos1);
+ sal_Int32 nPos2 = sStr.indexOf(sSQL_TOKEN,nPos1+1);
+ if(nPos2 != -1)
+ {
+ sFirst += sStr.subView(nPos1+sSQL_TOKEN.getLength(),nPos2-nPos1-sSQL_TOKEN.getLength());
+ sFirst += sStr.subView(nPos2+sSQL_TOKEN.getLength());
+ }
+ else
+ sFirst += sStr.subView(nPos1+sSQL_TOKEN.getLength());
+
+ m_sErrorMessage = sFirst;
+ }
+ else
+ m_sErrorMessage = sStr;
+
+ OUString aError = s_pScanner->getErrorMessage();
+ if(!aError.isEmpty())
+ {
+ m_sErrorMessage += ", ";
+ m_sErrorMessage += aError;
+ }
+ }
+}
+
+int OSQLParser::SQLlex()
+{
+ return OSQLScanner::SQLlex();
+}
diff --git a/connectivity/source/parse/sqlflex.l b/connectivity/source/parse/sqlflex.l
new file mode 100644
index 000000000..34a4067ea
--- /dev/null
+++ b/connectivity/source/parse/sqlflex.l
@@ -0,0 +1,808 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+%{
+
+#include "sal/config.h"
+
+#define YY_EXIT 1 // YY_FATAL will not halt the application
+
+#ifndef _CSTDARG_
+#include <cstdarg>
+#endif
+
+#include <string.h>
+
+#if defined _MSC_VER
+#pragma warning ( push )
+// Silence warnings about redefinition of INT8_MIN etc in stdint.h
+// The flex-generated workdir/LexTarget/idlc/source/scanner.cxx defines them prior to these includes
+#pragma warning ( disable : 4005 )
+#endif
+#include <connectivity/internalnode.hxx>
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+#ifndef INCLUDED_CONNECTIVITY_SOURCE_PARSE_SQLFLEX_L
+#define INCLUDED_CONNECTIVITY_SOURCE_PARSE_SQLFLEX_L
+
+#ifndef SQLYYDEBUG
+#define SQLYYDEBUG 1
+#endif
+
+#include "sqlbison.hxx"
+#undef SQLyylex
+#undef SQLyyerror
+#endif
+#include <osl/diagnose.h>
+#include <rtl/strbuf.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqlscan.hxx>
+
+#if defined _MSC_VER
+/**/
+#ifdef yywrap
+#undef yywrap
+#define yywrap() 1
+#endif
+/**/
+#endif
+#define YY_NO_UNISTD_H
+
+using namespace connectivity;
+
+// Creation of the pages for the tokens
+// Pages generally are created from the Lexer
+
+static sal_Int32 gatherString(int delim, sal_Int32 nTyp);
+static sal_Int32 gatherName(const char*);
+static sal_Int32 gatherNamePre(const char* );
+// has to be set before the parser starts
+OSQLScanner* xxx_pGLOBAL_SQLSCAN = nullptr;
+
+#define SQL_NEW_NODE(text, token) \
+ SQLyylval.pParseNode = new OSQLInternalNode(text, token);
+
+#define SQL_NEW_KEYWORD(token) \
+ SQLyylval.pParseNode = new OSQLInternalNode("", SQLNodeType::Keyword, (token)); return token;
+
+#define SQL_NEW_INTNUM SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::IntNum); return SQL_TOKEN_INTNUM;
+#define SQL_NEW_APPROXNUM SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::ApproxNum); return SQL_TOKEN_APPROXNUM;
+#define SQL_NEW_DATE SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::AccessDate); return SQL_TOKEN_ACCESS_DATE;
+
+#define YY_INPUT(buf,result,max_size) \
+{ \
+ int c = xxx_pGLOBAL_SQLSCAN->SQLyygetc(); \
+ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1);\
+}
+
+// coverity[+kill]
+static void do_fatal_error(const char* msg)
+{
+ xxx_pGLOBAL_SQLSCAN->SQLyyerror(msg);
+ /*hack to silence -Wunused-function*/
+ if ((0)) yy_fatal_error(msg);
+}
+
+#define YY_FATAL_ERROR(msg) \
+{ \
+ do_fatal_error(msg); \
+}
+
+%}
+
+%s SQL
+%s PREDICATE_ENG
+%s PREDICATE_GER
+%s DATE
+%s STRING
+
+%option noyywrap
+%option never-interactive
+%%
+
+ABS {SQL_NEW_KEYWORD(SQL_TOKEN_ABS); }
+ACOS {SQL_NEW_KEYWORD(SQL_TOKEN_ACOS); }
+AFTER {SQL_NEW_KEYWORD(SQL_TOKEN_AFTER); }
+ALL {SQL_NEW_KEYWORD(SQL_TOKEN_ALL); }
+ALTER {SQL_NEW_KEYWORD(SQL_TOKEN_ALTER); }
+AND {SQL_NEW_KEYWORD(SQL_TOKEN_AND); }
+ANY {SQL_NEW_KEYWORD(SQL_TOKEN_ANY); }
+ARRAY_AGG {SQL_NEW_KEYWORD(SQL_TOKEN_ARRAY_AGG); }
+AS {SQL_NEW_KEYWORD(SQL_TOKEN_AS); }
+ASC {SQL_NEW_KEYWORD(SQL_TOKEN_ASC); }
+ASCII {SQL_NEW_KEYWORD(SQL_TOKEN_ASCII); }
+ASIN {SQL_NEW_KEYWORD(SQL_TOKEN_ASIN); }
+AT {SQL_NEW_KEYWORD(SQL_TOKEN_AT); }
+ATAN {SQL_NEW_KEYWORD(SQL_TOKEN_ATAN); }
+ATAN2 {SQL_NEW_KEYWORD(SQL_TOKEN_ATAN2); }
+ATOMIC {SQL_NEW_KEYWORD(SQL_TOKEN_ATOMIC); }
+AUTHORIZATION {SQL_NEW_KEYWORD(SQL_TOKEN_AUTHORIZATION); }
+AVG {SQL_NEW_KEYWORD(SQL_TOKEN_AVG); }
+
+BEFORE {SQL_NEW_KEYWORD(SQL_TOKEN_BEFORE); }
+BEGIN {SQL_NEW_KEYWORD(SQL_TOKEN_BEGIN); }
+BETWEEN {SQL_NEW_KEYWORD(SQL_TOKEN_BETWEEN); }
+BIGINT {SQL_NEW_KEYWORD(SQL_TOKEN_BIGINT); }
+BINARY {SQL_NEW_KEYWORD(SQL_TOKEN_BINARY); }
+BIT {SQL_NEW_KEYWORD(SQL_TOKEN_BIT); }
+BIT_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_BIT_LENGTH); }
+BLOB {SQL_NEW_KEYWORD(SQL_TOKEN_BLOB); }
+BOTH {SQL_NEW_KEYWORD(SQL_TOKEN_BOTH); }
+BY {SQL_NEW_KEYWORD(SQL_TOKEN_BY); }
+
+CALL {SQL_NEW_KEYWORD(SQL_TOKEN_CALL); }
+CASE {SQL_NEW_KEYWORD(SQL_TOKEN_CASE); }
+CAST {SQL_NEW_KEYWORD(SQL_TOKEN_CAST); }
+CEILING {SQL_NEW_KEYWORD(SQL_TOKEN_CEILING); }
+CHAR {SQL_NEW_KEYWORD(SQL_TOKEN_CHAR); }
+CHARACTER {SQL_NEW_KEYWORD(SQL_TOKEN_CHARACTER); }
+CHAR(ACTER)?_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_CHAR_LENGTH); }
+CHECK {SQL_NEW_KEYWORD(SQL_TOKEN_CHECK); }
+CLOB {SQL_NEW_KEYWORD(SQL_TOKEN_CLOB); }
+COALESCE {SQL_NEW_KEYWORD(SQL_TOKEN_COALESCE); }
+COLLATE {SQL_NEW_KEYWORD(SQL_TOKEN_COLLATE); }
+COLLECT {SQL_NEW_KEYWORD(SQL_TOKEN_COLLECT); }
+COMMIT {SQL_NEW_KEYWORD(SQL_TOKEN_COMMIT); }
+CONCAT {SQL_NEW_KEYWORD(SQL_TOKEN_CONCAT); }
+CONTINUE {SQL_NEW_KEYWORD(SQL_TOKEN_CONTINUE); }
+CONVERT {SQL_NEW_KEYWORD(SQL_TOKEN_CONVERT); }
+COS {SQL_NEW_KEYWORD(SQL_TOKEN_COS); }
+COT {SQL_NEW_KEYWORD(SQL_TOKEN_COT); }
+COUNT {SQL_NEW_KEYWORD(SQL_TOKEN_COUNT); }
+CREATE {SQL_NEW_KEYWORD(SQL_TOKEN_CREATE); }
+CROSS {SQL_NEW_KEYWORD(SQL_TOKEN_CROSS); }
+CUME_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_CUME_DIST); }
+CURRENT {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT); }
+CURRENT_DATE {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_DATE); }
+CURRENT_CATALOG {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_CATALOG); }
+CURRENT_DEFAULT_TRANSFORM_GROUP {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP); }
+CURRENT_PATH {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_PATH); }
+CURRENT_ROLE {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_ROLE); }
+CURRENT_SCHEMA {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_SCHEMA); }
+CURRENT_USER {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_USER); }
+CURDATE {SQL_NEW_KEYWORD(SQL_TOKEN_CURDATE); }
+CURRENT_TIME {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_TIME); }
+CURTIME {SQL_NEW_KEYWORD(SQL_TOKEN_CURTIME); }
+CURRENT_TIMESTAMP {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_TIMESTAMP); }
+CURSOR {SQL_NEW_KEYWORD(SQL_TOKEN_CURSOR); }
+
+D {SQL_NEW_KEYWORD(SQL_TOKEN_D); }
+DATE {SQL_NEW_KEYWORD(SQL_TOKEN_DATE); }
+DATEDIFF {SQL_NEW_KEYWORD(SQL_TOKEN_DATEDIFF); }
+DATEVALUE {SQL_NEW_KEYWORD(SQL_TOKEN_DATEVALUE); }
+DAY {SQL_NEW_KEYWORD(SQL_TOKEN_DAY); }
+DAYNAME {SQL_NEW_KEYWORD(SQL_TOKEN_DAYNAME); }
+DAYOFMONTH {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFMONTH); }
+DAYOFWEEK {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFWEEK); }
+DAYOFYEAR {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFYEAR); }
+DEC {SQL_NEW_KEYWORD(SQL_TOKEN_DEC); }
+DECIMAL {SQL_NEW_KEYWORD(SQL_TOKEN_DECIMAL); }
+DECLARE {SQL_NEW_KEYWORD(SQL_TOKEN_DECLARE); }
+DEFAULT {SQL_NEW_KEYWORD(SQL_TOKEN_DEFAULT); }
+DEGREES {SQL_NEW_KEYWORD(SQL_TOKEN_DEGREES); }
+DELETE {SQL_NEW_KEYWORD(SQL_TOKEN_DELETE); }
+DENSE_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_DENSE_RANK); }
+DESC {SQL_NEW_KEYWORD(SQL_TOKEN_DESC); }
+DIFFERENCE {SQL_NEW_KEYWORD(SQL_TOKEN_DIFFERENCE); }
+DISTINCT {SQL_NEW_KEYWORD(SQL_TOKEN_DISTINCT); }
+DOUBLE {SQL_NEW_KEYWORD(SQL_TOKEN_DOUBLE); }
+DROP {SQL_NEW_KEYWORD(SQL_TOKEN_DROP); }
+
+EACH {SQL_NEW_KEYWORD(SQL_TOKEN_EACH); }
+ELSE {SQL_NEW_KEYWORD(SQL_TOKEN_ELSE); }
+END {SQL_NEW_KEYWORD(SQL_TOKEN_END); }
+EVERY {SQL_NEW_KEYWORD(SQL_TOKEN_EVERY); }
+ESCAPE {SQL_NEW_KEYWORD(SQL_TOKEN_ESCAPE); }
+EXCEPT {SQL_NEW_KEYWORD(SQL_TOKEN_EXCEPT); }
+EXCLUDE {SQL_NEW_KEYWORD(SQL_TOKEN_EXCLUDE); }
+EXISTS {SQL_NEW_KEYWORD(SQL_TOKEN_EXISTS); }
+EXP {SQL_NEW_KEYWORD(SQL_TOKEN_EXP); }
+EXTRACT {SQL_NEW_KEYWORD(SQL_TOKEN_EXTRACT); }
+
+FALSE {SQL_NEW_KEYWORD(SQL_TOKEN_FALSE); }
+FETCH {SQL_NEW_KEYWORD(SQL_TOKEN_FETCH); }
+FIRST {SQL_NEW_KEYWORD(SQL_TOKEN_FIRST); }
+FIRST_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_FIRST_VALUE); }
+FLOAT {SQL_NEW_KEYWORD(SQL_TOKEN_FLOAT); }
+FLOOR {SQL_NEW_KEYWORD(SQL_TOKEN_FLOOR); }
+FN {SQL_NEW_KEYWORD(SQL_TOKEN_FN); }
+FOLLOWING {SQL_NEW_KEYWORD(SQL_TOKEN_FOLLOWING); }
+FOR {SQL_NEW_KEYWORD(SQL_TOKEN_FOR); }
+FOREIGN {SQL_NEW_KEYWORD(SQL_TOKEN_FOREIGN); }
+FOUND {SQL_NEW_KEYWORD(SQL_TOKEN_FOUND); }
+FROM {SQL_NEW_KEYWORD(SQL_TOKEN_FROM); }
+FULL {SQL_NEW_KEYWORD(SQL_TOKEN_FULL); }
+FUSION {SQL_NEW_KEYWORD(SQL_TOKEN_FUSION); }
+
+GRANT {SQL_NEW_KEYWORD(SQL_TOKEN_GRANT); }
+GROUP {SQL_NEW_KEYWORD(SQL_TOKEN_GROUP); }
+
+HAVING {SQL_NEW_KEYWORD(SQL_TOKEN_HAVING); }
+HOUR {SQL_NEW_KEYWORD(SQL_TOKEN_HOUR); }
+
+IGNORE {SQL_NEW_KEYWORD(SQL_TOKEN_IGNORE); }
+IN {SQL_NEW_KEYWORD(SQL_TOKEN_IN); }
+INNER {SQL_NEW_KEYWORD(SQL_TOKEN_INNER); }
+INSERT {SQL_NEW_KEYWORD(SQL_TOKEN_INSERT); }
+INSTEAD {SQL_NEW_KEYWORD(SQL_TOKEN_INSTEAD); }
+INT(EGER)? {SQL_NEW_KEYWORD(SQL_TOKEN_INTEGER); }
+INTERSECT {SQL_NEW_KEYWORD(SQL_TOKEN_INTERSECT); }
+INTERVAL {SQL_NEW_KEYWORD(SQL_TOKEN_INTERVAL); }
+INTERSECTION {SQL_NEW_KEYWORD(SQL_TOKEN_INTERSECTION); }
+INTO {SQL_NEW_KEYWORD(SQL_TOKEN_INTO); }
+IS {SQL_NEW_KEYWORD(SQL_TOKEN_IS); }
+
+JOIN {SQL_NEW_KEYWORD(SQL_TOKEN_JOIN); }
+
+KEY {SQL_NEW_KEYWORD(SQL_TOKEN_KEY); }
+
+LAG {SQL_NEW_KEYWORD(SQL_TOKEN_LAG); }
+LARGE {SQL_NEW_KEYWORD(SQL_TOKEN_LARGE); }
+LAST {SQL_NEW_KEYWORD(SQL_TOKEN_LAST); }
+LAST_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_LAST_VALUE); }
+LCASE {SQL_NEW_KEYWORD(SQL_TOKEN_LCASE); }
+LEAD {SQL_NEW_KEYWORD(SQL_TOKEN_LEAD); }
+LEADING {SQL_NEW_KEYWORD(SQL_TOKEN_LEADING); }
+LEFT {SQL_NEW_KEYWORD(SQL_TOKEN_LEFT); }
+LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_LENGTH); }
+LIKE {SQL_NEW_KEYWORD(SQL_TOKEN_LIKE); }
+LIMIT {SQL_NEW_KEYWORD(SQL_TOKEN_LIMIT); }
+LN {SQL_NEW_KEYWORD(SQL_TOKEN_LN); }
+LOCAL {SQL_NEW_KEYWORD(SQL_TOKEN_LOCAL); }
+LOCATE {SQL_NEW_KEYWORD(SQL_TOKEN_LOCATE); }
+LOG {SQL_NEW_KEYWORD(SQL_TOKEN_LOG); }
+LOGF {SQL_NEW_KEYWORD(SQL_TOKEN_LOGF); }
+LOG10 {SQL_NEW_KEYWORD(SQL_TOKEN_LOG10); }
+LOWER {SQL_NEW_KEYWORD(SQL_TOKEN_LOWER); }
+LTRIM {SQL_NEW_KEYWORD(SQL_TOKEN_LTRIM); }
+
+MAX {SQL_NEW_KEYWORD(SQL_TOKEN_MAX); }
+MILLISECOND {SQL_NEW_KEYWORD(SQL_TOKEN_MILLISECOND); }
+MIN {SQL_NEW_KEYWORD(SQL_TOKEN_MIN); }
+MINUTE {SQL_NEW_KEYWORD(SQL_TOKEN_MINUTE); }
+MOD {SQL_NEW_KEYWORD(SQL_TOKEN_MOD); }
+MONTH {SQL_NEW_KEYWORD(SQL_TOKEN_MONTH); }
+MONTHNAME {SQL_NEW_KEYWORD(SQL_TOKEN_MONTHNAME); }
+
+NATIONAL {SQL_NEW_KEYWORD(SQL_TOKEN_NATIONAL); }
+NATURAL {SQL_NEW_KEYWORD(SQL_TOKEN_NATURAL); }
+NCHAR {SQL_NEW_KEYWORD(SQL_TOKEN_NCHAR); }
+NCLOB {SQL_NEW_KEYWORD(SQL_TOKEN_NCLOB); }
+NEW {SQL_NEW_KEYWORD(SQL_TOKEN_NEW); }
+NEXT {SQL_NEW_KEYWORD(SQL_TOKEN_NEXT); }
+NO {SQL_NEW_KEYWORD(SQL_TOKEN_NO); }
+NOT {SQL_NEW_KEYWORD(SQL_TOKEN_NOT); }
+NOW {SQL_NEW_KEYWORD(SQL_TOKEN_NOW); }
+NTH_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_NTH_VALUE); }
+NTILE {SQL_NEW_KEYWORD(SQL_TOKEN_NTILE); }
+NULL {SQL_NEW_KEYWORD(SQL_TOKEN_NULL); }
+NULLIF {SQL_NEW_KEYWORD(SQL_TOKEN_NULLIF); }
+NULLS {SQL_NEW_KEYWORD(SQL_TOKEN_NULLS); }
+NUMERIC {SQL_NEW_KEYWORD(SQL_TOKEN_NUMERIC); }
+
+OBJECT {SQL_NEW_KEYWORD(SQL_TOKEN_OBJECT); }
+OCTET_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_OCTET_LENGTH); }
+OF {SQL_NEW_KEYWORD(SQL_TOKEN_OF); }
+OFFSET {SQL_NEW_KEYWORD(SQL_TOKEN_OFFSET); }
+OJ {SQL_NEW_KEYWORD(SQL_TOKEN_OJ); }
+OLD {SQL_NEW_KEYWORD(SQL_TOKEN_OLD); }
+ON {SQL_NEW_KEYWORD(SQL_TOKEN_ON); }
+ONLY {SQL_NEW_KEYWORD(SQL_TOKEN_ONLY); }
+OPTION {SQL_NEW_KEYWORD(SQL_TOKEN_OPTION); }
+OR {SQL_NEW_KEYWORD(SQL_TOKEN_OR); }
+ORDER {SQL_NEW_KEYWORD(SQL_TOKEN_ORDER); }
+OTHERS {SQL_NEW_KEYWORD(SQL_TOKEN_OTHERS); }
+OUTER {SQL_NEW_KEYWORD(SQL_TOKEN_OUTER); }
+OVER {SQL_NEW_KEYWORD(SQL_TOKEN_OVER); }
+
+PARTITION {SQL_NEW_KEYWORD(SQL_TOKEN_PARTITION); }
+PERCENT_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENT_RANK); }
+PERCENTILE_CONT {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENTILE_CONT); }
+PERCENTILE_DISC {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENTILE_DISC); }
+PI {SQL_NEW_KEYWORD(SQL_TOKEN_PI); }
+POSITION {SQL_NEW_KEYWORD(SQL_TOKEN_POSITION); }
+POWER {SQL_NEW_KEYWORD(SQL_TOKEN_POWER); }
+PRECEDING {SQL_NEW_KEYWORD(SQL_TOKEN_PRECEDING); }
+PRECISION {SQL_NEW_KEYWORD(SQL_TOKEN_PRECISION); }
+PRIMARY {SQL_NEW_KEYWORD(SQL_TOKEN_PRIMARY); }
+PRIVILEGES {SQL_NEW_KEYWORD(SQL_TOKEN_PRIVILEGES); }
+PROCEDURE {SQL_NEW_KEYWORD(SQL_TOKEN_PROCEDURE); }
+PUBLIC {SQL_NEW_KEYWORD(SQL_TOKEN_PUBLIC); }
+
+QUARTER {SQL_NEW_KEYWORD(SQL_TOKEN_QUARTER); }
+
+RADIANS {SQL_NEW_KEYWORD(SQL_TOKEN_RADIANS); }
+RAND {SQL_NEW_KEYWORD(SQL_TOKEN_RAND); }
+RANGE {SQL_NEW_KEYWORD(SQL_TOKEN_RANGE); }
+RANK {SQL_NEW_KEYWORD(SQL_TOKEN_RANK); }
+REAL {SQL_NEW_KEYWORD(SQL_TOKEN_REAL); }
+REFERENCES {SQL_NEW_KEYWORD(SQL_TOKEN_REFERENCES); }
+REFERENCING {SQL_NEW_KEYWORD(SQL_TOKEN_REFERENCING); }
+REPEAT {SQL_NEW_KEYWORD(SQL_TOKEN_REPEAT); }
+REPLACE {SQL_NEW_KEYWORD(SQL_TOKEN_REPLACE); }
+RESPECT {SQL_NEW_KEYWORD(SQL_TOKEN_RESPECT); }
+ROLLBACK {SQL_NEW_KEYWORD(SQL_TOKEN_ROLLBACK); }
+ROUND {SQL_NEW_KEYWORD(SQL_TOKEN_ROUND); }
+ROUNDMAGIC {SQL_NEW_KEYWORD(SQL_TOKEN_ROUNDMAGIC); }
+ROW {SQL_NEW_KEYWORD(SQL_TOKEN_ROW); }
+ROWS {SQL_NEW_KEYWORD(SQL_TOKEN_ROWS); }
+ROW_NUMBER {SQL_NEW_KEYWORD(SQL_TOKEN_ROW_NUMBER); }
+RIGHT {SQL_NEW_KEYWORD(SQL_TOKEN_RIGHT); }
+RTRIM {SQL_NEW_KEYWORD(SQL_TOKEN_RTRIM); }
+
+SCHEMA {SQL_NEW_KEYWORD(SQL_TOKEN_SCHEMA); }
+SECOND {SQL_NEW_KEYWORD(SQL_TOKEN_SECOND); }
+SELECT {SQL_NEW_KEYWORD(SQL_TOKEN_SELECT); }
+SET {SQL_NEW_KEYWORD(SQL_TOKEN_SET); }
+SIZE {SQL_NEW_KEYWORD(SQL_TOKEN_SIZE); }
+SIGN {SQL_NEW_KEYWORD(SQL_TOKEN_SIGN); }
+SIN {SQL_NEW_KEYWORD(SQL_TOKEN_SIN); }
+SMALLINT {SQL_NEW_KEYWORD(SQL_TOKEN_SMALLINT); }
+SOME {SQL_NEW_KEYWORD(SQL_TOKEN_SOME); }
+SOUNDEX {SQL_NEW_KEYWORD(SQL_TOKEN_SOUNDEX); }
+SPACE {SQL_NEW_KEYWORD(SQL_TOKEN_SPACE); }
+SQRT {SQL_NEW_KEYWORD(SQL_TOKEN_SQRT); }
+STDDEV_POP {SQL_NEW_KEYWORD(SQL_TOKEN_STDDEV_POP); }
+STDDEV_SAMP {SQL_NEW_KEYWORD(SQL_TOKEN_STDDEV_SAMP); }
+STATEMENT {SQL_NEW_KEYWORD(SQL_TOKEN_STATEMENT); }
+SUBSTRING {SQL_NEW_KEYWORD(SQL_TOKEN_SUBSTRING); }
+SUM {SQL_NEW_KEYWORD(SQL_TOKEN_SUM); }
+SESSION_USER {SQL_NEW_KEYWORD(SQL_TOKEN_SESSION_USER); }
+SYSTEM_USER {SQL_NEW_KEYWORD(SQL_TOKEN_SYSTEM_USER); }
+
+TABLE {SQL_NEW_KEYWORD(SQL_TOKEN_TABLE); }
+TAN {SQL_NEW_KEYWORD(SQL_TOKEN_TAN); }
+THEN {SQL_NEW_KEYWORD(SQL_TOKEN_THEN); }
+TIES {SQL_NEW_KEYWORD(SQL_TOKEN_TIES); }
+TIME {SQL_NEW_KEYWORD(SQL_TOKEN_TIME); }
+TIMESTAMP {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMP); }
+TIMESTAMPADD {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMPADD); }
+TIMESTAMPDIFF {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMPDIFF); }
+TIMEVALUE {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEVALUE); }
+TIMEZONE_HOUR {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEZONE_HOUR); }
+TIMEZONE_MINUTE {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEZONE_MINUTE); }
+TO {SQL_NEW_KEYWORD(SQL_TOKEN_TO); }
+TRAILING {SQL_NEW_KEYWORD(SQL_TOKEN_TRAILING); }
+TRANSLATE {SQL_NEW_KEYWORD(SQL_TOKEN_TRANSLATE); }
+TRIGGER {SQL_NEW_KEYWORD(SQL_TOKEN_TRIGGER); }
+TRIM {SQL_NEW_KEYWORD(SQL_TOKEN_TRIM); }
+TRUE {SQL_NEW_KEYWORD(SQL_TOKEN_TRUE); }
+TRUNCATE {SQL_NEW_KEYWORD(SQL_TOKEN_TRUNCATE); }
+TS {SQL_NEW_KEYWORD(SQL_TOKEN_TS); }
+T {SQL_NEW_KEYWORD(SQL_TOKEN_T); }
+
+UCASE {SQL_NEW_KEYWORD(SQL_TOKEN_UCASE); }
+UNBOUNDED {SQL_NEW_KEYWORD(SQL_TOKEN_UNBOUNDED); }
+UNION {SQL_NEW_KEYWORD(SQL_TOKEN_UNION); }
+UNIQUE {SQL_NEW_KEYWORD(SQL_TOKEN_UNIQUE); }
+UNKNOWN {SQL_NEW_KEYWORD(SQL_TOKEN_UNKNOWN); }
+UPDATE {SQL_NEW_KEYWORD(SQL_TOKEN_UPDATE); }
+UPPER {SQL_NEW_KEYWORD(SQL_TOKEN_UPPER); }
+USAGE {SQL_NEW_KEYWORD(SQL_TOKEN_USAGE); }
+USER {SQL_NEW_KEYWORD(SQL_TOKEN_USER); }
+USING {SQL_NEW_KEYWORD(SQL_TOKEN_USING); }
+
+VARBINARY {SQL_NEW_KEYWORD(SQL_TOKEN_VARBINARY); }
+VARCHAR {SQL_NEW_KEYWORD(SQL_TOKEN_VARCHAR); }
+VARYING {SQL_NEW_KEYWORD(SQL_TOKEN_VARYING); }
+VAR_POP {SQL_NEW_KEYWORD(SQL_TOKEN_VAR_POP); }
+VAR_SAMP {SQL_NEW_KEYWORD(SQL_TOKEN_VAR_SAMP); }
+VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_VALUE); }
+VALUES {SQL_NEW_KEYWORD(SQL_TOKEN_VALUES); }
+VIEW {SQL_NEW_KEYWORD(SQL_TOKEN_VIEW); }
+
+WEEK {SQL_NEW_KEYWORD(SQL_TOKEN_WEEK); }
+WEEKDAY {SQL_NEW_KEYWORD(SQL_TOKEN_WEEKDAY); }
+WHEN {SQL_NEW_KEYWORD(SQL_TOKEN_WHEN); }
+WHERE {SQL_NEW_KEYWORD(SQL_TOKEN_WHERE); }
+WITH {SQL_NEW_KEYWORD(SQL_TOKEN_WITH); }
+WITHIN {SQL_NEW_KEYWORD(SQL_TOKEN_WITHIN); }
+WITHOUT {SQL_NEW_KEYWORD(SQL_TOKEN_WITHOUT); }
+WORK {SQL_NEW_KEYWORD(SQL_TOKEN_WORK); }
+
+YEAR {SQL_NEW_KEYWORD(SQL_TOKEN_YEAR); }
+YEARDAY {SQL_NEW_KEYWORD(SQL_TOKEN_YEARDAY); }
+
+ZONE {SQL_NEW_KEYWORD(SQL_TOKEN_ZONE); }
+
+"<" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Less);return SQL_LESS;}
+">" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Great);return SQL_GREAT;}
+"=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Equal);return SQL_EQUAL;}
+"<=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::LessEq);return SQL_LESSEQ;}
+">=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::GreatEq);return SQL_GREATEQ;}
+"<>" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::NotEqual);return SQL_NOTEQUAL;}
+"!=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::NotEqual);return SQL_NOTEQUAL;}
+"||" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Concat);return SQL_CONCAT;}
+
+
+[-+*/:(),.;?{}] { return SQLyytext[0]; }
+
+
+<SQL>[A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375][A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375_0-9]* {return gatherName( SQLyytext);}
+
+<SQL>([0-9]+) {SQL_NEW_INTNUM; }
+
+<SQL>("."[0-9]*) |
+<SQL>([0-9]+"."[0-9]*) |
+<SQL>[0-9]+[eE][+-]?[0-9]+ |
+<SQL>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
+<SQL>"."[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE>[A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375][A-Za-z0-9_%.,*?\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375]* {return gatherNamePre(SQLyytext);}
+
+<PREDICATE_GER,PREDICATE_ENG>([0-9]+) {SQL_NEW_INTNUM; }
+<PREDICATE_ENG>([0-9]{1,3}(","[0-9]{3})+) {SQL_NEW_INTNUM; }
+<PREDICATE_GER>([0-9]{1,3}("."[0-9]{3})+) {SQL_NEW_INTNUM; }
+
+<PREDICATE_ENG>([0-9]+"."[0-9]+) |
+<PREDICATE_ENG>([0-9]{1,3}(","[0-9]{3})+"."[0-9]+) |
+<PREDICATE_ENG>("."[0-9]+) {SQL_NEW_APPROXNUM; }
+<PREDICATE_ENG>[0-9]+[eE][+-]?[0-9]+ |
+<PREDICATE_ENG>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
+<PREDICATE_ENG>"."[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER>([0-9]+","[0-9]+) |
+<PREDICATE_GER>([0-9]{1,3}("."[0-9]{3})+","[0-9]+) |
+<PREDICATE_GER>(","[0-9]+) {SQL_NEW_APPROXNUM; }
+<PREDICATE_GER>[0-9]+[eE][+-]?[0-9]+ |
+<PREDICATE_GER>[0-9]+","[0-9]*[eE][+-]?[0-9]+ |
+<PREDICATE_GER>","[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER,PREDICATE_ENG>[0-9.,][A-Za-z0-9_.,%]* {return gatherNamePre(SQLyytext);}
+
+<SQL>\" { return gatherString('\"',0); }
+<SQL>` { return gatherString('`' ,0); }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE,SQL>"[" { return gatherString(']' ,0);}
+
+\' { return gatherString('\'',1); }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE># { return gatherString('#' ,2); }
+
+<DATE>[0-9]{1,4}[^ ]*[0-9] |
+<DATE>[0-9]{1,4}[^ ]*[0-9][ ][0-9]{1,4}[^ ]*[0-9] { SQL_NEW_DATE; }
+
+<STRING>["-""+""*""/"":""("")"",""."";""?""{""}"] { return SQLyytext[0]; } /* */
+<STRING>"[" { return gatherString(']' ,0); }
+<STRING>[^ ':["?"]* { return gatherNamePre(SQLyytext); }
+
+\n {}
+
+[ \t\r]+ {}
+
+"--".*$ {}
+
+. {YY_FATAL_ERROR("Invalid symbol"); return SQL_TOKEN_INVALIDSYMBOL;}
+
+%%
+
+// Kludge around a bug (well, Posix incompatibility) in flex 2.5.x
+// http://bugs.debian.org/cgi-bin/bugreport.cgi?archive=no&bug=189332
+#if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5
+
+ #ifndef YY_FLUSH_BUFFER
+ #define YY_FLUSH_BUFFER SQLyy_flush_buffer(YY_CURRENT_BUFFER )
+ #endif
+
+ #ifndef yytext_ptr
+ #define yytext_ptr SQLyytext
+ #endif
+
+#endif
+
+// Versions of flex apparently differ in whether input() resp. yyinput() returns
+// zero or EOF upon end of file:
+inline bool checkeof(int c) { return c == 0 || c == EOF; }
+
+/*
+ * Read SQL string literal
+ * Valid strings:
+ * '' 'a string' 'quote '' within string'
+ * "" "a string" "quote "" within string"
+ * nTyp == 0 -> SQLNodeType::Name
+ * nTyp == 1 -> SQLNodeType::String
+ * nTyp == 2 -> SQLNodeType::AccessDate
+ */
+sal_Int32 gatherString(int delim, sal_Int32 nTyp)
+{
+ int ch;
+ OStringBuffer sBuffer(256);
+
+ assert(nTyp == 0 || nTyp == 1 || nTyp == 2);
+
+ while (!checkeof(ch = yyinput()))
+ {
+ if (ch == delim)
+ {
+ if ((ch = yyinput()) != delim)
+ {
+ if (!checkeof(ch))
+ unput(ch);
+
+ switch(nTyp)
+ {
+ case 0:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ return SQL_TOKEN_NAME;
+ case 1:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::String);
+ return SQL_TOKEN_STRING;
+ case 2:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::AccessDate);
+ return SQL_TOKEN_ACCESS_DATE;
+ }
+ }
+ else
+ {
+ sBuffer.append(static_cast<char>(ch));
+ }
+
+ }
+ else if (nTyp == 2 && (ch == '\r' || ch == '\n') )
+ break;
+ else
+ {
+ sBuffer.append(static_cast<char>(ch));
+ }
+ }
+ YY_FATAL_ERROR("Unterminated name string");
+ return SQL_TOKEN_INVALIDSYMBOL;
+}
+
+sal_Int32 mapEnumToToken(IParseContext::InternationalKeyCode _eKeyCode )
+{
+ sal_Int32 nTokenID = 0;
+ switch( _eKeyCode )
+ {
+ case IParseContext::InternationalKeyCode::Like: nTokenID = SQL_TOKEN_LIKE; break;
+ case IParseContext::InternationalKeyCode::Not: nTokenID = SQL_TOKEN_NOT; break;
+ case IParseContext::InternationalKeyCode::Null: nTokenID = SQL_TOKEN_NULL; break;
+ case IParseContext::InternationalKeyCode::True: nTokenID = SQL_TOKEN_TRUE; break;
+ case IParseContext::InternationalKeyCode::False: nTokenID = SQL_TOKEN_FALSE; break;
+ case IParseContext::InternationalKeyCode::Is: nTokenID = SQL_TOKEN_IS; break;
+ case IParseContext::InternationalKeyCode::Between: nTokenID = SQL_TOKEN_BETWEEN; break;
+ case IParseContext::InternationalKeyCode::Or: nTokenID = SQL_TOKEN_OR; break;
+ case IParseContext::InternationalKeyCode::And: nTokenID = SQL_TOKEN_AND; break;
+ case IParseContext::InternationalKeyCode::Avg: nTokenID = SQL_TOKEN_AVG; break;
+ case IParseContext::InternationalKeyCode::Count: nTokenID = SQL_TOKEN_COUNT; break;
+ case IParseContext::InternationalKeyCode::Max: nTokenID = SQL_TOKEN_MAX; break;
+ case IParseContext::InternationalKeyCode::Min: nTokenID = SQL_TOKEN_MIN; break;
+ case IParseContext::InternationalKeyCode::Sum: nTokenID = SQL_TOKEN_SUM; break;
+ case IParseContext::InternationalKeyCode::Every: nTokenID = SQL_TOKEN_EVERY; break;
+ case IParseContext::InternationalKeyCode::Any: nTokenID = SQL_TOKEN_ANY; break;
+ case IParseContext::InternationalKeyCode::Some: nTokenID = SQL_TOKEN_SOME; break;
+ case IParseContext::InternationalKeyCode::StdDevPop: nTokenID = SQL_TOKEN_STDDEV_POP; break;
+ case IParseContext::InternationalKeyCode::StdDevSamp: nTokenID = SQL_TOKEN_STDDEV_SAMP; break;
+ case IParseContext::InternationalKeyCode::VarSamp: nTokenID = SQL_TOKEN_VAR_SAMP; break;
+ case IParseContext::InternationalKeyCode::VarPop: nTokenID = SQL_TOKEN_VAR_POP; break;
+ case IParseContext::InternationalKeyCode::Collect: nTokenID = SQL_TOKEN_COLLECT; break;
+ case IParseContext::InternationalKeyCode::Fusion: nTokenID = SQL_TOKEN_FUSION; break;
+ case IParseContext::InternationalKeyCode::Intersection: nTokenID = SQL_TOKEN_INTERSECTION; break;
+ default:
+ OSL_FAIL( "mapEnumToToken: unsupported key!" );
+ }
+ return nTokenID;
+}
+/*
+ * Read SQL Name literal
+ * Valid Names or international keywords:
+ * As we have international keywords, we test first on them
+ */
+sal_Int32 gatherName(const char* text)
+{
+ sal_Int32 nToken;
+ OSL_ENSURE(xxx_pGLOBAL_SQLSCAN,"You forgot to set the scanner!");
+ IParseContext::InternationalKeyCode eKeyCode = xxx_pGLOBAL_SQLSCAN->getInternationalTokenID(text);
+ switch (eKeyCode)
+ {
+ case IParseContext::InternationalKeyCode::Like:
+ case IParseContext::InternationalKeyCode::Not:
+ case IParseContext::InternationalKeyCode::Null:
+ case IParseContext::InternationalKeyCode::True:
+ case IParseContext::InternationalKeyCode::False:
+ case IParseContext::InternationalKeyCode::Is:
+ case IParseContext::InternationalKeyCode::Between:
+ case IParseContext::InternationalKeyCode::Or:
+ case IParseContext::InternationalKeyCode::And:
+ case IParseContext::InternationalKeyCode::Count:
+ case IParseContext::InternationalKeyCode::Avg:
+ case IParseContext::InternationalKeyCode::Max:
+ case IParseContext::InternationalKeyCode::Min:
+ case IParseContext::InternationalKeyCode::Sum:
+ case IParseContext::InternationalKeyCode::Every:
+ case IParseContext::InternationalKeyCode::Any:
+ case IParseContext::InternationalKeyCode::Some:
+ case IParseContext::InternationalKeyCode::StdDevPop:
+ case IParseContext::InternationalKeyCode::StdDevSamp:
+ case IParseContext::InternationalKeyCode::VarSamp:
+ case IParseContext::InternationalKeyCode::VarPop:
+ case IParseContext::InternationalKeyCode::Collect:
+ case IParseContext::InternationalKeyCode::Fusion:
+ case IParseContext::InternationalKeyCode::Intersection:
+ nToken = mapEnumToToken(eKeyCode);
+ SQL_NEW_KEYWORD(nToken);
+ break;
+ default:
+ SQL_NEW_NODE(OUString(text,strlen(text),RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ return SQL_TOKEN_NAME;
+ }
+}
+/**
+ Read SQL Name literal for predicate check
+ Valid Names or international keywords:
+ As we have international keywords, we test first on them
+*/
+sal_Int32 gatherNamePre(const char* text)
+{
+ sal_Int32 nToken;
+ OSL_ENSURE(xxx_pGLOBAL_SQLSCAN,"You forgot to set the scanner!");
+ IParseContext::InternationalKeyCode eKeyCode = xxx_pGLOBAL_SQLSCAN->getInternationalTokenID(text);
+ switch (eKeyCode)
+ {
+ case IParseContext::InternationalKeyCode::Like:
+ case IParseContext::InternationalKeyCode::Not:
+ case IParseContext::InternationalKeyCode::Null:
+ case IParseContext::InternationalKeyCode::True:
+ case IParseContext::InternationalKeyCode::False:
+ case IParseContext::InternationalKeyCode::Is:
+ case IParseContext::InternationalKeyCode::Between:
+ case IParseContext::InternationalKeyCode::Or:
+ case IParseContext::InternationalKeyCode::And:
+ case IParseContext::InternationalKeyCode::Count:
+ case IParseContext::InternationalKeyCode::Avg:
+ case IParseContext::InternationalKeyCode::Max:
+ case IParseContext::InternationalKeyCode::Min:
+ case IParseContext::InternationalKeyCode::Sum:
+ case IParseContext::InternationalKeyCode::Every:
+ case IParseContext::InternationalKeyCode::Any:
+ case IParseContext::InternationalKeyCode::Some:
+ case IParseContext::InternationalKeyCode::StdDevPop:
+ case IParseContext::InternationalKeyCode::StdDevSamp:
+ case IParseContext::InternationalKeyCode::VarSamp:
+ case IParseContext::InternationalKeyCode::VarPop:
+ case IParseContext::InternationalKeyCode::Collect:
+ case IParseContext::InternationalKeyCode::Fusion:
+ case IParseContext::InternationalKeyCode::Intersection:
+ nToken = mapEnumToToken(eKeyCode);
+ SQL_NEW_KEYWORD(nToken);
+ break;
+ default:
+ // we need a special handling for parameter
+ {
+ OString sStmt = xxx_pGLOBAL_SQLSCAN->getStatement();
+ sal_Int32 nLength = strlen(text);
+ sal_Int32 nPos = xxx_pGLOBAL_SQLSCAN->GetCurrentPos() - nLength - 2;
+ if (sStmt.getStr()[nPos] == ':')
+ {
+ SQL_NEW_NODE(OUString(text,nLength,RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ nToken = SQL_TOKEN_NAME;
+ }
+ else
+ {
+ SQL_NEW_NODE(OUString(text,nLength,RTL_TEXTENCODING_UTF8), SQLNodeType::String);
+ nToken = SQL_TOKEN_STRING;
+ }
+ }
+ }
+ return nToken;
+}
+
+using namespace connectivity;
+
+static bool IN_SQLyyerror;
+//------------------------------------------------------------------------------
+OSQLScanner::OSQLScanner()
+ : m_pContext(nullptr)
+ , m_nCurrentPos(0)
+ , m_bInternational(false)
+ , m_nRule(0) // 0 is INITIAL
+{
+ IN_SQLyyerror = false;
+}
+
+//------------------------------------------------------------------------------
+OSQLScanner::~OSQLScanner()
+{
+}
+//------------------------------------------------------------------------------
+void OSQLScanner::SQLyyerror(char const *fmt)
+{
+
+ if(IN_SQLyyerror)
+ return;
+ IN_SQLyyerror = true;
+
+ OSL_ENSURE(m_pContext, "OSQLScanner::SQLyyerror: No Context set");
+ m_sErrorMessage = OUString(fmt,strlen(fmt),RTL_TEXTENCODING_UTF8);
+ if (m_nCurrentPos < m_sStatement.getLength())
+ {
+ m_sErrorMessage += ": ";
+
+ OUString aError;
+ OUStringBuffer Buffer(256);
+
+ int ch = SQLyytext ? (SQLyytext[0] == 0 ? ' ' : SQLyytext[0]): ' ';
+ Buffer.append((sal_Unicode)ch);
+ while (!checkeof(ch = yyinput()))
+ {
+ if (ch == ' ')
+ {
+ if ((ch = yyinput()) != ' ')
+ {
+ if (!checkeof(ch))
+ unput(ch);
+ }
+ aError = Buffer.makeStringAndClear();
+ break;
+ }
+ else
+ {
+ Buffer.append((sal_Unicode)ch);
+ }
+ }
+ m_sErrorMessage += aError;
+ }
+ IN_SQLyyerror = false;
+ YY_FLUSH_BUFFER;
+}
+
+//------------------------------------------------------------------------------
+void OSQLScanner::prepareScan(const OUString & rNewStatement, const IParseContext* pContext, bool bInternational)
+{
+ YY_FLUSH_BUFFER;
+ BEGIN(m_nRule);
+
+ m_sErrorMessage = OUString();
+ m_sStatement = OUStringToOString(rNewStatement, RTL_TEXTENCODING_UTF8);
+ m_nCurrentPos = 0;
+ m_bInternational = bInternational;
+ m_pContext = pContext;
+}
+
+//------------------------------------------------------------------------------
+sal_Int32 OSQLScanner::SQLyygetc(void)
+{
+ sal_Int32 nPos = (m_nCurrentPos >= m_sStatement.getLength()) ? EOF : m_sStatement.getStr()[m_nCurrentPos];
+ m_nCurrentPos++;
+ return nPos;
+}
+
+//------------------------------------------------------------------------------
+IParseContext::InternationalKeyCode OSQLScanner::getInternationalTokenID(const char* sToken) const
+{
+ OSL_ENSURE(m_pContext, "OSQLScanner::getInternationalTokenID: No Context set");
+ return (m_bInternational) ? m_pContext->getIntlKeyCode(OString(sToken) ) : IParseContext::InternationalKeyCode::None;
+}
+sal_Int32 OSQLScanner::GetGERRule() { return PREDICATE_GER; }
+sal_Int32 OSQLScanner::GetENGRule() { return PREDICATE_ENG; }
+sal_Int32 OSQLScanner::GetSQLRule() { return SQL; }
+sal_Int32 OSQLScanner::GetDATERule() { return DATE; }
+sal_Int32 OSQLScanner::GetSTRINGRule() { return STRING; }
+void OSQLScanner::setScanner(bool _bNull)
+{
+ xxx_pGLOBAL_SQLSCAN = _bNull ? nullptr : this;
+}
+sal_Int32 OSQLScanner::SQLlex()
+{
+ return SQLyylex();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/parse/sqliterator.cxx b/connectivity/source/parse/sqliterator.cxx
new file mode 100644
index 000000000..fcebd2879
--- /dev/null
+++ b/connectivity/source/parse/sqliterator.cxx
@@ -0,0 +1,2117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sdbcx/VTable.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <sqlbison.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#ifdef SQL_TEST_PARSETREEITERATOR
+#include <iostream>
+#endif
+#include <connectivity/PColumn.hxx>
+#include <tools/diagnose_ex.h>
+#include <TConnection.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+
+#include <iterator>
+#include <memory>
+
+using namespace ::comphelper;
+using namespace ::connectivity;
+using namespace ::connectivity::sdbcx;
+using namespace ::dbtools;
+using namespace ::connectivity::parse;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+
+namespace connectivity
+{
+ struct OSQLParseTreeIteratorImpl
+ {
+ std::vector< TNodePair > m_aJoinConditions;
+ Reference< XConnection > m_xConnection;
+ Reference< XDatabaseMetaData > m_xDatabaseMetaData;
+ Reference< XNameAccess > m_xTableContainer;
+ Reference< XNameAccess > m_xQueryContainer;
+
+ std::shared_ptr< OSQLTables > m_pTables; // all tables which participate in the SQL statement
+ std::shared_ptr< OSQLTables > m_pSubTables; // all tables from sub queries not the tables from the select tables
+ std::shared_ptr< QueryNameSet > m_pForbiddenQueryNames;
+
+ TraversalParts m_nIncludeMask;
+
+ bool m_bIsCaseSensitive;
+
+ OSQLParseTreeIteratorImpl( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables )
+ :m_xConnection( _rxConnection )
+ ,m_nIncludeMask( TraversalParts::All )
+ ,m_bIsCaseSensitive( true )
+ {
+ OSL_PRECOND( m_xConnection.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" );
+ m_xDatabaseMetaData = m_xConnection->getMetaData();
+
+ m_bIsCaseSensitive = m_xDatabaseMetaData.is() && m_xDatabaseMetaData->supportsMixedCaseQuotedIdentifiers();
+ m_pTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive );
+ m_pSubTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive );
+
+ m_xTableContainer = _rxTables;
+
+ DatabaseMetaData aMetaData( m_xConnection );
+ if ( aMetaData.supportsSubqueriesInFrom() )
+ {
+ // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection
+ // service
+ Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY );
+ if ( xSuppQueries.is() )
+ m_xQueryContainer = xSuppQueries->getQueries();
+ }
+ }
+
+ public:
+ bool isQueryAllowed( const OUString& _rQueryName )
+ {
+ if ( !m_pForbiddenQueryNames )
+ return true;
+ if ( m_pForbiddenQueryNames->find( _rQueryName ) == m_pForbiddenQueryNames->end() )
+ return true;
+ return false;
+ }
+ };
+
+ namespace {
+
+ /** helper class for temporarily adding a query name to a list of forbidden query names
+ */
+ class ForbidQueryName
+ {
+ std::shared_ptr< QueryNameSet >& m_rpAllForbiddenNames;
+ OUString m_sForbiddenQueryName;
+
+ public:
+ ForbidQueryName( OSQLParseTreeIteratorImpl& _rIteratorImpl, const OUString& _rForbiddenQueryName )
+ :m_rpAllForbiddenNames( _rIteratorImpl.m_pForbiddenQueryNames )
+ ,m_sForbiddenQueryName( _rForbiddenQueryName )
+ {
+ if ( !m_rpAllForbiddenNames )
+ m_rpAllForbiddenNames = std::make_shared<QueryNameSet>();
+ m_rpAllForbiddenNames->insert( m_sForbiddenQueryName );
+ }
+
+ ~ForbidQueryName()
+ {
+ m_rpAllForbiddenNames->erase( m_sForbiddenQueryName );
+ }
+ };
+
+ }
+}
+
+OSQLParseTreeIterator::OSQLParseTreeIterator(const Reference< XConnection >& _rxConnection,
+ const Reference< XNameAccess >& _rxTables,
+ const OSQLParser& _rParser )
+ :m_rParser( _rParser )
+ ,m_pImpl( new OSQLParseTreeIteratorImpl( _rxConnection, _rxTables ) )
+{
+ setParseTree(nullptr);
+}
+
+
+OSQLParseTreeIterator::OSQLParseTreeIterator( const OSQLParseTreeIterator& _rParentIterator, const OSQLParser& _rParser, const OSQLParseNode* pRoot )
+ :m_rParser( _rParser )
+ ,m_pImpl( new OSQLParseTreeIteratorImpl( _rParentIterator.m_pImpl->m_xConnection, _rParentIterator.m_pImpl->m_xTableContainer ) )
+{
+ m_pImpl->m_pForbiddenQueryNames = _rParentIterator.m_pImpl->m_pForbiddenQueryNames;
+ setParseTree( pRoot );
+}
+
+
+OSQLParseTreeIterator::~OSQLParseTreeIterator()
+{
+ dispose();
+}
+
+
+const OSQLTables& OSQLParseTreeIterator::getTables() const
+{
+ return *m_pImpl->m_pTables;
+}
+
+
+bool OSQLParseTreeIterator::isCaseSensitive() const
+{
+ return m_pImpl->m_bIsCaseSensitive;
+}
+
+
+void OSQLParseTreeIterator::dispose()
+{
+ m_aSelectColumns = nullptr;
+ m_aGroupColumns = nullptr;
+ m_aOrderColumns = nullptr;
+ m_aParameters = nullptr;
+ m_pImpl->m_xTableContainer = nullptr;
+ m_pImpl->m_xDatabaseMetaData = nullptr;
+ m_aCreateColumns = nullptr;
+ m_pImpl->m_pTables->clear();
+ m_pImpl->m_pSubTables->clear();
+}
+
+void OSQLParseTreeIterator::setParseTree(const OSQLParseNode * pNewParseTree)
+{
+ m_pImpl->m_pTables->clear();
+ m_pImpl->m_pSubTables->clear();
+
+ m_aSelectColumns = new OSQLColumns();
+ m_aGroupColumns = new OSQLColumns();
+ m_aOrderColumns = new OSQLColumns();
+ m_aParameters = new OSQLColumns();
+ m_aCreateColumns = new OSQLColumns();
+
+ m_pParseTree = pNewParseTree;
+ if (!m_pParseTree)
+ {
+ m_eStatementType = OSQLStatementType::Unknown;
+ return;
+ }
+
+ // If m_pParseTree, but no connection then return
+ if ( !m_pImpl->m_xTableContainer.is() )
+ return;
+
+ m_xErrors.reset();
+
+
+ // Determine statement type ...
+ if (SQL_ISRULE(m_pParseTree,select_statement) || SQL_ISRULE(m_pParseTree,union_statement) )
+ {
+ m_eStatementType = OSQLStatementType::Select;
+ }
+ else if (SQL_ISRULE(m_pParseTree,insert_statement))
+ {
+ m_eStatementType = OSQLStatementType::Insert;
+ }
+ else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
+ {
+ m_eStatementType = OSQLStatementType::Update;
+ }
+ else if (SQL_ISRULE(m_pParseTree,delete_statement_searched))
+ {
+ m_eStatementType = OSQLStatementType::Delete;
+ }
+ else if (m_pParseTree->count() == 3 && SQL_ISRULE(m_pParseTree->getChild(1),odbc_call_spec))
+ {
+ m_eStatementType = OSQLStatementType::OdbcCall;
+ }
+ else if (SQL_ISRULE(m_pParseTree->getChild(0),base_table_def))
+ {
+ m_eStatementType = OSQLStatementType::CreateTable;
+ m_pParseTree = m_pParseTree->getChild(0);
+ }
+ else
+ {
+ m_eStatementType = OSQLStatementType::Unknown;
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+}
+
+
+namespace
+{
+
+ void impl_getRowString( const Reference< XRow >& _rxRow, const sal_Int32 _nColumnIndex, OUString& _out_rString )
+ {
+ _out_rString = _rxRow->getString( _nColumnIndex );
+ if ( _rxRow->wasNull() )
+ _out_rString.clear();
+ }
+
+
+ OUString lcl_findTableInMetaData(
+ const Reference< XDatabaseMetaData >& _rxDBMeta, const OUString& _rCatalog,
+ const OUString& _rSchema, const OUString& _rTableName )
+ {
+ OUString sComposedName;
+
+ static constexpr OUStringLiteral s_sWildcard = u"%" ;
+
+ // we want all catalogues, all schemas, all tables
+ Sequence< OUString > sTableTypes { "VIEW", "TABLE", s_sWildcard }; // this last one just to be sure to include anything else...
+
+ if ( _rxDBMeta.is() )
+ {
+ sComposedName.clear();
+
+ Reference< XResultSet> xRes = _rxDBMeta->getTables(
+ !_rCatalog.isEmpty() ? Any( _rCatalog ) : Any(), !_rSchema.isEmpty() ? _rSchema : s_sWildcard, _rTableName, sTableTypes );
+
+ Reference< XRow > xCurrentRow( xRes, UNO_QUERY );
+ if ( xCurrentRow.is() && xRes->next() )
+ {
+ OUString sCatalog, sSchema, sName;
+
+ impl_getRowString( xCurrentRow, 1, sCatalog );
+ impl_getRowString( xCurrentRow, 2, sSchema );
+ impl_getRowString( xCurrentRow, 3, sName );
+
+ sComposedName = ::dbtools::composeTableName(
+ _rxDBMeta,
+ sCatalog,
+ sSchema,
+ sName,
+ false,
+ ::dbtools::EComposeRule::InDataManipulation
+ );
+ }
+ }
+ return sComposedName;
+ }
+}
+
+
+void OSQLParseTreeIterator::impl_getQueryParameterColumns( const OSQLTable& _rQuery )
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
+ // parameters not to be included in the traversal
+ return;
+
+ ::rtl::Reference pSubQueryParameterColumns( new OSQLColumns() );
+
+ // get the command and the EscapeProcessing properties from the sub query
+ OUString sSubQueryCommand;
+ bool bEscapeProcessing = false;
+ try
+ {
+ Reference< XPropertySet > xQueryProperties( _rQuery, UNO_QUERY_THROW );
+ OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sSubQueryCommand );
+ OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+
+ // parse the sub query
+ do {
+
+ if ( !bEscapeProcessing || ( sSubQueryCommand.isEmpty() ) )
+ break;
+
+ OUString sError;
+ std::unique_ptr< OSQLParseNode > pSubQueryNode( const_cast< OSQLParser& >( m_rParser ).parseTree( sError, sSubQueryCommand ) );
+ if (!pSubQueryNode)
+ break;
+
+ OSQLParseTreeIterator aSubQueryIterator( *this, m_rParser, pSubQueryNode.get() );
+ aSubQueryIterator.impl_traverse( TraversalParts::Parameters | TraversalParts::SelectColumns );
+ // SelectColumns might also contain parameters #i77635#
+ pSubQueryParameterColumns = aSubQueryIterator.getParameters();
+ aSubQueryIterator.dispose();
+
+ } while ( false );
+
+ // copy the parameters of the sub query to our own parameter array
+ m_aParameters->insert( m_aParameters->end(), pSubQueryParameterColumns->begin(), pSubQueryParameterColumns->end() );
+}
+
+
+OSQLTable OSQLParseTreeIterator::impl_locateRecordSource( const OUString& _rComposedName )
+{
+ if ( _rComposedName.isEmpty() )
+ {
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" );
+ return OSQLTable();
+ }
+
+ OSQLTable aReturn;
+ OUString sComposedName( _rComposedName );
+
+ try
+ {
+ OUString sCatalog, sSchema, sName;
+ qualifiedNameComponents( m_pImpl->m_xDatabaseMetaData, sComposedName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation );
+
+ // check whether there is a query with the given name
+ bool bQueryDoesExist = m_pImpl->m_xQueryContainer.is() && m_pImpl->m_xQueryContainer->hasByName( sComposedName );
+
+ // check whether the table container contains an object with the given name
+ if ( !bQueryDoesExist && !m_pImpl->m_xTableContainer->hasByName( sComposedName ) )
+ sComposedName = lcl_findTableInMetaData( m_pImpl->m_xDatabaseMetaData, sCatalog, sSchema, sName );
+ bool bTableDoesExist = m_pImpl->m_xTableContainer->hasByName( sComposedName );
+
+ // now obtain the object
+
+ // if we're creating a table, and there already is a table or query with the same name,
+ // this is worth an error
+ if ( OSQLStatementType::CreateTable == m_eStatementType )
+ {
+ if ( bQueryDoesExist )
+ impl_appendError( IParseContext::ErrorCode::InvalidQueryExist, &sName );
+ else if ( bTableDoesExist )
+ impl_appendError( IParseContext::ErrorCode::InvalidTableExist, &sName );
+ else
+ aReturn = impl_createTableObject( sName, sCatalog, sSchema );
+ }
+ else
+ {
+ // queries win over tables, so if there's a query with this name, take this, no matter if
+ // there's a table, too
+ if ( bQueryDoesExist )
+ {
+ if ( !m_pImpl->isQueryAllowed( sComposedName ) )
+ {
+ impl_appendError( m_rParser.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES, nullptr ) );
+ return nullptr;
+ }
+
+ m_pImpl->m_xQueryContainer->getByName( sComposedName ) >>= aReturn;
+
+ // collect the parameters from the sub query
+ ForbidQueryName aForbidName( *m_pImpl, sComposedName );
+ impl_getQueryParameterColumns( aReturn );
+ }
+ else if ( bTableDoesExist )
+ m_pImpl->m_xTableContainer->getByName( sComposedName ) >>= aReturn;
+ else
+ {
+ if ( m_pImpl->m_xQueryContainer.is() )
+ // the connection on which we're working supports sub queries in from (else
+ // m_xQueryContainer would not have been set), so emit a better error message
+ impl_appendError( IParseContext::ErrorCode::InvalidTableOrQuery, &sName );
+ else
+ impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sName );
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sComposedName );
+ }
+
+ return aReturn;
+}
+
+
+void OSQLParseTreeIterator::traverseOneTableName( OSQLTables& _rTables,const OSQLParseNode * pTableName, const OUString & rTableRange )
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::TableNames ) )
+ // tables should not be included in the traversal
+ return;
+
+ OSL_ENSURE(pTableName != nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL");
+
+ Any aCatalog;
+ OUString aSchema,aTableName,aComposedName;
+ OUString aTableRange(rTableRange);
+
+ // Get table name
+ OSQLParseNode::getTableComponents(pTableName,aCatalog,aSchema,aTableName,m_pImpl->m_xDatabaseMetaData);
+
+ // create the composed name like DOMAIN.USER.TABLE1
+ aComposedName = ::dbtools::composeTableName(m_pImpl->m_xDatabaseMetaData,
+ aCatalog.hasValue() ? ::comphelper::getString(aCatalog) : OUString(),
+ aSchema,
+ aTableName,
+ false,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ // if there is no alias for the table name assign the original name to it
+ if ( aTableRange.isEmpty() )
+ aTableRange = aComposedName;
+
+ // get the object representing this table/query
+ OSQLTable aTable = impl_locateRecordSource( aComposedName );
+ if ( aTable.is() )
+ _rTables[ aTableRange ] = aTable;
+}
+
+void OSQLParseTreeIterator::impl_fillJoinConditions(const OSQLParseNode* i_pJoinCondition)
+{
+ if (i_pJoinCondition->count() == 3 && // Expression with brackets
+ SQL_ISPUNCTUATION(i_pJoinCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(i_pJoinCondition->getChild(2),")"))
+ {
+ impl_fillJoinConditions(i_pJoinCondition->getChild(1));
+ }
+ else if (SQL_ISRULEOR2(i_pJoinCondition,search_condition,boolean_term) && // AND/OR logic operation:
+ i_pJoinCondition->count() == 3)
+ {
+ // Only allow AND logic operation
+ if ( SQL_ISTOKEN(i_pJoinCondition->getChild(1),AND) )
+ {
+ impl_fillJoinConditions(i_pJoinCondition->getChild(0));
+ impl_fillJoinConditions(i_pJoinCondition->getChild(1));
+ }
+ }
+ else if (SQL_ISRULE(i_pJoinCondition,comparison_predicate))
+ {
+ // only the comparison of columns is allowed
+ OSL_ENSURE(i_pJoinCondition->count() == 3,"OQueryDesignView::InsertJoinConnection: error in the parse tree");
+ if (SQL_ISRULE(i_pJoinCondition->getChild(0),column_ref) &&
+ SQL_ISRULE(i_pJoinCondition->getChild(2),column_ref) &&
+ i_pJoinCondition->getChild(1)->getNodeType() == SQLNodeType::Equal)
+ {
+ m_pImpl->m_aJoinConditions.push_back( TNodePair(i_pJoinCondition->getChild(0),i_pJoinCondition->getChild(2)) );
+ }
+ }
+}
+
+std::vector< TNodePair >& OSQLParseTreeIterator::getJoinConditions() const
+{
+ return m_pImpl->m_aJoinConditions;
+}
+
+void OSQLParseTreeIterator::getQualified_join( OSQLTables& _rTables, const OSQLParseNode *pTableRef, OUString& aTableRange )
+{
+ OSL_PRECOND( SQL_ISRULE( pTableRef, cross_union ) || SQL_ISRULE( pTableRef, qualified_join ) ,
+ "OSQLParseTreeIterator::getQualified_join: illegal node!" );
+
+ aTableRange.clear();
+
+ const OSQLParseNode* pNode = getTableNode(_rTables,pTableRef->getChild(0),aTableRange);
+ if ( isTableNode( pNode ) )
+ traverseOneTableName( _rTables, pNode, aTableRange );
+
+ sal_uInt32 nPos = 4;
+ if( SQL_ISRULE(pTableRef,cross_union) || pTableRef->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL)
+ {
+ nPos = 3;
+ // join_condition,named_columns_join
+ if ( SQL_ISRULE( pTableRef, qualified_join ) )
+ {
+ const OSQLParseNode* pJoin_spec = pTableRef->getChild(4);
+ if ( SQL_ISRULE( pJoin_spec, join_condition ) )
+ {
+ impl_fillJoinConditions(pJoin_spec->getChild(1));
+ }
+ else
+ {
+ const OSQLParseNode* pColumnCommalist = pJoin_spec->getChild(2);
+ // All columns in the column_commalist ...
+ for (size_t i = 0; i < pColumnCommalist->count(); i++)
+ {
+ const OSQLParseNode * pCol = pColumnCommalist->getChild(i);
+ // add twice because the column must exists in both tables
+ m_pImpl->m_aJoinConditions.push_back( TNodePair(pCol,pCol) );
+ }
+ }
+ }
+ }
+
+ pNode = getTableNode(_rTables,pTableRef->getChild(nPos),aTableRange);
+ if ( isTableNode( pNode ) )
+ traverseOneTableName( _rTables, pNode, aTableRange );
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getTableNode( OSQLTables& _rTables, const OSQLParseNode *pTableRef,OUString& rTableRange )
+{
+ OSL_PRECOND( SQL_ISRULE( pTableRef, table_ref ) || SQL_ISRULE( pTableRef, joined_table )
+ || SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ),
+ "OSQLParseTreeIterator::getTableNode: only to be called for table_ref nodes!" );
+
+ const OSQLParseNode* pTableNameNode = nullptr;
+
+ if ( SQL_ISRULE( pTableRef, joined_table ) )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
+ }
+ if ( SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ) )
+ {
+ getQualified_join( _rTables, pTableRef, rTableRange );
+ }
+ else
+ {
+ rTableRange = OSQLParseNode::getTableRange(pTableRef);
+ if ( ( pTableRef->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
+ || ( pTableRef->count() == 5 ) // '(' joined_table ')' range_variable op_column_commalist
+ )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(6 - pTableRef->count()), rTableRange );
+ }
+ else if ( pTableRef->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')'
+ {
+ const OSQLParseNode* pSubQuery = pTableRef->getChild(0);
+ if ( pSubQuery->isToken() )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
+ }
+ else
+ {
+ OSL_ENSURE( pSubQuery->count() == 3, "sub queries should have 3 children!" );
+ const OSQLParseNode* pQueryExpression = pSubQuery->getChild(1);
+ if ( SQL_ISRULE( pQueryExpression, select_statement ) )
+ {
+ getSelect_statement( *m_pImpl->m_pSubTables, pQueryExpression );
+ // TODO: now, we need to setup an OSQLTable from pQueryExpression in some way
+ // and stick it in _rTables[rTableRange]. Probably fake it by
+ // setting up a full OSQLParseTreeIterator on pQueryExpression
+ // and using its m_aSelectColumns
+ // This is necessary in stuff like "SELECT * FROM tbl1 INNER JOIN (SELECT foo, bar FROM tbl2) AS tbl3"
+ // so that setSelectColumnName() can expand the "*" correctly.
+ // See e.g. R_UserAndLastSubscription query of https://bugs.libreoffice.org/attachment.cgi?id=71871
+ }
+ else
+ {
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" );
+ }
+ }
+ }
+ else if ( pTableRef->count() == 2 ) // table_node table_primary_as_range_column
+ {
+ pTableNameNode = pTableRef->getChild(0);
+ }
+ else
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: unhandled case!" );
+ }
+
+ return pTableNameNode;
+}
+
+void OSQLParseTreeIterator::getSelect_statement(OSQLTables& _rTables,const OSQLParseNode* pSelect)
+{
+ if(SQL_ISRULE(pSelect,union_statement))
+ {
+ getSelect_statement(_rTables,pSelect->getChild(0));
+ //getSelect_statement(pSelect->getChild(3));
+ return;
+ }
+ OSQLParseNode * pTableRefCommalist = pSelect->getChild(3)->getChild(0)->getChild(1);
+
+ OSL_ENSURE(pTableRefCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableRefCommalist,table_ref_commalist),"OSQLParseTreeIterator: error in parse tree!");
+
+ const OSQLParseNode* pTableName = nullptr;
+ OUString aTableRange;
+ for (size_t i = 0; i < pTableRefCommalist->count(); i++)
+ { // Process FROM clause
+ aTableRange.clear();
+
+ const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i);
+ if ( isTableNode( pTableListElement ) )
+ {
+ traverseOneTableName( _rTables, pTableListElement, aTableRange );
+ }
+ else if ( SQL_ISRULE( pTableListElement, table_ref ) )
+ {
+ // Table references can be made up of table names, table names (+),'('joined_table')'(+)
+ pTableName = pTableListElement->getChild(0);
+ if( isTableNode( pTableName ) )
+ { // Found table names
+ aTableRange = OSQLParseNode::getTableRange(pTableListElement);
+ traverseOneTableName( _rTables, pTableName, aTableRange );
+ }
+ else if(SQL_ISPUNCTUATION(pTableName,"{"))
+ { // '{' SQL_TOKEN_OJ joined_table '}'
+ getQualified_join( _rTables, pTableListElement->getChild(2), aTableRange );
+ }
+ else
+ { // '(' joined_table ')' range_variable op_column_commalist
+ getTableNode( _rTables, pTableListElement, aTableRange );
+ }
+ }
+ else if (SQL_ISRULE( pTableListElement, qualified_join ) || SQL_ISRULE( pTableListElement, cross_union ) )
+ {
+ getQualified_join( _rTables, pTableListElement, aTableRange );
+ }
+ else if ( SQL_ISRULE( pTableListElement, joined_table ) )
+ {
+ getQualified_join( _rTables, pTableListElement->getChild(1), aTableRange );
+ }
+
+ // if (! aIteratorStatus.IsSuccessful()) break;
+ }
+}
+
+bool OSQLParseTreeIterator::traverseTableNames(OSQLTables& _rTables)
+{
+ if ( m_pParseTree == nullptr )
+ return false;
+
+ OSQLParseNode* pTableName = nullptr;
+
+ switch ( m_eStatementType )
+ {
+ case OSQLStatementType::Select:
+ getSelect_statement( _rTables, m_pParseTree );
+ break;
+
+ case OSQLStatementType::CreateTable:
+ case OSQLStatementType::Insert:
+ case OSQLStatementType::Delete:
+ pTableName = m_pParseTree->getChild(2);
+ break;
+
+ case OSQLStatementType::Update:
+ pTableName = m_pParseTree->getChild(1);
+ break;
+ default:
+ break;
+ }
+
+ if ( pTableName )
+ {
+ traverseOneTableName( _rTables, pTableName, OUString() );
+ }
+
+ return !hasErrors();
+}
+
+OUString OSQLParseTreeIterator::getColumnAlias(const OSQLParseNode* _pDerivedColumn)
+{
+ OSL_ENSURE(SQL_ISRULE(_pDerivedColumn,derived_column),"No derived column!");
+ OUString sColumnAlias;
+ if(_pDerivedColumn->getChild(1)->count() == 2)
+ sColumnAlias = _pDerivedColumn->getChild(1)->getChild(1)->getTokenValue();
+ else if(!_pDerivedColumn->getChild(1)->isRule())
+ sColumnAlias = _pDerivedColumn->getChild(1)->getTokenValue();
+ return sColumnAlias;
+}
+
+
+namespace
+{
+ void lcl_getColumnRange( const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection,
+ OUString& _out_rColumnName, OUString& _out_rTableRange,
+ const OSQLColumns* _pSelectColumns, OUString& _out_rColumnAliasIfPresent )
+ {
+ _out_rColumnName.clear();
+ _out_rTableRange.clear();
+ _out_rColumnAliasIfPresent.clear();
+ if ( SQL_ISRULE( _pColumnRef, column_ref ) )
+ {
+ if( _pColumnRef->count() > 1 )
+ {
+ for ( sal_Int32 i=0; i<static_cast<sal_Int32>(_pColumnRef->count())-2; ++i )
+ _pColumnRef->getChild(i)->parseNodeToStr( _out_rTableRange, _rxConnection, nullptr, false, false );
+ _out_rColumnName = _pColumnRef->getChild( _pColumnRef->count()-1 )->getChild(0)->getTokenValue();
+ }
+ else
+ _out_rColumnName = _pColumnRef->getChild(0)->getTokenValue();
+
+ // look up the column in the select column, to find a possible alias
+ if ( _pSelectColumns )
+ {
+ for (const Reference< XPropertySet >& xColumn : *_pSelectColumns)
+ {
+ try
+ {
+ OUString sName, sTableName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) >>= sName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME ) ) >>= sTableName;
+ if ( sName == _out_rColumnName && ( _out_rTableRange.isEmpty() || sTableName == _out_rTableRange ) )
+ {
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= _out_rColumnAliasIfPresent;
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+ }
+ }
+ }
+ else if(SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec))
+ { // Function
+ _pColumnRef->parseNodeToStr( _out_rColumnName, _rxConnection );
+ }
+ else if(_pColumnRef->getNodeType() == SQLNodeType::Name)
+ _out_rColumnName = _pColumnRef->getTokenValue();
+ }
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ OUString& _rColumnName,
+ OUString& _rTableRange) const
+{
+ OUString sDummy;
+ lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, nullptr, sDummy );
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ OUString& _rColumnName,
+ OUString& _rTableRange,
+ OUString& _out_rColumnAliasIfPresent ) const
+{
+ lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, &*m_aSelectColumns, _out_rColumnAliasIfPresent );
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ const Reference< XConnection >& _rxConnection, OUString& _out_rColumnName, OUString& _out_rTableRange )
+{
+ OUString sDummy;
+ lcl_getColumnRange( _pColumnRef, _rxConnection, _out_rColumnName, _out_rTableRange, nullptr, sDummy );
+}
+
+
+void OSQLParseTreeIterator::traverseCreateColumns(const OSQLParseNode* pSelectNode)
+{
+ // aIteratorStatus.Clear();
+
+ if (!pSelectNode || m_eStatementType != OSQLStatementType::CreateTable || m_pImpl->m_pTables->empty())
+ {
+ impl_appendError( IParseContext::ErrorCode::General );
+ return;
+ }
+ if (!SQL_ISRULE(pSelectNode,base_table_element_commalist))
+ return ;
+
+ for (size_t i = 0; i < pSelectNode->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelectNode->getChild(i);
+
+ if (SQL_ISRULE(pColumnRef,column_def))
+ {
+ OUString aColumnName;
+ OUString aTypeName;
+ sal_Int32 nType = DataType::VARCHAR;
+ aColumnName = pColumnRef->getChild(0)->getTokenValue();
+
+ OSQLParseNode *pDatatype = pColumnRef->getChild(1);
+ if (pDatatype && SQL_ISRULE(pDatatype,character_string_type))
+ {
+ const OSQLParseNode *pType = pDatatype->getChild(0);
+ aTypeName = pType->getTokenValue();
+ if (pDatatype->count() == 2 && (pType->getTokenID() == SQL_TOKEN_CHAR || pType->getTokenID() == SQL_TOKEN_CHARACTER ))
+ nType = DataType::CHAR;
+ }
+ else if(pDatatype && pDatatype->getNodeType() == SQLNodeType::Keyword)
+ {
+ aTypeName = "VARCHAR";
+ }
+
+ if (!aTypeName.isEmpty())
+ {
+ //TODO:Create a new class for create statement to handle field length
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aColumnName,aTypeName,OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(false);
+ pColumn->setRealName(aColumnName);
+
+ m_aCreateColumns->push_back(pColumn);
+ }
+ }
+
+ }
+}
+
+bool OSQLParseTreeIterator::traverseSelectColumnNames(const OSQLParseNode* pSelectNode)
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::SelectColumns ) )
+ return true;
+
+ if (!pSelectNode || m_eStatementType != OSQLStatementType::Select || m_pImpl->m_pTables->empty())
+ {
+ impl_appendError( IParseContext::ErrorCode::General );
+ return false;
+ }
+
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ return traverseSelectColumnNames( pSelectNode->getChild( 0 ) )
+ /*&& traverseSelectColumnNames( pSelectNode->getChild( 3 ) )*/;
+ }
+
+ // nyi: more checks for correct structure!
+ if (pSelectNode->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode->getChild(2)->getChild(0),"*"))
+ {
+ // SELECT * ...
+ setSelectColumnName("*", "", "");
+ }
+ else if (SQL_ISRULE(pSelectNode->getChild(2),scalar_exp_commalist))
+ {
+ // SELECT column[,column] or SELECT COUNT(*) ...
+ OSQLParseNode * pSelection = pSelectNode->getChild(2);
+
+ for (size_t i = 0; i < pSelection->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelection->getChild(i);
+
+ //if (SQL_ISRULE(pColumnRef,select_sublist))
+ if (SQL_ISRULE(pColumnRef,derived_column) &&
+ SQL_ISRULE(pColumnRef->getChild(0),column_ref) &&
+ pColumnRef->getChild(0)->count() == 3 &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(0)->getChild(2),"*"))
+ {
+ // All the table's columns
+ OUString aTableRange;
+ pColumnRef->getChild(0)->parseNodeToStr( aTableRange, m_pImpl->m_xConnection, nullptr, false, false );
+ setSelectColumnName("*", "", aTableRange);
+ continue;
+ }
+ else if (SQL_ISRULE(pColumnRef,derived_column))
+ {
+ OUString aColumnAlias(getColumnAlias(pColumnRef)); // can be empty
+ OUString sColumnName;
+ OUString aTableRange;
+ sal_Int32 nType = DataType::VARCHAR;
+ bool bFkt(false);
+ pColumnRef = pColumnRef->getChild(0);
+ while (
+ pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
+ pColumnRef->count() == 3 &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
+ )
+ pColumnRef = pColumnRef->getChild(1);
+
+ if (SQL_ISRULE(pColumnRef,column_ref))
+ {
+ getColumnRange(pColumnRef,sColumnName,aTableRange);
+ OSL_ENSURE(!sColumnName.isEmpty(),"Column name must not be empty!");
+ }
+ else /*if (SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec) ||
+ SQL_ISRULE(pColumnRef,position_exp) || SQL_ISRULE(pColumnRef,extract_exp) ||
+ SQL_ISRULE(pColumnRef,length_exp) || SQL_ISRULE(pColumnRef,char_value_fct)||
+ SQL_ISRULE(pColumnRef,num_value_exp) || SQL_ISRULE(pColumnRef,term))*/
+ {
+ // Function call present
+ pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection );
+ // check if the column is also a parameter
+ traverseSearchCondition(pColumnRef); // num_value_exp
+
+ if ( pColumnRef->isRule() )
+ {
+ // FIXME: the if condition is not quite right
+ // many expressions are rules, e.g. "5+3"
+ // or even: "colName + 1"
+ bFkt = true;
+ nType = getFunctionReturnType(pColumnRef);
+ }
+ }
+ /*
+ else
+ {
+ aIteratorStatus.setStatementTooComplex();
+ return;
+ }
+ */
+ if(aColumnAlias.isEmpty())
+ aColumnAlias = sColumnName;
+ setSelectColumnName(sColumnName,aColumnAlias,aTableRange,bFkt,nType,SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec));
+ }
+ }
+ }
+
+ return !hasErrors();
+}
+
+
+bool OSQLParseTreeIterator::traverseOrderByColumnNames(const OSQLParseNode* pSelectNode)
+{
+ traverseByColumnNames( pSelectNode, true );
+ return !hasErrors();
+}
+
+void OSQLParseTreeIterator::traverseByColumnNames(const OSQLParseNode* pSelectNode, bool _bOrder)
+{
+ // aIteratorStatus.Clear();
+
+ if (pSelectNode == nullptr)
+ {
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+
+ if (m_eStatementType != OSQLStatementType::Select)
+ {
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ traverseByColumnNames(pSelectNode->getChild(0),_bOrder);
+ return;
+ }
+
+ OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pTableExp = pSelectNode->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator:table_exp error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ sal_uInt32 nPos = ( _bOrder ? ORDER_BY_CHILD_POS : 2 );
+
+ OSQLParseNode * pOptByClause = pTableExp->getChild(nPos);
+ OSL_ENSURE(pOptByClause != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ if ( pOptByClause->count() == 0 )
+ return;
+
+ OSL_ENSURE(pOptByClause->count() == 3,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pOrderingSpecCommalist = pOptByClause->getChild(2);
+ OSL_ENSURE(pOrderingSpecCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(!_bOrder || SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OSQLParseTreeIterator:ordering_spec_commalist error in parse tree!");
+ OSL_ENSURE(pOrderingSpecCommalist->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
+
+ OUString sColumnName;
+ OUString aTableRange;
+ sal_uInt32 nCount = pOrderingSpecCommalist->count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ OSQLParseNode* pColumnRef = pOrderingSpecCommalist->getChild(i);
+ OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ if ( _bOrder )
+ {
+ OSL_ENSURE(SQL_ISRULE(pColumnRef,ordering_spec),"OSQLParseTreeIterator:ordering_spec error in parse tree!");
+ OSL_ENSURE(pColumnRef->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+
+ pColumnRef = pColumnRef->getChild(0);
+ }
+ OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ aTableRange.clear();
+ sColumnName.clear();
+ if ( SQL_ISRULE(pColumnRef,column_ref) )
+ {
+ // Column name (and TableRange):
+ getColumnRange(pColumnRef,sColumnName,aTableRange);
+ }
+ else
+ { // here I found a predicate
+ pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ }
+ OSL_ENSURE(!sColumnName.isEmpty(),"sColumnName must not be empty!");
+ if ( _bOrder )
+ {
+ // Ascending/Descending
+ OSQLParseNode * pOptAscDesc = pColumnRef->getParent()->getChild(1);
+ OSL_ENSURE(pOptAscDesc != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+ bool bAscending = ! (pOptAscDesc && SQL_ISTOKEN(pOptAscDesc,DESC));
+ setOrderByColumnName(sColumnName, aTableRange,bAscending);
+ }
+ else
+ setGroupByColumnName(sColumnName, aTableRange);
+ }
+}
+
+bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode* pSelectNode)
+{
+ traverseByColumnNames( pSelectNode, false );
+ return !hasErrors();
+}
+
+
+namespace
+{
+ OUString lcl_generateParameterName( const OSQLParseNode& _rParentNode, const OSQLParseNode& _rParamNode )
+ {
+ OUString sColumnName( "param" );
+ const sal_Int32 nCount = static_cast<sal_Int32>(_rParentNode.count());
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ if ( _rParentNode.getChild(i) == &_rParamNode )
+ {
+ sColumnName += OUString::number( i+1 );
+ break;
+ }
+ }
+ return sColumnName;
+ }
+}
+
+
+void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode* _pNode)
+{
+ if ( _pNode == nullptr )
+ return;
+
+ OUString sColumnName, sTableRange, aColumnAlias;
+ const OSQLParseNode* pParent = _pNode->getParent();
+ if ( pParent != nullptr )
+ {
+ if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
+ {
+ sal_uInt32 nPos = 0;
+ if ( pParent->getChild(nPos) == _pNode )
+ nPos = 2;
+ const OSQLParseNode* pOther = pParent->getChild(nPos);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ } // if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
+ else if ( SQL_ISRULE(pParent,other_like_predicate_part_2) )
+ {
+ const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ }
+ else if ( SQL_ISRULE(pParent,between_predicate_part_2) )
+ {
+ const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ {
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ lcl_generateParameterName( *pParent, *_pNode );
+ }
+ }
+ else if ( pParent->getNodeType() == SQLNodeType::CommaListRule )
+ {
+ lcl_generateParameterName( *pParent, *_pNode );
+ }
+ }
+ traverseParameter( _pNode, pParent, sColumnName, sTableRange, aColumnAlias );
+ const sal_uInt32 nCount = _pNode->count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ const OSQLParseNode* pChild = _pNode->getChild(i);
+ traverseParameters( pChild );
+ }
+}
+
+bool OSQLParseTreeIterator::traverseSelectionCriteria(const OSQLParseNode* pSelectNode)
+{
+ if ( pSelectNode == nullptr )
+ return false;
+
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to WHERE clause:
+ OSQLParseNode * pWhereClause = nullptr;
+
+ if (m_eStatementType == OSQLStatementType::Select)
+ {
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ return traverseSelectionCriteria( pSelectNode->getChild( 0 ) )
+ && traverseSelectionCriteria( pSelectNode->getChild( 3 ) );
+ }
+ OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pTableExp = pSelectNode->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pWhereClause = pTableExp->getChild(1);
+ } else if (SQL_ISRULE(pSelectNode,update_statement_searched)) {
+ OSL_ENSURE(pSelectNode->count() == 5,"OSQLParseTreeIterator: error in parse tree!");
+ pWhereClause = pSelectNode->getChild(4);
+ } else if (SQL_ISRULE(pSelectNode,delete_statement_searched)) {
+ OSL_ENSURE(pSelectNode->count() == 4,"OSQLParseTreeIterator: error in parse tree!");
+ pWhereClause = pSelectNode->getChild(3);
+ } else if (SQL_ISRULE(pSelectNode,delete_statement_positioned)) {
+ // nyi
+ SAL_WARN( "connectivity.parse","OSQLParseTreeIterator::getSelectionCriteria: positioned nyi");
+ } else {
+ // Other statement, no selection criteria
+ return false;
+ }
+
+ if (!pWhereClause || !SQL_ISRULE(pWhereClause,where_clause))
+ {
+ // The WHERE clause is optional most of the time; which means it could be a "optional_where_clause".
+ OSL_ENSURE(pWhereClause && SQL_ISRULE(pWhereClause,opt_where_clause),"OSQLParseTreeIterator: error in parse tree!");
+ return false;
+ }
+
+ // But if it's a where_clause, then it must not be empty
+ OSL_ENSURE(pWhereClause->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
+ OSL_ENSURE(pComparisonPredicate != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+
+ // Process the comparison criteria now
+
+
+ traverseSearchCondition(pComparisonPredicate);
+
+ return !hasErrors();
+}
+
+
+void OSQLParseTreeIterator::traverseSearchCondition(OSQLParseNode const * pSearchCondition)
+{
+ if (
+ SQL_ISRULE(pSearchCondition,boolean_primary) &&
+ pSearchCondition->count() == 3 &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")
+ )
+ {
+ // Round brackets
+ traverseSearchCondition(pSearchCondition->getChild(1));
+ }
+ // The first element is an OR logical operation
+ else if ( SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 )
+ {
+ // if this assert fails, the SQL grammar has changed!
+ assert(SQL_ISTOKEN(pSearchCondition->getChild(1),OR));
+ // Then process recursively (use the same row) ...
+ traverseSearchCondition(pSearchCondition->getChild(0));
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+
+ // Continue with the right child
+ traverseSearchCondition(pSearchCondition->getChild(2));
+ }
+ // The first element is an AND logical operation (again)
+ else if ( SQL_ISRULE(pSearchCondition,boolean_term) && pSearchCondition->count() == 3 )
+ {
+ // Then process recursively (use the same row)
+ traverseSearchCondition(pSearchCondition->getChild(0));
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+
+ // Continue with the right child
+ traverseSearchCondition(pSearchCondition->getChild(2));
+ }
+ // Else, process single search criteria (like =, !=, ..., LIKE, IS NULL etc.)
+ else if (SQL_ISRULE(pSearchCondition,comparison_predicate) )
+ {
+ OUString aValue;
+ pSearchCondition->getChild(2)->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
+ traverseOnePredicate(pSearchCondition->getChild(0),aValue,pSearchCondition->getChild(2));
+ impl_fillJoinConditions(pSearchCondition);
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,like_predicate) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+
+ sal_Int32 nCurentPos = pPart2->count()-2;
+
+ OSQLParseNode * pNum_value_exp = pPart2->getChild(nCurentPos);
+ OSQLParseNode * pOptEscape = pPart2->getChild(nCurentPos+1);
+
+ OSL_ENSURE(pNum_value_exp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pOptEscape != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+ if (pOptEscape->count() != 0)
+ {
+ // aIteratorStatus.setStatementTooComplex();
+ return;
+ }
+
+ OUString aValue;
+ OSQLParseNode * pParam = nullptr;
+ if (SQL_ISRULE(pNum_value_exp,parameter))
+ pParam = pNum_value_exp;
+ else if(pNum_value_exp->isToken())
+ // Normal value
+ aValue = pNum_value_exp->getTokenValue();
+ else
+ {
+ pNum_value_exp->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
+ pParam = pNum_value_exp;
+ }
+
+ traverseOnePredicate(pSearchCondition->getChild(0),aValue,pParam);
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,in_predicate))
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+
+ traverseSearchCondition(pSearchCondition->getChild(0));
+ // if (! aIteratorStatus.IsSuccessful()) return;
+
+ OSQLParseNode* pChild = pPart2->getChild(2);
+ if ( SQL_ISRULE(pChild->getChild(0),subquery) )
+ {
+ traverseTableNames( *m_pImpl->m_pSubTables );
+ traverseSelectionCriteria(pChild->getChild(0)->getChild(1));
+ }
+ else
+ { // '(' value_exp_commalist ')'
+ pChild = pChild->getChild(1);
+ sal_Int32 nCount = pChild->count();
+ for (sal_Int32 i=0; i < nCount; ++i)
+ {
+ traverseSearchCondition(pChild->getChild(i));
+ }
+ }
+ }
+ else if (SQL_ISRULE(pSearchCondition,test_for_null) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+ OSL_ENSURE(SQL_ISTOKEN(pPart2->getChild(0),IS),"OSQLParseTreeIterator: error in parse tree!");
+
+ OUString aString;
+ traverseOnePredicate(pSearchCondition->getChild(0),aString,nullptr);
+ // if (! aIteratorStatus.IsSuccessful()) return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,num_value_exp) || SQL_ISRULE(pSearchCondition,term))
+ {
+ OUString aString;
+ traverseOnePredicate(pSearchCondition->getChild(0),aString,pSearchCondition->getChild(0));
+ traverseOnePredicate(pSearchCondition->getChild(2),aString,pSearchCondition->getChild(2));
+ }
+ // Just pass on the error
+}
+
+void OSQLParseTreeIterator::traverseParameter(const OSQLParseNode* _pParseNode
+ ,const OSQLParseNode* _pParentNode
+ ,const OUString& _aColumnName
+ ,OUString& _aTableRange
+ ,const OUString& _rColumnAlias)
+{
+ if ( !SQL_ISRULE( _pParseNode, parameter ) )
+ return;
+
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
+ // parameters not to be included in the traversal
+ return;
+
+ OSL_ENSURE(_pParseNode->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pMark = _pParseNode->getChild(0);
+ OUString sParameterName;
+
+ if (SQL_ISPUNCTUATION(pMark,"?"))
+ {
+ sParameterName = !_rColumnAlias.isEmpty()
+ ? _rColumnAlias
+ : !_aColumnName.isEmpty()
+ ? _aColumnName
+ : OUString("?");
+ }
+ else if (SQL_ISPUNCTUATION(pMark,":"))
+ {
+ sParameterName = _pParseNode->getChild(1)->getTokenValue();
+ }
+ else if (SQL_ISPUNCTUATION(pMark,"["))
+ {
+ sParameterName = _pParseNode->getChild(1)->getTokenValue();
+ }
+ else
+ {
+ SAL_WARN( "connectivity.parse","OSQLParseTreeIterator: error in parse tree!");
+ }
+
+ // found a parameter
+ if ( _pParentNode && (SQL_ISRULE(_pParentNode,general_set_fct) || SQL_ISRULE(_pParentNode,set_fct_spec)) )
+ {// found a function as column_ref
+ OUString sFunctionName;
+ _pParentNode->getChild(0)->parseNodeToStr( sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+ const sal_uInt32 nCount = _pParentNode->count();
+ sal_uInt32 i = 0;
+ for(; i < nCount;++i)
+ {
+ if ( _pParentNode->getChild(i) == _pParseNode )
+ break;
+ }
+ sal_Int32 nType = ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode->getChild(0)->getTokenID(), i-1);
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn( sParameterName,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(true);
+ pColumn->setRealName(sFunctionName);
+ m_aParameters->push_back(pColumn);
+ }
+ else
+ {
+ bool bNotFound = true;
+ OSQLColumns::const_iterator aIter = ::connectivity::find(
+ m_aSelectColumns->begin(),
+ m_aSelectColumns->end(),
+ _aColumnName,::comphelper::UStringMixEqual( isCaseSensitive() )
+ );
+ if(aIter != m_aSelectColumns->end())
+ {
+ rtl::Reference<OParseColumn> pNewColumn = new OParseColumn(*aIter,isCaseSensitive());
+ pNewColumn->setName(sParameterName);
+ pNewColumn->setRealName(_aColumnName);
+ m_aParameters->push_back(pNewColumn);
+ bNotFound = false;
+ }
+ else if(!_aColumnName.isEmpty())// search in the tables for the right one
+ {
+
+ Reference<XPropertySet> xColumn = findColumn( _aColumnName, _aTableRange, true );
+
+ if ( xColumn.is() )
+ {
+ rtl::Reference<OParseColumn> pNewColumn = new OParseColumn(xColumn,isCaseSensitive());
+ pNewColumn->setName(sParameterName);
+ pNewColumn->setRealName(_aColumnName);
+ m_aParameters->push_back(pNewColumn);
+ bNotFound = false;
+ }
+ }
+ if ( bNotFound )
+ {
+ sal_Int32 nType = DataType::VARCHAR;
+ OSQLParseNode* pParent = _pParentNode ? _pParentNode->getParent() : nullptr;
+ if ( pParent && (SQL_ISRULE(pParent,general_set_fct) || SQL_ISRULE(pParent,set_fct_spec)) )
+ {
+ const sal_uInt32 nCount = _pParentNode->count();
+ sal_uInt32 i = 0;
+ for(; i < nCount;++i)
+ {
+ if ( _pParentNode->getChild(i) == _pParseNode )
+ break;
+ }
+ nType = ::connectivity::OSQLParser::getFunctionParameterType( pParent->getChild(0)->getTokenID(), i+1);
+ }
+
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), sParameterName));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString());
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(sParameterName);
+ m_aParameters->push_back(pColumn);
+ }
+ }
+}
+
+void OSQLParseTreeIterator::traverseOnePredicate(
+ OSQLParseNode const * pColumnRef,
+ OUString& rValue,
+ OSQLParseNode const * pParseNode)
+{
+ if ( !pParseNode )
+ return;
+
+ // Column name (and TableRange):
+ OUString aColumnName, aTableRange, sColumnAlias;
+ getColumnRange( pColumnRef, aColumnName, aTableRange, sColumnAlias);
+
+ OUString aName;
+
+ /*if (SQL_ISRULE(pParseNode,parameter))
+ traverseParameter( pParseNode, pColumnRef, aColumnName, aTableRange, sColumnAlias );
+ else */if (SQL_ISRULE(pParseNode,column_ref))// Column-Name (and TableRange):
+ getColumnRange(pParseNode,aName,rValue);
+ else
+ {
+ traverseSearchCondition(pParseNode);
+ // if (! aIteratorStatus.IsSuccessful()) return;
+ }
+}
+
+
+void OSQLParseTreeIterator::traverseAll()
+{
+ impl_traverse( TraversalParts::All );
+}
+
+
+void OSQLParseTreeIterator::impl_traverse( TraversalParts _nIncludeMask )
+{
+ // resets our errors
+ m_xErrors.reset();
+
+ m_pImpl->m_nIncludeMask = _nIncludeMask;
+
+ if ( !traverseTableNames( *m_pImpl->m_pTables ) )
+ return;
+
+ switch ( m_eStatementType )
+ {
+ case OSQLStatementType::Select:
+ {
+ const OSQLParseNode* pSelectNode = m_pParseTree;
+ traverseParameters( pSelectNode );
+ if ( !traverseSelectColumnNames( pSelectNode )
+ || !traverseOrderByColumnNames( pSelectNode )
+ || !traverseGroupByColumnNames( pSelectNode )
+ || !traverseSelectionCriteria( pSelectNode )
+ )
+ return;
+ }
+ break;
+ case OSQLStatementType::CreateTable:
+ {
+ //0 | 1 | 2 |3| 4 |5
+ //create table sc.foo ( a char(20), b char )
+ const OSQLParseNode* pCreateNode = m_pParseTree->getChild(4);
+ traverseCreateColumns(pCreateNode);
+ }
+ break;
+ case OSQLStatementType::Insert:
+ break;
+ default:
+ break;
+ }
+}
+
+// Dummy implementations
+
+
+OSQLTable OSQLParseTreeIterator::impl_createTableObject( const OUString& rTableName,
+ const OUString& rCatalogName, const OUString& rSchemaName )
+{
+ OSL_PRECOND( m_eStatementType == OSQLStatementType::CreateTable,
+ "OSQLParseTreeIterator::impl_createTableObject: only to be called for CREATE TABLE statements!" );
+ // (in all other cases, m_pTables is to contain the table objects as obtained from the tables
+ // container of the connection (m_xTablesContainer)
+
+ OSQLTable aReturnTable = new OTable(
+ nullptr,
+ false,
+ rTableName,
+ "Table",
+ "New Created Table",
+ rSchemaName,
+ rCatalogName
+ );
+ return aReturnTable;
+}
+
+void OSQLParseTreeIterator::appendColumns(const OUString& _rTableAlias, const OSQLTable& _rTable)
+{
+ if (!_rTable.is())
+ return;
+
+ Reference<XNameAccess> xColumns = _rTable->getColumns();
+ if ( !xColumns.is() )
+ return;
+
+ Sequence< OUString > aColNames = xColumns->getElementNames();
+ const OUString* pBegin = aColNames.getConstArray();
+ const OUString* pEnd = pBegin + aColNames.getLength();
+
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+ std::vector<OUString> aSelectColumnNames = getSelectColumnNames();
+
+ for(;pBegin != pEnd;++pBegin)
+ {
+ OUString aName(getUniqueColumnName(aSelectColumnNames, *pBegin));
+ Reference< XPropertySet > xColumn;
+ if(xColumns->hasByName(*pBegin) && (xColumns->getByName(*pBegin) >>= xColumn) && xColumn.is())
+ {
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aName
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
+ , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)))
+ , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))
+ , isCaseSensitive()
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))));
+
+ pColumn->setTableName(_rTableAlias);
+ pColumn->setRealName(*pBegin);
+ m_aSelectColumns->push_back(pColumn);
+ // update aSelectColumnNames with newly insert aName
+ aSelectColumnNames.insert(std::upper_bound(aSelectColumnNames.begin(), aSelectColumnNames.end(), aName, aCompare), aName);
+ }
+ else
+ impl_appendError( IParseContext::ErrorCode::InvalidColumn, pBegin, &_rTableAlias );
+ }
+}
+
+void OSQLParseTreeIterator::setSelectColumnName(const OUString & rColumnName,const OUString & rColumnAlias, const OUString & rTableRange, bool bFkt, sal_Int32 _nType, bool bAggFkt)
+{
+ if(rColumnName.toChar() == '*' && rTableRange.isEmpty())
+ { // SELECT * ...
+ for (auto const& table : *m_pImpl->m_pTables)
+ appendColumns(table.first, table.second);
+ }
+ else if( rColumnName.toChar() == '*' && !rTableRange.isEmpty() )
+ { // SELECT <table>.*
+ OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
+
+ if(aFind != m_pImpl->m_pTables->end())
+ appendColumns(rTableRange, aFind->second);
+ }
+ else if ( rTableRange.isEmpty() )
+ { // SELECT <something> ...
+ // without table specified
+ if ( !bFkt )
+ {
+ Reference< XPropertySet> xNewColumn;
+
+ for (auto const& table : *m_pImpl->m_pTables)
+ {
+ if ( !table.second.is() )
+ continue;
+
+ Reference<XNameAccess> xColumns = table.second->getColumns();
+ Reference< XPropertySet > xColumn;
+ if ( !xColumns->hasByName( rColumnName )
+ || !( xColumns->getByName( rColumnName ) >>= xColumn )
+ )
+ continue;
+
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(xColumn,isCaseSensitive());
+ xNewColumn = pColumn;
+ pColumn->setTableName(table.first);
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(rColumnName);
+
+ break;
+ }
+
+ if ( !xNewColumn.is() )
+ {
+ // no function (due to the above !bFkt), no existing column
+ // => assume an expression
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+ // did not find a column with this name in any of the tables
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(
+ aNewColName,
+ "VARCHAR",
+ // TODO: does this match with _nType?
+ // Or should be fill this from the getTypeInfo of the connection?
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ _nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString()
+ );
+
+ xNewColumn = pColumn;
+ pColumn->setRealName( rColumnName );
+ }
+
+ m_aSelectColumns->push_back( xNewColumn );
+ }
+ else
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+ pColumn->setRealName(rColumnName);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ }
+ else // ColumnName and TableName exist
+ {
+ OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
+
+ bool bError = false;
+ if (aFind != m_pImpl->m_pTables->end() && aFind->second.is())
+ {
+ if (bFkt)
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+ pColumn->setRealName(rColumnName);
+ SAL_WARN("connectivity.parse", "Trying to construct a column with Function==true and a TableName; this makes no sense.");
+ assert(false);
+ pColumn->setTableName(aFind->first);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ else
+ {
+ Reference< XPropertySet > xColumn;
+ if (aFind->second->getColumns()->hasByName(rColumnName) && (aFind->second->getColumns()->getByName(rColumnName) >>= xColumn))
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(xColumn,isCaseSensitive());
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(rColumnName);
+ pColumn->setTableName(aFind->first);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ else
+ bError = true;
+ }
+ }
+ else
+ bError = true;
+
+ // Table does not exist or lacking field
+ if (bError)
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,DataType::VARCHAR,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ }
+}
+
+std::vector<OUString> OSQLParseTreeIterator::getSelectColumnNames() const
+{
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+
+ std::vector<OUString> aColumnNames;
+ OUString sPropertyName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ for (const auto& col : *m_aSelectColumns)
+ aColumnNames.push_back(getString(col->getPropertyValue(sPropertyName)));
+ std::sort(aColumnNames.begin(), aColumnNames.end(), aCompare);
+
+ return aColumnNames;
+}
+
+OUString OSQLParseTreeIterator::getUniqueColumnName(const std::vector<OUString>& rColumnNames, const OUString& rColumnName) const
+{
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+ if (!std::binary_search(rColumnNames.begin(), rColumnNames.end(), rColumnName, aCompare))
+ return rColumnName;
+
+ OUString aAlias;
+ sal_Int32 i=1;
+ do
+ {
+ aAlias = rColumnName + OUString::number(i++);
+ }
+ while (std::binary_search(rColumnNames.begin(), rColumnNames.end(), aAlias, aCompare));
+ return aAlias;
+}
+
+void OSQLParseTreeIterator::setOrderByColumnName(const OUString & rColumnName, OUString & rTableRange, bool bAscending)
+{
+ Reference<XPropertySet> xColumn = findSelectColumn( rColumnName );
+ if ( !xColumn.is() )
+ xColumn = findColumn ( rColumnName, rTableRange, false );
+ if ( xColumn.is() )
+ m_aOrderColumns->push_back(new OOrderColumn( xColumn, rTableRange, isCaseSensitive(), bAscending ) );
+ else
+ {
+ sal_Int32 nId = rColumnName.toInt32();
+ if ( nId > 0 && o3tl::make_unsigned(nId) < m_aSelectColumns->size() )
+ m_aOrderColumns->push_back( new OOrderColumn( (*m_aSelectColumns)[nId-1], isCaseSensitive(), bAscending ) );
+ }
+
+#ifdef SQL_TEST_PARSETREEITERATOR
+ cout << "OSQLParseTreeIterator::setOrderByColumnName: "
+ << (const char *) rColumnName << ", "
+ << (const char *) rTableRange << ", "
+ << (bAscending ? "true" : "false")
+ << "\n";
+#endif
+}
+
+void OSQLParseTreeIterator::setGroupByColumnName(const OUString & rColumnName, OUString & rTableRange)
+{
+ Reference<XPropertySet> xColumn = findColumn( rColumnName, rTableRange, false );
+ if ( xColumn.is() )
+ m_aGroupColumns->push_back(new OParseColumn(xColumn,isCaseSensitive()));
+ else
+ {
+ sal_Int32 nId = rColumnName.toInt32();
+ if ( nId > 0 && o3tl::make_unsigned(nId) < m_aSelectColumns->size() )
+ m_aGroupColumns->push_back(new OParseColumn((*m_aSelectColumns)[nId-1],isCaseSensitive()));
+ }
+
+#ifdef SQL_TEST_PARSETREEITERATOR
+ cout << "OSQLParseTreeIterator::setGroupByColumnName: "
+ << (const char *) rColumnName << ", "
+ << (const char *) rTableRange << ", "
+ << (bAscending ? "true" : "false")
+ << "\n";
+#endif
+}
+
+
+const OSQLParseNode* OSQLParseTreeIterator::getWhereTree() const
+{
+ if (!m_pParseTree)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to WHERE clause:
+ OSQLParseNode * pWhereClause = nullptr;
+ if(getStatementType() == OSQLStatementType::Select)
+ {
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pWhereClause = pTableExp->getChild(1);
+ }
+ else if (SQL_ISRULE(m_pParseTree,update_statement_searched) ||
+ SQL_ISRULE(m_pParseTree,delete_statement_searched))
+ {
+ pWhereClause = m_pParseTree->getChild(m_pParseTree->count()-1);
+ }
+ if(pWhereClause && pWhereClause->count() != 2)
+ pWhereClause = nullptr;
+ return pWhereClause;
+}
+
+
+const OSQLParseNode* OSQLParseTreeIterator::getOrderTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+
+ assert(SQL_ISRULE(m_pParseTree, select_statement) || SQL_ISRULE(m_pParseTree, union_statement));
+
+ auto pParseTree = m_pParseTree;
+ if(SQL_ISRULE(m_pParseTree, union_statement))
+ {
+ assert(m_pParseTree->count() == 4);
+ pParseTree = pParseTree->getChild(3);
+ // since UNION is left-associative (at least in our grammar),
+ // possibly the left-hand (m_pParseTree->getChild(0)) is a union_statement,
+ // but the right hand cannot.
+ assert(SQL_ISRULE(pParseTree, select_statement));
+ }
+
+ OSQLParseNode * pOrderClause = nullptr;
+ OSL_ENSURE(pParseTree->count() == 4, "OSQLParseTreeIterator::getOrderTree: expected a SELECT, and a SELECT must have exactly four children");
+ OSQLParseNode * pTableExp = pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr, "OSQLParseTreeIterator::getOrderTree: got NULL table_exp");
+ OSL_ENSURE(SQL_ISRULE(pTableExp, table_exp), "OSQLParseTreeIterator::getOrderTree: expected table_exp but got something else");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator::getOrderTree: table_exp doesn't have the expected number of children");
+ // tdf#141115 upgrade the above to an assert;
+ // this cannot go well if there are too few children
+ assert(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT);
+
+ pOrderClause = pTableExp->getChild(ORDER_BY_CHILD_POS);
+ // If it is an order_by, it must not be empty
+ if(pOrderClause->count() != 3)
+ pOrderClause = nullptr;
+ return pOrderClause;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getGroupByTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+ OSQLParseNode * pGroupClause = nullptr;
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pGroupClause = pTableExp->getChild(2);
+ // If it is an order_by, it must not be empty
+ if(pGroupClause->count() != 3)
+ pGroupClause = nullptr;
+ return pGroupClause;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getHavingTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+ OSQLParseNode * pHavingClause = nullptr;
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pHavingClause = pTableExp->getChild(3);
+ // If it is an order_by, then it must not be empty
+ if(pHavingClause->count() < 1)
+ pHavingClause = nullptr;
+ return pHavingClause;
+}
+
+bool OSQLParseTreeIterator::isTableNode(const OSQLParseNode* _pTableNode)
+{
+ return _pTableNode && (SQL_ISRULE(_pTableNode,catalog_name) ||
+ SQL_ISRULE(_pTableNode,schema_name) ||
+ SQL_ISRULE(_pTableNode,table_name));
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleWhereTree() const
+{
+ const OSQLParseNode* pNode = getWhereTree();
+ return pNode ? pNode->getChild(1) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleOrderTree() const
+{
+ const OSQLParseNode* pNode = getOrderTree();
+ return pNode ? pNode->getChild(2) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleGroupByTree() const
+{
+ const OSQLParseNode* pNode = getGroupByTree();
+ return pNode ? pNode->getChild(2) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleHavingTree() const
+{
+ const OSQLParseNode* pNode = getHavingTree();
+ return pNode ? pNode->getChild(1) : nullptr;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findSelectColumn( std::u16string_view rColumnName )
+{
+ for (auto const& lookupColumn : *m_aSelectColumns)
+ {
+ Reference< XPropertySet > xColumn( lookupColumn );
+ try
+ {
+ OUString sName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sName;
+ if ( sName == rColumnName )
+ return xColumn;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+ }
+ return nullptr;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findColumn( const OUString & rColumnName, OUString & rTableRange, bool _bLookInSubTables )
+{
+ Reference< XPropertySet > xColumn = findColumn( *m_pImpl->m_pTables, rColumnName, rTableRange );
+ if ( !xColumn.is() && _bLookInSubTables )
+ xColumn = findColumn( *m_pImpl->m_pSubTables, rColumnName, rTableRange );
+ return xColumn;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findColumn(const OSQLTables& _rTables, const OUString & rColumnName, OUString & rTableRange)
+{
+ Reference< XPropertySet > xColumn;
+ if ( !rTableRange.isEmpty() )
+ {
+ OSQLTables::const_iterator aFind = _rTables.find(rTableRange);
+
+ if ( aFind != _rTables.end()
+ && aFind->second.is()
+ && aFind->second->getColumns().is()
+ && aFind->second->getColumns()->hasByName(rColumnName) )
+ aFind->second->getColumns()->getByName(rColumnName) >>= xColumn;
+ }
+ if ( !xColumn.is() )
+ {
+ for (auto const& table : _rTables)
+ {
+ if ( table.second.is() )
+ {
+ Reference<XNameAccess> xColumns = table.second->getColumns();
+ if( xColumns.is() && xColumns->hasByName(rColumnName) && (xColumns->getByName(rColumnName) >>= xColumn) )
+ {
+ OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!");
+ // Cannot take "rTableRange = table.first" because that is the fully composed name
+ // that is, catalogName.schemaName.tableName
+ rTableRange = getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)));
+ break; // This column must only exits once
+ }
+ }
+ }
+ }
+ return xColumn;
+}
+
+
+void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError, const OUString* _pReplaceToken1, const OUString* _pReplaceToken2 )
+{
+ OUString sErrorMessage = m_rParser.getContext().getErrorMessage( _eError );
+ if ( _pReplaceToken1 )
+ {
+ bool bTwoTokens = ( _pReplaceToken2 != nullptr );
+ const char* pPlaceHolder1 = bTwoTokens ? "#1" : "#";
+ const OUString sPlaceHolder1 = OUString::createFromAscii( pPlaceHolder1 );
+
+ sErrorMessage = sErrorMessage.replaceFirst( sPlaceHolder1, *_pReplaceToken1 );
+ if ( _pReplaceToken2 )
+ sErrorMessage = sErrorMessage.replaceFirst( "#2" , *_pReplaceToken2 );
+ }
+
+ impl_appendError( SQLException(
+ sErrorMessage, nullptr, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() ) );
+}
+
+
+void OSQLParseTreeIterator::impl_appendError( const SQLException& _rError )
+{
+ SAL_WARN("connectivity.parse", "Adding error " << exceptionToString(Any(_rError)));
+ if ( m_xErrors )
+ {
+ SQLException* pErrorChain = &*m_xErrors;
+ while ( pErrorChain->NextException.hasValue() )
+ pErrorChain = static_cast< SQLException* >( pErrorChain->NextException.pData );
+ pErrorChain->NextException <<= _rError;
+ }
+ else
+ m_xErrors = _rError;
+}
+
+sal_Int32 OSQLParseTreeIterator::getFunctionReturnType(const OSQLParseNode* _pNode )
+{
+ sal_Int32 nType = DataType::OTHER;
+ OUString sFunctionName;
+ if ( SQL_ISRULE(_pNode,length_exp) )
+ {
+ _pNode->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+ nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
+ }
+ else if ( SQL_ISRULE(_pNode,num_value_exp) || SQL_ISRULE(_pNode,term) || SQL_ISRULE(_pNode,factor) )
+ {
+ nType = DataType::DOUBLE;
+ }
+ else
+ {
+ _pNode->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+
+ // MIN and MAX have another return type, we have to check the expression itself.
+ // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566
+ if ( SQL_ISRULE(_pNode,general_set_fct) && (SQL_ISTOKEN(_pNode->getChild(0),MIN) || SQL_ISTOKEN(_pNode->getChild(0),MAX) ))
+ {
+ const OSQLParseNode* pValueExp = _pNode->getChild(3);
+ if (SQL_ISRULE(pValueExp,column_ref))
+ {
+ OUString sColumnName;
+ OUString aTableRange;
+ getColumnRange(pValueExp,sColumnName,aTableRange);
+ OSL_ENSURE(!sColumnName.isEmpty(),"Columnname must not be empty!");
+ Reference<XPropertySet> xColumn = findColumn( sColumnName, aTableRange, true );
+
+ if ( xColumn.is() )
+ {
+ xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE)) >>= nType;
+ }
+ }
+ else
+ {
+ if ( SQL_ISRULE(pValueExp,num_value_exp) || SQL_ISRULE(pValueExp,term) || SQL_ISRULE(pValueExp,factor) )
+ {
+ nType = DataType::DOUBLE;
+ }
+ else if ( SQL_ISRULE(pValueExp,datetime_primary) )
+ {
+ switch(pValueExp->getChild(0)->getTokenID() )
+ {
+ case SQL_TOKEN_CURRENT_DATE:
+ nType = DataType::DATE;
+ break;
+ case SQL_TOKEN_CURRENT_TIME:
+ nType = DataType::TIME;
+ break;
+ case SQL_TOKEN_CURRENT_TIMESTAMP:
+ nType = DataType::TIMESTAMP;
+ break;
+ }
+ }
+ else if ( SQL_ISRULE(pValueExp,value_exp_primary) )
+ {
+ nType = getFunctionReturnType(pValueExp->getChild(1));
+ }
+ else if ( SQL_ISRULE(pValueExp,concatenation)
+ || SQL_ISRULE(pValueExp,char_factor)
+ || SQL_ISRULE(pValueExp,bit_value_fct)
+ || SQL_ISRULE(pValueExp,char_value_fct)
+ || SQL_ISRULE(pValueExp,char_substring_fct)
+ || SQL_ISRULE(pValueExp,fold)
+ || SQL_ISTOKEN(pValueExp,STRING) )
+ {
+ nType = DataType::VARCHAR;
+ }
+ }
+ if ( nType == DataType::OTHER )
+ nType = DataType::DOUBLE;
+ }
+ else
+ nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
+ }
+
+ return nType;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/sqlnode.cxx b/connectivity/source/parse/sqlnode.cxx
new file mode 100644
index 000000000..75acac48f
--- /dev/null
+++ b/connectivity/source/parse/sqlnode.cxx
@@ -0,0 +1,2789 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/macros.h>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <connectivity/sqlbison_exports.hxx>
+#include <connectivity/internalnode.hxx>
+#define YYBISON 1
+#include <sqlbison.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqlscan.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/i18n/LocaleData.hpp>
+#include <com/sun/star/i18n/NumberFormatIndex.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/i18n/KParseType.hpp>
+#include <com/sun/star/i18n/KParseTokens.hpp>
+#include <com/sun/star/i18n/CharacterClassification.hpp>
+#include <connectivity/dbconversion.hxx>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <TConnection.hxx>
+#include <comphelper/numbers.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <tools/diagnose_ex.h>
+#include <string.h>
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <string_view>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star;
+using namespace ::osl;
+using namespace ::dbtools;
+using namespace ::comphelper;
+
+namespace
+{
+
+ bool lcl_saveConvertToNumber(const Reference< XNumberFormatter > & _xFormatter,sal_Int32 _nKey,const OUString& _sValue,double& _nrValue)
+ {
+ bool bRet = false;
+ try
+ {
+ _nrValue = _xFormatter->convertStringToNumber(_nKey, _sValue);
+ bRet = true;
+ }
+ catch(Exception&)
+ {
+ }
+ return bRet;
+ }
+
+ void replaceAndReset(connectivity::OSQLParseNode*& _pResetNode,connectivity::OSQLParseNode* _pNewNode)
+ {
+ _pResetNode->getParent()->replace(_pResetNode, _pNewNode);
+ delete _pResetNode;
+ _pResetNode = _pNewNode;
+ }
+
+ /** quotes a string and search for quotes inside the string and replace them with the new quote
+ @param rValue
+ The value to be quoted.
+ @param rQuot
+ The quote
+ @param rQuotToReplace
+ The quote to replace with
+ @return
+ The quoted string.
+ */
+ OUString SetQuotation(std::u16string_view rValue, const OUString& rQuot, std::u16string_view rQuotToReplace)
+ {
+ OUString rNewValue = rQuot + rValue;
+ sal_Int32 nIndex = sal_Int32(-1); // Replace quotes with double quotes or the parser gets into problems
+
+ if (!rQuot.isEmpty())
+ {
+ do
+ {
+ nIndex += 2;
+ nIndex = rNewValue.indexOf(rQuot,nIndex);
+ if(nIndex != -1)
+ rNewValue = rNewValue.replaceAt(nIndex,rQuot.getLength(),rQuotToReplace);
+ } while (nIndex != -1);
+ }
+
+ rNewValue += rQuot;
+ return rNewValue;
+ }
+
+ bool columnMatchP(const connectivity::OSQLParseNode* pSubTree, const connectivity::SQLParseNodeParameter& rParam)
+ {
+ using namespace connectivity;
+ assert(SQL_ISRULE(pSubTree,column_ref));
+
+ if(!rParam.xField.is())
+ return false;
+
+ // retrieve the field's name & table range
+ OUString aFieldName;
+ try
+ {
+ sal_Int32 nNamePropertyId = PROPERTY_ID_NAME;
+ if ( rParam.xField->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) )
+ nNamePropertyId = PROPERTY_ID_REALNAME;
+ rParam.xField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( nNamePropertyId ) ) >>= aFieldName;
+ }
+ catch ( Exception& )
+ {
+ }
+
+ if(!pSubTree->count())
+ return false;
+
+ const OSQLParseNode* pCol = pSubTree->getChild(pSubTree->count()-1);
+ if (SQL_ISRULE(pCol,column_val))
+ {
+ assert(pCol->count() == 1);
+ pCol = pCol->getChild(0);
+ }
+ const OSQLParseNode* pTable(nullptr);
+ switch (pSubTree->count())
+ {
+ case 1:
+ break;
+ case 3:
+ pTable = pSubTree->getChild(0);
+ break;
+ case 5:
+ case 7:
+ SAL_WARN("connectivity.parse", "SQL: catalog and/or schema in column_ref in predicate");
+ break;
+ default:
+ SAL_WARN("connectivity.parse", "columnMatchP: SQL grammar changed; column_ref has " << pSubTree->count() << " children");
+ assert(false);
+ break;
+ }
+ // TODO: not all DBMS match column names case-insensitively...
+ // see XDatabaseMetaData::supportsMixedCaseIdentifiers()
+ // and XDatabaseMetaData::supportsMixedCaseQuotedIdentifiers()
+ if ( // table name matches (or no table name)?
+ ( !pTable || pTable->getTokenValue().equalsIgnoreAsciiCase(rParam.sPredicateTableAlias) )
+ && // column name matches?
+ pCol->getTokenValue().equalsIgnoreAsciiCase(aFieldName)
+ )
+ return true;
+ return false;
+ }
+}
+
+namespace connectivity
+{
+
+SQLParseNodeParameter::SQLParseNodeParameter( const Reference< XConnection >& _rxConnection,
+ const Reference< XNumberFormatter >& _xFormatter, const Reference< XPropertySet >& _xField,
+ const OUString &_sPredicateTableAlias,
+ const Locale& _rLocale, const IParseContext* _pContext,
+ bool _bIntl, bool _bQuote, OUString _sDecSep, bool _bPredicate, bool _bParseToSDBC )
+ :rLocale(_rLocale)
+ ,aMetaData( _rxConnection )
+ ,pParser( nullptr )
+ ,pSubQueryHistory( std::make_shared<QueryNameSet>() )
+ ,xFormatter(_xFormatter)
+ ,xField(_xField)
+ ,sPredicateTableAlias(_sPredicateTableAlias)
+ ,m_rContext( _pContext ? *_pContext : OSQLParser::s_aDefaultContext )
+ ,sDecSep(_sDecSep)
+ ,bQuote(_bQuote)
+ ,bInternational(_bIntl)
+ ,bPredicate(_bPredicate)
+ ,bParseToSDBCLevel( _bParseToSDBC )
+{
+}
+
+OUString OSQLParseNode::convertDateString(const SQLParseNodeParameter& rParam, std::u16string_view rString)
+{
+ Date aDate = DBTypeConversion::toDate(rString);
+ Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
+ Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
+
+ double fDate = DBTypeConversion::toDouble(aDate,DBTypeConversion::getNULLDate(xSupplier));
+ sal_Int32 nKey = xTypes->getFormatIndex(NumberFormatIndex::DATE_SYS_DDMMYYYY, rParam.rLocale);
+ return rParam.xFormatter->convertNumberToString(nKey, fDate);
+}
+
+
+OUString OSQLParseNode::convertDateTimeString(const SQLParseNodeParameter& rParam, const OUString& rString)
+{
+ DateTime aDate = DBTypeConversion::toDateTime(rString);
+ Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
+ Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
+
+ double fDateTime = DBTypeConversion::toDouble(aDate,DBTypeConversion::getNULLDate(xSupplier));
+ sal_Int32 nKey = xTypes->getFormatIndex(NumberFormatIndex::DATETIME_SYS_DDMMYYYY_HHMMSS, rParam.rLocale);
+ return rParam.xFormatter->convertNumberToString(nKey, fDateTime);
+}
+
+
+OUString OSQLParseNode::convertTimeString(const SQLParseNodeParameter& rParam, std::u16string_view rString)
+{
+ css::util::Time aTime = DBTypeConversion::toTime(rString);
+ Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
+
+ Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
+
+ double fTime = DBTypeConversion::toDouble(aTime);
+ sal_Int32 nKey = xTypes->getFormatIndex(NumberFormatIndex::TIME_HHMMSS, rParam.rLocale);
+ return rParam.xFormatter->convertNumberToString(nKey, fTime);
+}
+
+
+void OSQLParseNode::parseNodeToStr(OUString& rString,
+ const Reference< XConnection >& _rxConnection,
+ const IParseContext* pContext,
+ bool _bIntl,
+ bool _bQuote) const
+{
+ parseNodeToStr(
+ rString, _rxConnection, nullptr, nullptr, OUString(),
+ pContext ? pContext->getPreferredLocale() : OParseContext::getDefaultLocale(),
+ pContext, _bIntl, _bQuote, OUString("."), false );
+}
+
+
+void OSQLParseNode::parseNodeToPredicateStr(OUString& rString,
+ const Reference< XConnection >& _rxConnection,
+ const Reference< XNumberFormatter > & xFormatter,
+ const css::lang::Locale& rIntl,
+ OUString _sDec,
+ const IParseContext* pContext ) const
+{
+ OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!");
+
+ if (xFormatter.is())
+ parseNodeToStr(rString, _rxConnection, xFormatter, nullptr, OUString(), rIntl, pContext, true, true, _sDec, true);
+}
+
+
+void OSQLParseNode::parseNodeToPredicateStr(OUString& rString,
+ const Reference< XConnection > & _rxConnection,
+ const Reference< XNumberFormatter > & xFormatter,
+ const Reference< XPropertySet > & _xField,
+ const OUString &_sPredicateTableAlias,
+ const css::lang::Locale& rIntl,
+ OUString _sDec,
+ const IParseContext* pContext ) const
+{
+ OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!");
+
+ if (xFormatter.is())
+ parseNodeToStr( rString, _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext, true, true, _sDec, true );
+}
+
+
+void OSQLParseNode::parseNodeToStr(OUString& rString,
+ const Reference< XConnection > & _rxConnection,
+ const Reference< XNumberFormatter > & xFormatter,
+ const Reference< XPropertySet > & _xField,
+ const OUString &_sPredicateTableAlias,
+ const css::lang::Locale& rIntl,
+ const IParseContext* pContext,
+ bool _bIntl,
+ bool _bQuote,
+ OUString _sDecSep,
+ bool _bPredicate) const
+{
+ OSL_ENSURE( _rxConnection.is(), "OSQLParseNode::parseNodeToStr: invalid connection!" );
+
+ if ( !_rxConnection.is() )
+ return;
+
+ OUStringBuffer sBuffer(rString);
+ try
+ {
+ OSQLParseNode::impl_parseNodeToString_throw( sBuffer,
+ SQLParseNodeParameter(
+ _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext,
+ _bIntl, _bQuote, _sDecSep, _bPredicate, false
+ ) );
+ }
+ catch( const SQLException& )
+ {
+ SAL_WARN( "connectivity.parse", "OSQLParseNode::parseNodeToStr: this should not throw!" );
+ // our callers don't expect this method to throw anything. The only known situation
+ // where impl_parseNodeToString_throw can throw is when there is a cyclic reference
+ // in the sub queries, but this cannot be the case here, as we do not parse to
+ // SDBC level.
+ }
+ rString = sBuffer.makeStringAndClear();
+}
+
+bool OSQLParseNode::parseNodeToExecutableStatement( OUString& _out_rString, const Reference< XConnection >& _rxConnection,
+ OSQLParser& _rParser, css::sdbc::SQLException* _pErrorHolder ) const
+{
+ OSL_PRECOND( _rxConnection.is(), "OSQLParseNode::parseNodeToExecutableStatement: invalid connection!" );
+ SQLParseNodeParameter aParseParam( _rxConnection,
+ nullptr, nullptr, OUString(), OParseContext::getDefaultLocale(), nullptr, false, true, OUString("."), false, true );
+
+ if ( aParseParam.aMetaData.supportsSubqueriesInFrom() )
+ {
+ Reference< XQueriesSupplier > xSuppQueries( _rxConnection, UNO_QUERY );
+ OSL_ENSURE( xSuppQueries.is(), "OSQLParseNode::parseNodeToExecutableStatement: cannot substitute everything without a QueriesSupplier!" );
+ if ( xSuppQueries.is() )
+ aParseParam.xQueries = xSuppQueries->getQueries();
+ }
+
+ aParseParam.pParser = &_rParser;
+
+ // LIMIT keyword differs in Firebird
+ OSQLParseNode* pTableExp = getChild(3);
+ Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData() );
+ OUString sLimitValue;
+ if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1)
+ && (xMeta->getURL().equalsIgnoreAsciiCase("sdbc:embedded:firebird")
+ || xMeta->getURL().startsWithIgnoreAsciiCase("sdbc:firebird:")))
+ {
+ sLimitValue = pTableExp->getChild(6)->getChild(1)->getTokenValue();
+ delete pTableExp->removeAt(6);
+ }
+
+ _out_rString.clear();
+ OUStringBuffer sBuffer;
+ bool bSuccess = false;
+ try
+ {
+ impl_parseNodeToString_throw( sBuffer, aParseParam );
+ bSuccess = true;
+ }
+ catch( const SQLException& e )
+ {
+ if ( _pErrorHolder )
+ *_pErrorHolder = e;
+ }
+
+ if(sLimitValue.getLength() > 0)
+ {
+ constexpr char SELECT_KEYWORD[] = "SELECT";
+ sBuffer.insert(sBuffer.indexOf(SELECT_KEYWORD) + strlen(SELECT_KEYWORD),
+ OUStringConcatenation(" FIRST " + sLimitValue));
+ }
+
+ _out_rString = sBuffer.makeStringAndClear();
+ return bSuccess;
+}
+
+
+namespace
+{
+ bool lcl_isAliasNamePresent( const OSQLParseNode& _rTableNameNode )
+ {
+ return !OSQLParseNode::getTableRange(_rTableNameNode.getParent()).isEmpty();
+ }
+}
+
+
+void OSQLParseNode::impl_parseNodeToString_throw(OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple) const
+{
+ if ( isToken() )
+ {
+ parseLeaf(rString,rParam);
+ return;
+ }
+
+ // Lets see how many nodes this subtree has
+ sal_uInt32 nCount = count();
+
+ bool bHandled = false;
+ switch ( getKnownRuleID() )
+ {
+ // special handling for parameters
+ case parameter:
+ {
+ bSimple=false;
+ if(!rString.isEmpty())
+ rString.append(" ");
+ if (nCount == 1) // ?
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
+ else if (rParam.bParseToSDBCLevel && rParam.aMetaData.shouldSubstituteParameterNames())
+ {
+ rString.append("?");
+ }
+ else if (nCount == 2) // :Name
+ {
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
+ rString.append(m_aChildren[1]->m_aNodeValue);
+ } // [Name]
+ else
+ {
+ assert (nCount == 3);
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
+ rString.append(m_aChildren[1]->m_aNodeValue);
+ rString.append(m_aChildren[2]->m_aNodeValue);
+ }
+ bHandled = true;
+ }
+ break;
+
+ // table refs
+ case table_ref:
+ bSimple=false;
+ if ( ( nCount == 2 ) || ( nCount == 3 ) || ( nCount == 5 ) )
+ {
+ impl_parseTableRangeNodeToString_throw( rString, rParam );
+ bHandled = true;
+ }
+ break;
+
+ // table name - might be a query name
+ case table_name:
+ bSimple=false;
+ bHandled = impl_parseTableNameNodeToString_throw( rString, rParam );
+ break;
+
+ case as_clause:
+ bSimple=false;
+ assert(nCount == 0 || nCount == 2);
+ if (nCount == 2)
+ {
+ if ( rParam.aMetaData.generateASBeforeCorrelationName() )
+ rString.append(" AS ");
+ m_aChildren[1]->impl_parseNodeToString_throw( rString, rParam, false );
+ }
+ bHandled = true;
+ break;
+
+ case opt_as:
+ assert(nCount == 0);
+ bHandled = true;
+ break;
+
+ case like_predicate:
+ // Depending on whether international is given, LIKE is treated differently
+ // international: *, ? are placeholders
+ // else SQL92 conform: %, _
+ impl_parseLikeNodeToString_throw( rString, rParam, bSimple );
+ bHandled = true;
+ break;
+
+ case general_set_fct:
+ case set_fct_spec:
+ case position_exp:
+ case extract_exp:
+ case length_exp:
+ case char_value_fct:
+ bSimple=false;
+ if (!addDateValue(rString, rParam))
+ {
+ // Do not quote function name
+ SQLParseNodeParameter aNewParam(rParam);
+ aNewParam.bQuote = ( SQL_ISRULE(this,length_exp) || SQL_ISRULE(this,char_value_fct) );
+
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, aNewParam, false );
+ aNewParam.bQuote = rParam.bQuote;
+ //aNewParam.bPredicate = sal_False; // disable [ ] around names // look at i73215
+ OUStringBuffer aStringPara;
+ for (sal_uInt32 i=1; i<nCount; i++)
+ {
+ const OSQLParseNode * pSubTree = m_aChildren[i].get();
+ if (pSubTree)
+ {
+ pSubTree->impl_parseNodeToString_throw( aStringPara, aNewParam, false );
+
+ // In the comma lists, put commas in-between all subtrees
+ if ((m_eNodeType == SQLNodeType::CommaListRule) && (i < (nCount - 1)))
+ aStringPara.append(",");
+ }
+ else
+ i++;
+ }
+ rString.append(aStringPara);
+ }
+ bHandled = true;
+ break;
+ case odbc_call_spec:
+ case subquery:
+ case term:
+ case factor:
+ case window_function:
+ case cast_spec:
+ case num_value_exp:
+ bSimple = false;
+ break;
+ default:
+ break;
+ } // switch ( getKnownRuleID() )
+
+ if ( bHandled )
+ return;
+
+ for (auto i = m_aChildren.begin(); i != m_aChildren.end();)
+ {
+ const OSQLParseNode* pSubTree = i->get();
+ if ( !pSubTree )
+ {
+ ++i;
+ continue;
+ }
+
+ SQLParseNodeParameter aNewParam(rParam);
+
+ // don't replace the field for subqueries
+ if (rParam.xField.is() && SQL_ISRULE(pSubTree,subquery))
+ aNewParam.xField = nullptr;
+
+ // When we are building a criterion inside a query view,
+ // simplify criterion display by removing:
+ // "currentFieldName"
+ // "currentFieldName" =
+ // but only in simple expressions.
+ // This means anything that is made of:
+ // (see the rules conditionalised by inPredicateCheck() in sqlbison.y).
+ // - parentheses
+ // - logical operators (and, or, not)
+ // - comparison operators (IS, =, >, <, BETWEEN, LIKE, ...)
+ // but *not* e.g. in function arguments
+ if (bSimple && rParam.bPredicate && rParam.xField.is() && SQL_ISRULE(pSubTree,column_ref))
+ {
+ if (columnMatchP(pSubTree, rParam))
+ {
+ // skip field
+ ++i;
+ // if the following node is the comparison operator'=',
+ // we filter it as well
+ if (SQL_ISRULE(this, comparison_predicate))
+ {
+ if(i != m_aChildren.end())
+ {
+ pSubTree = i->get();
+ if (pSubTree && pSubTree->getNodeType() == SQLNodeType::Equal)
+ ++i;
+ }
+ }
+ }
+ else
+ {
+ pSubTree->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
+ ++i;
+
+ // In the comma lists, put commas in-between all subtrees
+ if ((m_eNodeType == SQLNodeType::CommaListRule) && (i != m_aChildren.end()))
+ rString.append(",");
+ }
+ }
+ else
+ {
+ pSubTree->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
+ ++i;
+
+ // In the comma lists, put commas in-between all subtrees
+ if ((m_eNodeType == SQLNodeType::CommaListRule) && (i != m_aChildren.end()))
+ {
+ if (SQL_ISRULE(this,value_exp_commalist) && rParam.bPredicate)
+ rString.append(";");
+ else
+ rString.append(",");
+ }
+ }
+ // The right hand-side of these operators is not simple
+ switch ( getKnownRuleID() )
+ {
+ case general_set_fct:
+ case set_fct_spec:
+ case position_exp:
+ case extract_exp:
+ case length_exp:
+ case char_value_fct:
+ case odbc_call_spec:
+ case subquery:
+ case comparison_predicate:
+ case between_predicate:
+ case like_predicate:
+ case test_for_null:
+ case in_predicate:
+ case existence_test:
+ case unique_test:
+ case all_or_any_predicate:
+ case join_condition:
+ case comparison_predicate_part_2:
+ case parenthesized_boolean_value_expression:
+ case other_like_predicate_part_2:
+ case between_predicate_part_2:
+ bSimple=false;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+bool OSQLParseNode::impl_parseTableNameNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const
+{
+ // is the table_name part of a table_ref?
+ OSL_ENSURE( getParent(), "OSQLParseNode::impl_parseTableNameNodeToString_throw: table_name without parent?" );
+ if ( !getParent() || ( getParent()->getKnownRuleID() != table_ref ) )
+ return false;
+
+ // if it's a query, maybe we need to substitute the SQL statement ...
+ if ( !rParam.bParseToSDBCLevel )
+ return false;
+
+ if ( !rParam.xQueries.is() )
+ // connection does not support queries in queries, or was no query supplier
+ return false;
+
+ try
+ {
+ OUString sTableOrQueryName( getChild(0)->getTokenValue() );
+ bool bIsQuery = rParam.xQueries->hasByName( sTableOrQueryName );
+ if ( !bIsQuery )
+ return false;
+
+ // avoid recursion (e.g. "foo" defined as "SELECT * FROM bar" and "bar" defined as "SELECT * FROM foo".
+ if ( rParam.pSubQueryHistory->find( sTableOrQueryName ) != rParam.pSubQueryHistory->end() )
+ {
+ OSL_ENSURE( rParam.pParser, "OSQLParseNode::impl_parseTableNameNodeToString_throw: no parser?" );
+ if ( rParam.pParser )
+ {
+ const SQLError& rErrors( rParam.pParser->getErrorHelper() );
+ rErrors.raiseException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES );
+ }
+ else
+ {
+ SQLError aErrors;
+ aErrors.raiseException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES );
+ }
+ }
+ rParam.pSubQueryHistory->insert( sTableOrQueryName );
+
+ Reference< XPropertySet > xQuery( rParam.xQueries->getByName( sTableOrQueryName ), UNO_QUERY_THROW );
+
+ // substitute the query name with the constituting command
+ OUString sCommand;
+ OSL_VERIFY( xQuery->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sCommand );
+
+ bool bEscapeProcessing = false;
+ OSL_VERIFY( xQuery->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing );
+
+ // the query we found here might itself be based on another query, so parse it recursively
+ OSL_ENSURE( rParam.pParser, "OSQLParseNode::impl_parseTableNameNodeToString_throw: cannot analyze sub queries without a parser!" );
+ if ( bEscapeProcessing && rParam.pParser )
+ {
+ OUString sError;
+ std::unique_ptr< OSQLParseNode > pSubQueryNode( rParam.pParser->parseTree( sError, sCommand ) );
+ if (pSubQueryNode)
+ {
+ // parse the sub-select to SDBC level, too
+ OUStringBuffer sSubSelect;
+ pSubQueryNode->impl_parseNodeToString_throw( sSubSelect, rParam, false );
+ if ( !sSubSelect.isEmpty() )
+ sCommand = sSubSelect.makeStringAndClear();
+ }
+ }
+
+ rString.append( " ( " );
+ rString.append(sCommand);
+ rString.append( " )" );
+
+ // append the query name as table alias, since it might be referenced in other
+ // parts of the statement - but only if there's no other alias name present
+ if ( !lcl_isAliasNamePresent( *this ) )
+ {
+ rString.append( " AS " );
+ if ( rParam.bQuote )
+ rString.append(SetQuotation( sTableOrQueryName,
+ rParam.aMetaData.getIdentifierQuoteString(), rParam.aMetaData.getIdentifierQuoteString() ));
+ }
+
+ // don't forget to remove the query name from the history, else multiple inclusions
+ // won't work
+ // #i69227# / 2006-10-10 / frank.schoenheit@sun.com
+ rParam.pSubQueryHistory->erase( sTableOrQueryName );
+
+ return true;
+ }
+ catch( const SQLException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+ return false;
+}
+
+
+void OSQLParseNode::impl_parseTableRangeNodeToString_throw(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
+{
+ OSL_PRECOND( ( count() == 2 ) || ( count() == 3 ) || ( count() == 5 ) ,"Illegal count");
+
+ // rString += " ";
+ std::for_each(m_aChildren.begin(),m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & pNode) { pNode->impl_parseNodeToString_throw(rString, rParam, false); });
+}
+
+
+void OSQLParseNode::impl_parseLikeNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple ) const
+{
+ assert(SQL_ISRULE(this,like_predicate));
+ OSL_ENSURE(count() == 2,"count != 2: Prepare for GPF");
+
+ const OSQLParseNode* pEscNode = nullptr;
+ const OSQLParseNode* pParaNode = nullptr;
+
+ SQLParseNodeParameter aNewParam(rParam);
+ //aNewParam.bQuote = sal_True; // why setting this to true? @see https://bz.apache.org/ooo/show_bug.cgi?id=75557
+
+ if ( !(bSimple && rParam.bPredicate && rParam.xField.is() && SQL_ISRULE(m_aChildren[0],column_ref) && columnMatchP(m_aChildren[0].get(), rParam)) )
+ m_aChildren[0]->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
+
+ const OSQLParseNode* pPart2 = m_aChildren[1].get();
+ pPart2->getChild(0)->impl_parseNodeToString_throw( rString, aNewParam, false );
+ pPart2->getChild(1)->impl_parseNodeToString_throw( rString, aNewParam, false );
+ pParaNode = pPart2->getChild(2);
+ pEscNode = pPart2->getChild(3);
+
+ if (pParaNode->isToken())
+ {
+ OUString aStr = ConvertLikeToken(pParaNode, pEscNode, rParam.bInternational);
+ rString.append(" ");
+ rString.append(SetQuotation(aStr, "\'", u"\'\'"));
+ }
+ else
+ pParaNode->impl_parseNodeToString_throw( rString, aNewParam, false );
+
+ pEscNode->impl_parseNodeToString_throw( rString, aNewParam, false );
+}
+
+
+bool OSQLParseNode::getTableComponents(const OSQLParseNode* _pTableNode,
+ css::uno::Any &_rCatalog,
+ OUString &_rSchema,
+ OUString &_rTable,
+ const Reference< XDatabaseMetaData >& _xMetaData)
+{
+ OSL_ENSURE(_pTableNode,"Wrong use of getTableComponents! _pTableNode is not allowed to be null!");
+ if(_pTableNode)
+ {
+ const bool bSupportsCatalog = _xMetaData.is() && _xMetaData->supportsCatalogsInDataManipulation();
+ const bool bSupportsSchema = _xMetaData.is() && _xMetaData->supportsSchemasInDataManipulation();
+ const OSQLParseNode* pTableNode = _pTableNode;
+ // clear the parameter given
+ _rCatalog = Any();
+ _rSchema.clear();
+ _rTable.clear();
+ // see rule catalog_name: in sqlbison.y
+ if (SQL_ISRULE(pTableNode,catalog_name))
+ {
+ OSL_ENSURE(pTableNode->getChild(0) && pTableNode->getChild(0)->isToken(),"Invalid parsenode!");
+ _rCatalog <<= pTableNode->getChild(0)->getTokenValue();
+ pTableNode = pTableNode->getChild(2);
+ }
+ // check if we have schema_name rule
+ if(SQL_ISRULE(pTableNode,schema_name))
+ {
+ if ( bSupportsCatalog && !bSupportsSchema )
+ _rCatalog <<= pTableNode->getChild(0)->getTokenValue();
+ else
+ _rSchema = pTableNode->getChild(0)->getTokenValue();
+ pTableNode = pTableNode->getChild(2);
+ }
+ // check if we have table_name rule
+ if(SQL_ISRULE(pTableNode,table_name))
+ {
+ _rTable = pTableNode->getChild(0)->getTokenValue();
+ }
+ else
+ {
+ SAL_WARN( "connectivity.parse","Error in parse tree!");
+ }
+ }
+ return !_rTable.isEmpty();
+}
+
+void OSQLParser::killThousandSeparator(OSQLParseNode* pLiteral)
+{
+ if ( pLiteral )
+ {
+ if ( s_xLocaleData->getLocaleItem( m_pData->aLocale ).decimalSeparator.toChar() == ',' )
+ {
+ pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace('.', sal_Unicode());
+ // and replace decimal
+ pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace(',', '.');
+ }
+ else
+ pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace(',', sal_Unicode());
+ }
+}
+
+OSQLParseNode* OSQLParser::convertNode(sal_Int32 nType, OSQLParseNode* pLiteral)
+{
+ if ( !pLiteral )
+ return nullptr;
+
+ OSQLParseNode* pReturn = pLiteral;
+
+ if ( ( pLiteral->isRule() && !SQL_ISRULE(pLiteral,value_exp) ) || SQL_ISTOKEN(pLiteral,FALSE) || SQL_ISTOKEN(pLiteral,TRUE) )
+ {
+ switch(nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ if ( !SQL_ISRULE(pReturn,char_value_exp) && !buildStringNodes(pReturn) )
+ pReturn = nullptr;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch(pLiteral->getNodeType())
+ {
+ case SQLNodeType::String:
+ switch(nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ break;
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ if (m_xFormatter.is())
+ pReturn = buildDate( nType, pReturn);
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
+ break;
+ }
+ break;
+ case SQLNodeType::AccessDate:
+ switch(nType)
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ if ( m_xFormatter.is() )
+ pReturn = buildDate( nType, pReturn);
+ else
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidDateCompare);
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
+ break;
+ }
+ break;
+ case SQLNodeType::IntNum:
+ switch(nType)
+ {
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::BIGINT:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ // kill thousand separators if any
+ killThousandSeparator(pReturn);
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ pReturn = buildNode_STR_NUM(pReturn);
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidIntCompare);
+ break;
+ }
+ break;
+ case SQLNodeType::ApproxNum:
+ switch(nType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::FLOAT:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ // kill thousand separators if any
+ killThousandSeparator(pReturn);
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ pReturn = buildNode_STR_NUM(pReturn);
+ break;
+ case DataType::INTEGER:
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidRealCompare);
+ break;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ return pReturn;
+}
+
+sal_Int16 OSQLParser::buildPredicateRule(OSQLParseNode*& pAppend, OSQLParseNode* pLiteral, OSQLParseNode* pCompare, OSQLParseNode* pLiteral2)
+{
+ OSL_ENSURE(inPredicateCheck(),"Only in predicate check allowed!");
+ sal_Int16 nErg = 0;
+ if ( m_xField.is() )
+ {
+ sal_Int32 nType = 0;
+ try
+ {
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
+ }
+ catch( Exception& )
+ {
+ return nErg;
+ }
+
+ OSQLParseNode* pNode1 = convertNode(nType,pLiteral);
+ if ( pNode1 )
+ {
+ OSQLParseNode* pNode2 = convertNode(nType,pLiteral2);
+ if ( m_sErrorMessage.isEmpty() )
+ nErg = buildNode(pAppend,pCompare,pNode1,pNode2);
+ }
+ }
+ if (!pCompare->getParent()) // I have no parent so I was not used and I must die :-)
+ delete pCompare;
+ return nErg;
+}
+
+sal_Int16 OSQLParser::buildLikeRule(OSQLParseNode* pAppend, OSQLParseNode*& pLiteral, const OSQLParseNode* pEscape)
+{
+ sal_Int16 nErg = 0;
+ sal_Int32 nType = 0;
+
+ if (!m_xField.is())
+ return nErg;
+ try
+ {
+ Any aValue;
+ {
+ aValue = m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE));
+ aValue >>= nType;
+ }
+ }
+ catch( Exception& )
+ {
+ return nErg;
+ }
+
+ switch (nType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ if(pLiteral->isRule())
+ {
+ pAppend->append(pLiteral);
+ nErg = 1;
+ }
+ else
+ {
+ switch(pLiteral->getNodeType())
+ {
+ case SQLNodeType::String:
+ pLiteral->m_aNodeValue = ConvertLikeToken(pLiteral, pEscape, false);
+ pAppend->append(pLiteral);
+ nErg = 1;
+ break;
+ case SQLNodeType::ApproxNum:
+ if (m_xFormatter.is() && m_nFormatKey)
+ {
+ sal_Int16 nScale = 0;
+ try
+ {
+ Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, "Decimals" );
+ aValue >>= nScale;
+ }
+ catch( Exception& )
+ {
+ }
+
+ pAppend->append(new OSQLInternalNode(stringToDouble(pLiteral->getTokenValue(),nScale),SQLNodeType::String));
+ }
+ else
+ pAppend->append(new OSQLInternalNode(pLiteral->getTokenValue(),SQLNodeType::String));
+
+ delete pLiteral;
+ nErg = 1;
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::ValueNoLike);
+ m_sErrorMessage = m_sErrorMessage.replaceAt(m_sErrorMessage.indexOf("#1"),2,pLiteral->getTokenValue());
+ break;
+ }
+ }
+ break;
+ default:
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::FieldNoLike);
+ break;
+ }
+ return nErg;
+}
+
+OSQLParseNode* OSQLParser::buildNode_Date(const double& fValue, sal_Int32 nType)
+{
+ OSQLParseNode* pNewNode = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::set_fct_spec));
+ pNewNode->append(new OSQLInternalNode("{", SQLNodeType::Punctuation));
+ OSQLParseNode* pDateNode = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::odbc_fct_spec));
+ pNewNode->append(pDateNode);
+ pNewNode->append(new OSQLInternalNode("}", SQLNodeType::Punctuation));
+
+ switch (nType)
+ {
+ case DataType::DATE:
+ {
+ Date aDate = DBTypeConversion::toDate(fValue,DBTypeConversion::getNULLDate(m_xFormatter->getNumberFormatsSupplier()));
+ OUString aString = DBTypeConversion::toDateString(aDate);
+ pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_D));
+ pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
+ break;
+ }
+ case DataType::TIME:
+ {
+ css::util::Time aTime = DBTypeConversion::toTime(fValue);
+ OUString aString = DBTypeConversion::toTimeString(aTime);
+ pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_T));
+ pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
+ break;
+ }
+ case DataType::TIMESTAMP:
+ {
+ DateTime aDateTime = DBTypeConversion::toDateTime(fValue,DBTypeConversion::getNULLDate(m_xFormatter->getNumberFormatsSupplier()));
+ if (aDateTime.Seconds || aDateTime.Minutes || aDateTime.Hours)
+ {
+ OUString aString = DBTypeConversion::toDateTimeString(aDateTime);
+ pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_TS));
+ pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
+ }
+ else
+ {
+ Date aDate(aDateTime.Day,aDateTime.Month,aDateTime.Year);
+ pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_D));
+ pDateNode->append(new OSQLInternalNode(DBTypeConversion::toDateString(aDate), SQLNodeType::String));
+ }
+ break;
+ }
+ }
+
+ return pNewNode;
+}
+
+OSQLParseNode* OSQLParser::buildNode_STR_NUM(OSQLParseNode*& _pLiteral)
+{
+ OSQLParseNode* pReturn = nullptr;
+ if ( _pLiteral )
+ {
+ if (m_nFormatKey)
+ {
+ sal_Int16 nScale = 0;
+ try
+ {
+ Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, "Decimals" );
+ aValue >>= nScale;
+ }
+ catch( Exception& )
+ {
+ }
+
+ pReturn = new OSQLInternalNode(stringToDouble(_pLiteral->getTokenValue(),nScale),SQLNodeType::String);
+ }
+ else
+ pReturn = new OSQLInternalNode(_pLiteral->getTokenValue(),SQLNodeType::String);
+
+ delete _pLiteral;
+ _pLiteral = nullptr;
+ }
+ return pReturn;
+}
+
+OUString OSQLParser::stringToDouble(const OUString& _rValue,sal_Int16 _nScale)
+{
+ OUString aValue;
+ if(!m_xCharClass.is())
+ m_xCharClass = CharacterClassification::create( m_xContext );
+ if( s_xLocaleData.is() )
+ {
+ try
+ {
+ ParseResult aResult = m_xCharClass->parsePredefinedToken(KParseType::ANY_NUMBER,_rValue,0,m_pData->aLocale,0,OUString(),KParseType::ANY_NUMBER,OUString());
+ if((aResult.TokenType & KParseType::IDENTNAME) && aResult.EndPos == _rValue.getLength())
+ {
+ aValue = OUString::number(aResult.Value);
+ sal_Int32 nPos = aValue.lastIndexOf('.');
+ if((nPos+_nScale) < aValue.getLength())
+ aValue = aValue.replaceAt(nPos+_nScale,aValue.getLength()-nPos-_nScale, u"");
+ aValue = aValue.replaceAt(aValue.lastIndexOf('.'),1,s_xLocaleData->getLocaleItem(m_pData->aLocale).decimalSeparator);
+ return aValue;
+ }
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ return aValue;
+}
+
+
+::osl::Mutex& OSQLParser::getMutex()
+{
+ static ::osl::Mutex aMutex;
+ return aMutex;
+}
+
+
+std::unique_ptr<OSQLParseNode> OSQLParser::predicateTree(OUString& rErrorMessage, const OUString& rStatement,
+ const Reference< css::util::XNumberFormatter > & xFormatter,
+ const Reference< XPropertySet > & xField,
+ bool bUseRealName)
+{
+ // Guard the parsing
+ ::osl::MutexGuard aGuard(getMutex());
+ // must be reset
+ setParser(this);
+
+
+ // reset the parser
+ m_xField = xField;
+ m_xFormatter = xFormatter;
+
+ if (m_xField.is())
+ {
+ sal_Int32 nType=0;
+ try
+ {
+ // get the field name
+ OUString aString;
+
+ // retrieve the fields name
+ // #75243# use the RealName of the column if there is any otherwise the name which could be the alias
+ // of the field
+ Reference< XPropertySetInfo> xInfo = m_xField->getPropertySetInfo();
+ if ( bUseRealName && xInfo->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME)))
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME)) >>= aString;
+ else
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aString;
+
+ m_sFieldName = aString;
+
+ // get the field format key
+ if ( xInfo->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)))
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) >>= m_nFormatKey;
+ else
+ m_nFormatKey = 0;
+
+ // get the field type
+ m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
+ }
+ catch ( Exception& )
+ {
+ OSL_ASSERT(false);
+ }
+
+ if (m_nFormatKey && m_xFormatter.is())
+ {
+ Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LOCALE) );
+ OSL_ENSURE(aValue.getValueType() == cppu::UnoType<css::lang::Locale>::get(), "OSQLParser::PredicateTree : invalid language property !");
+
+ if (aValue.getValueType() == cppu::UnoType<css::lang::Locale>::get())
+ aValue >>= m_pData->aLocale;
+ }
+ else
+ m_pData->aLocale = m_pContext->getPreferredLocale();
+
+ if ( m_xFormatter.is() )
+ {
+ try
+ {
+ Reference< css::util::XNumberFormatsSupplier > xFormatSup = m_xFormatter->getNumberFormatsSupplier();
+ if ( xFormatSup.is() )
+ {
+ Reference< css::util::XNumberFormats > xFormats = xFormatSup->getNumberFormats();
+ if ( xFormats.is() )
+ {
+ css::lang::Locale aLocale;
+ aLocale.Language = "en";
+ aLocale.Country = "US";
+ OUString sFormat("YYYY-MM-DD");
+ m_nDateFormatKey = xFormats->queryKey(sFormat,aLocale,false);
+ if ( m_nDateFormatKey == sal_Int32(-1) )
+ m_nDateFormatKey = xFormats->addNew(sFormat, aLocale);
+ }
+ }
+ }
+ catch ( Exception& )
+ {
+ SAL_WARN( "connectivity.parse","DateFormatKey");
+ }
+ }
+
+ switch (nType)
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ s_pScanner->SetRule(OSQLScanner::GetDATERule());
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ s_pScanner->SetRule(OSQLScanner::GetSTRINGRule());
+ break;
+ default:
+ if ( s_xLocaleData->getLocaleItem( m_pData->aLocale ).decimalSeparator.toChar() == ',' )
+ s_pScanner->SetRule(OSQLScanner::GetGERRule());
+ else
+ s_pScanner->SetRule(OSQLScanner::GetENGRule());
+ }
+
+ }
+ else
+ s_pScanner->SetRule(OSQLScanner::GetSQLRule());
+
+ s_pScanner->prepareScan(rStatement, m_pContext, true);
+
+ SQLyylval.pParseNode = nullptr;
+ // SQLyypvt = NULL;
+ m_pParseTree = nullptr;
+ m_sErrorMessage.clear();
+
+ // Start the parser
+ if (SQLyyparse() != 0)
+ {
+ m_sFieldName.clear();
+ m_xField.clear();
+ m_xFormatter.clear();
+ m_nFormatKey = 0;
+ m_nDateFormatKey = 0;
+
+ if (m_sErrorMessage.isEmpty())
+ m_sErrorMessage = s_pScanner->getErrorMessage();
+ if (m_sErrorMessage.isEmpty())
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::General);
+
+ rErrorMessage = m_sErrorMessage;
+
+ // clear the garbage collector
+ (*s_pGarbageCollector)->clearAndDelete();
+ m_pParseTree.release(); // because the garbage collector deleted it
+ return nullptr;
+ }
+ else
+ {
+ (*s_pGarbageCollector)->clear();
+
+ m_sFieldName.clear();
+ m_xField.clear();
+ m_xFormatter.clear();
+ m_nFormatKey = 0;
+ m_nDateFormatKey = 0;
+
+ // Return the result (the root parse node):
+
+ // Instead, the parse method sets the member pParseTree and simply returns that
+ OSL_ENSURE(m_pParseTree != nullptr,"OSQLParser: Parser did not return a ParseTree!");
+ return std::move(m_pParseTree);
+ }
+}
+
+
+OSQLParser::OSQLParser(const css::uno::Reference< css::uno::XComponentContext >& rxContext, const IParseContext* _pContext)
+ :m_pContext(_pContext)
+ ,m_pData( new OSQLParser_Data )
+ ,m_nFormatKey(0)
+ ,m_nDateFormatKey(0)
+ ,m_xContext(rxContext)
+{
+
+
+ setParser(this);
+
+#ifdef SQLYYDEBUG
+#ifdef SQLYYDEBUG_ON
+ SQLyydebug = 1;
+#endif
+#endif
+
+ ::osl::MutexGuard aGuard(getMutex());
+ // Do we have to initialize the data?
+ if (s_nRefCount == 0)
+ {
+ s_pScanner = new OSQLScanner();
+ s_pScanner->setScanner();
+ s_pGarbageCollector = new OSQLParseNodesGarbageCollector();
+
+ if(!s_xLocaleData.is())
+ s_xLocaleData = LocaleData::create(m_xContext);
+
+ // reset to UNKNOWN_RULE
+ static_assert(OSQLParseNode::UNKNOWN_RULE==0, "UNKNOWN_RULE must be 0 for memset to 0 to work");
+ memset(OSQLParser::s_nRuleIDs,0,sizeof(OSQLParser::s_nRuleIDs));
+
+ const struct
+ {
+ OSQLParseNode::Rule eRule; // the parse node's ID for the rule
+ OString sRuleName; // the name of the rule ("select_statement")
+ } aRuleDescriptions[] =
+ {
+ { OSQLParseNode::select_statement, "select_statement" },
+ { OSQLParseNode::table_exp, "table_exp" },
+ { OSQLParseNode::table_ref_commalist, "table_ref_commalist" },
+ { OSQLParseNode::table_ref, "table_ref" },
+ { OSQLParseNode::catalog_name, "catalog_name" },
+ { OSQLParseNode::schema_name, "schema_name" },
+ { OSQLParseNode::table_name, "table_name" },
+ { OSQLParseNode::opt_column_commalist, "opt_column_commalist" },
+ { OSQLParseNode::column_commalist, "column_commalist" },
+ { OSQLParseNode::column_ref_commalist, "column_ref_commalist" },
+ { OSQLParseNode::column_ref, "column_ref" },
+ { OSQLParseNode::opt_order_by_clause, "opt_order_by_clause" },
+ { OSQLParseNode::ordering_spec_commalist, "ordering_spec_commalist" },
+ { OSQLParseNode::ordering_spec, "ordering_spec" },
+ { OSQLParseNode::opt_asc_desc, "opt_asc_desc" },
+ { OSQLParseNode::where_clause, "where_clause" },
+ { OSQLParseNode::opt_where_clause, "opt_where_clause" },
+ { OSQLParseNode::search_condition, "search_condition" },
+ { OSQLParseNode::comparison, "comparison" },
+ { OSQLParseNode::comparison_predicate, "comparison_predicate" },
+ { OSQLParseNode::between_predicate, "between_predicate" },
+ { OSQLParseNode::like_predicate, "like_predicate" },
+ { OSQLParseNode::opt_escape, "opt_escape" },
+ { OSQLParseNode::test_for_null, "test_for_null" },
+ { OSQLParseNode::scalar_exp_commalist, "scalar_exp_commalist" },
+ { OSQLParseNode::scalar_exp, "scalar_exp" },
+ { OSQLParseNode::parameter_ref, "parameter_ref" },
+ { OSQLParseNode::parameter, "parameter" },
+ { OSQLParseNode::general_set_fct, "general_set_fct" },
+ { OSQLParseNode::range_variable, "range_variable" },
+ { OSQLParseNode::column, "column" },
+ { OSQLParseNode::delete_statement_positioned, "delete_statement_positioned" },
+ { OSQLParseNode::delete_statement_searched, "delete_statement_searched" },
+ { OSQLParseNode::update_statement_positioned, "update_statement_positioned" },
+ { OSQLParseNode::update_statement_searched, "update_statement_searched" },
+ { OSQLParseNode::assignment_commalist, "assignment_commalist" },
+ { OSQLParseNode::assignment, "assignment" },
+ { OSQLParseNode::values_or_query_spec, "values_or_query_spec" },
+ { OSQLParseNode::insert_statement, "insert_statement" },
+ { OSQLParseNode::insert_atom_commalist, "insert_atom_commalist" },
+ { OSQLParseNode::insert_atom, "insert_atom" },
+ { OSQLParseNode::from_clause, "from_clause" },
+ { OSQLParseNode::qualified_join, "qualified_join" },
+ { OSQLParseNode::cross_union, "cross_union" },
+ { OSQLParseNode::select_sublist, "select_sublist" },
+ { OSQLParseNode::derived_column, "derived_column" },
+ { OSQLParseNode::column_val, "column_val" },
+ { OSQLParseNode::set_fct_spec, "set_fct_spec" },
+ { OSQLParseNode::boolean_term, "boolean_term" },
+ { OSQLParseNode::boolean_primary, "boolean_primary" },
+ { OSQLParseNode::num_value_exp, "num_value_exp" },
+ { OSQLParseNode::join_type, "join_type" },
+ { OSQLParseNode::position_exp, "position_exp" },
+ { OSQLParseNode::extract_exp, "extract_exp" },
+ { OSQLParseNode::length_exp, "length_exp" },
+ { OSQLParseNode::char_value_fct, "char_value_fct" },
+ { OSQLParseNode::odbc_call_spec, "odbc_call_spec" },
+ { OSQLParseNode::in_predicate, "in_predicate" },
+ { OSQLParseNode::existence_test, "existence_test" },
+ { OSQLParseNode::unique_test, "unique_test" },
+ { OSQLParseNode::all_or_any_predicate, "all_or_any_predicate" },
+ { OSQLParseNode::named_columns_join, "named_columns_join" },
+ { OSQLParseNode::join_condition, "join_condition" },
+ { OSQLParseNode::joined_table, "joined_table" },
+ { OSQLParseNode::boolean_factor, "boolean_factor" },
+ { OSQLParseNode::sql_not, "sql_not" },
+ { OSQLParseNode::manipulative_statement, "manipulative_statement" },
+ { OSQLParseNode::subquery, "subquery" },
+ { OSQLParseNode::value_exp_commalist, "value_exp_commalist" },
+ { OSQLParseNode::odbc_fct_spec, "odbc_fct_spec" },
+ { OSQLParseNode::union_statement, "union_statement" },
+ { OSQLParseNode::outer_join_type, "outer_join_type" },
+ { OSQLParseNode::char_value_exp, "char_value_exp" },
+ { OSQLParseNode::term, "term" },
+ { OSQLParseNode::value_exp_primary, "value_exp_primary" },
+ { OSQLParseNode::value_exp, "value_exp" },
+ { OSQLParseNode::selection, "selection" },
+ { OSQLParseNode::fold, "fold" },
+ { OSQLParseNode::char_substring_fct, "char_substring_fct" },
+ { OSQLParseNode::factor, "factor" },
+ { OSQLParseNode::base_table_def, "base_table_def" },
+ { OSQLParseNode::base_table_element_commalist, "base_table_element_commalist" },
+ { OSQLParseNode::data_type, "data_type" },
+ { OSQLParseNode::column_def, "column_def" },
+ { OSQLParseNode::table_node, "table_node" },
+ { OSQLParseNode::as_clause, "as_clause" },
+ { OSQLParseNode::opt_as, "opt_as" },
+ { OSQLParseNode::op_column_commalist, "op_column_commalist" },
+ { OSQLParseNode::table_primary_as_range_column, "table_primary_as_range_column" },
+ { OSQLParseNode::datetime_primary, "datetime_primary" },
+ { OSQLParseNode::concatenation, "concatenation" },
+ { OSQLParseNode::char_factor, "char_factor" },
+ { OSQLParseNode::bit_value_fct, "bit_value_fct" },
+ { OSQLParseNode::comparison_predicate_part_2, "comparison_predicate_part_2" },
+ { OSQLParseNode::parenthesized_boolean_value_expression, "parenthesized_boolean_value_expression" },
+ { OSQLParseNode::character_string_type, "character_string_type" },
+ { OSQLParseNode::other_like_predicate_part_2, "other_like_predicate_part_2" },
+ { OSQLParseNode::between_predicate_part_2, "between_predicate_part_2" },
+ { OSQLParseNode::null_predicate_part_2, "null_predicate_part_2" },
+ { OSQLParseNode::cast_spec, "cast_spec" },
+ { OSQLParseNode::window_function, "window_function" }
+ };
+ const size_t nRuleMapCount = std::size( aRuleDescriptions );
+ // added a new rule? Adjust this map!
+ // +1 for UNKNOWN_RULE
+ static_assert(nRuleMapCount + 1 == static_cast<size_t>(OSQLParseNode::rule_count), "must be equal");
+
+ for (const auto & aRuleDescription : aRuleDescriptions)
+ {
+ // look up the rule description in the our identifier map
+ sal_uInt32 nParserRuleID = StrToRuleID( aRuleDescription.sRuleName );
+ // map the parser's rule ID to the OSQLParseNode::Rule
+ s_aReverseRuleIDLookup[ nParserRuleID ] = aRuleDescription.eRule;
+ // and map the OSQLParseNode::Rule to the parser's rule ID
+ s_nRuleIDs[ aRuleDescription.eRule ] = nParserRuleID;
+ }
+ }
+ ++s_nRefCount;
+
+ if (m_pContext == nullptr)
+ // take the default context
+ m_pContext = &s_aDefaultContext;
+
+ m_pData->aLocale = m_pContext->getPreferredLocale();
+}
+
+
+OSQLParser::~OSQLParser()
+{
+ ::osl::MutexGuard aGuard(getMutex());
+ OSL_ENSURE(s_nRefCount > 0, "OSQLParser::~OSQLParser() : suspicious call : has a refcount of 0 !");
+ if (!--s_nRefCount)
+ {
+ s_pScanner->setScanner(true);
+ delete s_pScanner;
+ s_pScanner = nullptr;
+
+ delete s_pGarbageCollector;
+ s_pGarbageCollector = nullptr;
+ // Is only set the first time, so we should delete it only when there are no more instances
+ s_xLocaleData = nullptr;
+
+ RuleIDMap().swap(s_aReverseRuleIDLookup);
+ }
+ m_pParseTree = nullptr;
+}
+
+void OSQLParseNode::substituteParameterNames(OSQLParseNode const * _pNode)
+{
+ sal_Int32 nCount = _pNode->count();
+ for(sal_Int32 i=0;i < nCount;++i)
+ {
+ OSQLParseNode* pChildNode = _pNode->getChild(i);
+ if(SQL_ISRULE(pChildNode,parameter) && pChildNode->count() > 1)
+ {
+ OSQLParseNode* pNewNode = new OSQLParseNode("?" ,SQLNodeType::Punctuation,0);
+ delete pChildNode->replace(pChildNode->getChild(0),pNewNode);
+ sal_Int32 nChildCount = pChildNode->count();
+ for(sal_Int32 j=1;j < nChildCount;++j)
+ delete pChildNode->removeAt(1);
+ }
+ else
+ substituteParameterNames(pChildNode);
+
+ }
+}
+
+bool OSQLParser::extractDate(OSQLParseNode const * pLiteral,double& _rfValue)
+{
+ Reference< XNumberFormatsSupplier > xFormatSup = m_xFormatter->getNumberFormatsSupplier();
+ Reference< XNumberFormatTypes > xFormatTypes;
+ if ( xFormatSup.is() )
+ xFormatTypes.set(xFormatSup->getNumberFormats(), css::uno::UNO_QUERY);
+
+ // if there is no format key, yet, make sure we have a feasible one for our locale
+ try
+ {
+ if ( !m_nFormatKey && xFormatTypes.is() )
+ m_nFormatKey = ::dbtools::getDefaultNumberFormat( m_xField, xFormatTypes, m_pData->aLocale );
+ }
+ catch( Exception& ) { }
+ const OUString& sValue = pLiteral->getTokenValue();
+ sal_Int32 nTryFormat = m_nFormatKey;
+ bool bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
+
+ // If our format key didn't do, try the default date format for our locale.
+ if ( !bSuccess && xFormatTypes.is() )
+ {
+ try
+ {
+ nTryFormat = xFormatTypes->getStandardFormat( NumberFormat::DATE, m_pData->aLocale );
+ }
+ catch( Exception& ) { }
+ bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
+ }
+
+ // if this also didn't do, try ISO format
+ if ( !bSuccess && xFormatTypes.is() )
+ {
+ try
+ {
+ nTryFormat = xFormatTypes->getFormatIndex( NumberFormatIndex::DATE_DIN_YYYYMMDD, m_pData->aLocale );
+ }
+ catch( Exception& ) { }
+ bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
+ }
+
+ // if this also didn't do, try fallback date format (en-US)
+ if ( !bSuccess )
+ {
+ nTryFormat = m_nDateFormatKey;
+ bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
+ }
+ return bSuccess;
+}
+
+OSQLParseNode* OSQLParser::buildDate(sal_Int32 _nType,OSQLParseNode*& pLiteral)
+{
+ // try converting the string into a date, according to our format key
+ double fValue = 0.0;
+ OSQLParseNode* pFCTNode = nullptr;
+
+ if ( extractDate(pLiteral,fValue) )
+ pFCTNode = buildNode_Date( fValue, _nType);
+
+ delete pLiteral;
+ pLiteral = nullptr;
+
+ if ( !pFCTNode )
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidDateCompare);
+
+ return pFCTNode;
+}
+
+
+OSQLParseNode::OSQLParseNode(const char * pNewValue,
+ SQLNodeType eNewNodeType,
+ sal_uInt32 nNewNodeID)
+ :m_pParent(nullptr)
+ ,m_aNodeValue(pNewValue,strlen(pNewValue),RTL_TEXTENCODING_UTF8)
+ ,m_eNodeType(eNewNodeType)
+ ,m_nNodeID(nNewNodeID)
+{
+ OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
+}
+
+OSQLParseNode::OSQLParseNode(std::string_view _rNewValue,
+ SQLNodeType eNewNodeType,
+ sal_uInt32 nNewNodeID)
+ :m_pParent(nullptr)
+ ,m_aNodeValue(OStringToOUString(_rNewValue,RTL_TEXTENCODING_UTF8))
+ ,m_eNodeType(eNewNodeType)
+ ,m_nNodeID(nNewNodeID)
+{
+ OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
+}
+
+OSQLParseNode::OSQLParseNode(const OUString &_rNewValue,
+ SQLNodeType eNewNodeType,
+ sal_uInt32 nNewNodeID)
+ :m_pParent(nullptr)
+ ,m_aNodeValue(_rNewValue)
+ ,m_eNodeType(eNewNodeType)
+ ,m_nNodeID(nNewNodeID)
+{
+ OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
+}
+
+OSQLParseNode::OSQLParseNode(const OSQLParseNode& rParseNode)
+{
+ // Set the getParent to NULL
+ m_pParent = nullptr;
+
+ // Copy the members
+ m_aNodeValue = rParseNode.m_aNodeValue;
+ m_eNodeType = rParseNode.m_eNodeType;
+ m_nNodeID = rParseNode.m_nNodeID;
+
+
+ // Remember that we derived from Container. According to SV-Help the Container's
+ // copy ctor creates a new Container with the same pointers for content.
+ // This means after copying the Container, for all non-NULL pointers a copy is
+ // created and reattached instead of the old pointer.
+
+ // If not a leaf, then process SubTrees
+ for (auto const& child : rParseNode.m_aChildren)
+ append(new OSQLParseNode(*child));
+}
+
+
+OSQLParseNode& OSQLParseNode::operator=(const OSQLParseNode& rParseNode)
+{
+ if (this != &rParseNode)
+ {
+ // Copy the members - pParent remains the same
+ m_aNodeValue = rParseNode.m_aNodeValue;
+ m_eNodeType = rParseNode.m_eNodeType;
+ m_nNodeID = rParseNode.m_nNodeID;
+
+ m_aChildren.clear();
+
+ for (auto const& child : rParseNode.m_aChildren)
+ append(new OSQLParseNode(*child));
+ }
+ return *this;
+}
+
+
+bool OSQLParseNode::operator==(OSQLParseNode const & rParseNode) const
+{
+ // The members must be equal
+ bool bResult = (m_nNodeID == rParseNode.m_nNodeID) &&
+ (m_eNodeType == rParseNode.m_eNodeType) &&
+ (m_aNodeValue == rParseNode.m_aNodeValue) &&
+ count() == rParseNode.count();
+
+ // Parameters are not equal!
+ bResult = bResult && !SQL_ISRULE(this, parameter);
+
+ // compare children
+ for (size_t i=0; bResult && i < count(); i++)
+ bResult = *getChild(i) == *rParseNode.getChild(i);
+
+ return bResult;
+}
+
+
+OSQLParseNode::~OSQLParseNode()
+{
+}
+
+
+void OSQLParseNode::append(OSQLParseNode* pNewNode)
+{
+ OSL_ENSURE(pNewNode != nullptr, "OSQLParseNode: invalid NewSubTree");
+ OSL_ENSURE(pNewNode->getParent() == nullptr, "OSQLParseNode: Node is not an orphan");
+ OSL_ENSURE(std::none_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewNode; }),
+ "OSQLParseNode::append() Node already element of parent");
+
+ // Create connection to getParent
+ pNewNode->setParent( this );
+ // and attach the SubTree at the end
+ m_aChildren.emplace_back(pNewNode);
+}
+
+bool OSQLParseNode::addDateValue(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
+{
+ // special display for date/time values
+ if (!SQL_ISRULE(this,set_fct_spec) || !SQL_ISPUNCTUATION(m_aChildren[0],"{"))
+ return false;
+
+ const OSQLParseNode* pODBCNode = m_aChildren[1].get();
+ const OSQLParseNode* pODBCNodeChild = pODBCNode->m_aChildren[0].get();
+
+ if (pODBCNodeChild->getNodeType() != SQLNodeType::Keyword || !(
+ SQL_ISTOKEN(pODBCNodeChild, D) ||
+ SQL_ISTOKEN(pODBCNodeChild, T) ||
+ SQL_ISTOKEN(pODBCNodeChild, TS) ))
+ return false;
+
+ OUString suQuote("'");
+ if (rParam.bPredicate)
+ {
+ if (rParam.aMetaData.shouldEscapeDateTime())
+ {
+ suQuote = "#";
+ }
+ }
+ else
+ {
+ if (rParam.aMetaData.shouldEscapeDateTime())
+ {
+ // suQuote = "'";
+ return false;
+ }
+ }
+
+ if (!rString.isEmpty())
+ rString.append(" ");
+ rString.append(suQuote);
+ const OUString sTokenValue = pODBCNode->m_aChildren[1]->getTokenValue();
+ if (SQL_ISTOKEN(pODBCNodeChild, D))
+ {
+ rString.append(rParam.bPredicate ? convertDateString(rParam, sTokenValue) : sTokenValue);
+ }
+ else if (SQL_ISTOKEN(pODBCNodeChild, T))
+ {
+ rString.append(rParam.bPredicate ? convertTimeString(rParam, sTokenValue) : sTokenValue);
+ }
+ else
+ {
+ rString.append(rParam.bPredicate ? convertDateTimeString(rParam, sTokenValue) : sTokenValue);
+ }
+ rString.append(suQuote);
+ return true;
+}
+
+void OSQLParseNode::replaceNodeValue(const OUString& rTableAlias, const OUString& rColumnName)
+{
+ for (size_t i=0;i<count();++i)
+ {
+ if (SQL_ISRULE(this,column_ref) && count() == 1 && getChild(0)->getTokenValue() == rColumnName)
+ {
+ OSQLParseNode * pCol = removeAt(sal_uInt32(0));
+ append(new OSQLParseNode(rTableAlias,SQLNodeType::Name));
+ append(new OSQLParseNode(".",SQLNodeType::Punctuation));
+ append(pCol);
+ }
+ else
+ getChild(i)->replaceNodeValue(rTableAlias,rColumnName);
+ }
+}
+
+OSQLParseNode* OSQLParseNode::getByRule(OSQLParseNode::Rule eRule) const
+{
+ OSQLParseNode* pRetNode = nullptr;
+ if (isRule() && OSQLParser::RuleID(eRule) == getRuleID())
+ pRetNode = const_cast<OSQLParseNode*>(this);
+ else
+ {
+ for (auto const& child : m_aChildren)
+ {
+ pRetNode = child->getByRule(eRule);
+ if (pRetNode)
+ break;
+ }
+ }
+ return pRetNode;
+}
+
+static OSQLParseNode* MakeANDNode(OSQLParseNode *pLeftLeaf,OSQLParseNode *pRightLeaf)
+{
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_term));
+ pNewNode->append(pLeftLeaf);
+ pNewNode->append(new OSQLParseNode("AND",SQLNodeType::Keyword,SQL_TOKEN_AND));
+ pNewNode->append(pRightLeaf);
+ return pNewNode;
+}
+
+static OSQLParseNode* MakeORNode(OSQLParseNode *pLeftLeaf,OSQLParseNode *pRightLeaf)
+{
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::search_condition));
+ pNewNode->append(pLeftLeaf);
+ pNewNode->append(new OSQLParseNode("OR",SQLNodeType::Keyword,SQL_TOKEN_OR));
+ pNewNode->append(pRightLeaf);
+ return pNewNode;
+}
+
+void OSQLParseNode::disjunctiveNormalForm(OSQLParseNode*& pSearchCondition)
+{
+ if(!pSearchCondition) // no where condition at entry point
+ return;
+
+ OSQLParseNode::absorptions(pSearchCondition);
+ // '(' search_condition ')'
+ if (SQL_ISRULE(pSearchCondition,boolean_primary))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(1);
+ disjunctiveNormalForm(pLeft);
+ }
+ // search_condition SQL_TOKEN_OR boolean_term
+ else if (SQL_ISRULE(pSearchCondition,search_condition))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ disjunctiveNormalForm(pLeft);
+
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ disjunctiveNormalForm(pRight);
+ }
+ // boolean_term SQL_TOKEN_AND boolean_factor
+ else if (SQL_ISRULE(pSearchCondition,boolean_term))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ disjunctiveNormalForm(pLeft);
+
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ disjunctiveNormalForm(pRight);
+
+ OSQLParseNode* pNewNode = nullptr;
+ // '(' search_condition ')' on left side
+ if(pLeft->count() == 3 && SQL_ISRULE(pLeft,boolean_primary) && SQL_ISRULE(pLeft->getChild(1),search_condition))
+ {
+ // and-or tree on left side
+ OSQLParseNode* pOr = pLeft->getChild(1);
+ OSQLParseNode* pNewLeft = nullptr;
+ OSQLParseNode* pNewRight = nullptr;
+
+ // cut right from parent
+ OSQLParseNode* pOldRight = pSearchCondition->removeAt(2);
+ assert(pOldRight == pRight);
+
+ pNewRight = MakeANDNode(pOr->removeAt(2), pOldRight);
+ pNewLeft = MakeANDNode(pOr->removeAt(sal_uInt32(0)), new OSQLParseNode(*pOldRight));
+ pNewNode = MakeORNode(pNewLeft,pNewRight);
+ // and append new Node
+ replaceAndReset(pSearchCondition,pNewNode);
+
+ disjunctiveNormalForm(pSearchCondition);
+ }
+ else if(pRight->count() == 3 && SQL_ISRULE(pRight,boolean_primary) && SQL_ISRULE(pRight->getChild(1),search_condition))
+ { // '(' search_condition ')' on right side
+ // and-or tree on right side
+ // a and (b or c)
+ OSQLParseNode* pOr = pRight->getChild(1);
+ OSQLParseNode* pNewLeft = nullptr;
+ OSQLParseNode* pNewRight = nullptr;
+
+ // cut left from parent
+ OSQLParseNode* pOldLeft = pSearchCondition->removeAt(sal_uInt32(0));
+ assert(pOldLeft == pLeft);
+
+ pNewRight = MakeANDNode(pOldLeft, pOr->removeAt(2));
+ pNewLeft = MakeANDNode(new OSQLParseNode(*pOldLeft), pOr->removeAt(sal_uInt32(0)));
+ pNewNode = MakeORNode(pNewLeft,pNewRight);
+
+ // and append new Node
+ replaceAndReset(pSearchCondition,pNewNode);
+ disjunctiveNormalForm(pSearchCondition);
+ }
+ else if(SQL_ISRULE(pLeft,boolean_primary) && (!SQL_ISRULE(pLeft->getChild(1),search_condition) || !SQL_ISRULE(pLeft->getChild(1),boolean_term)))
+ pSearchCondition->replace(pLeft, pLeft->removeAt(1));
+ else if(SQL_ISRULE(pRight,boolean_primary) && (!SQL_ISRULE(pRight->getChild(1),search_condition) || !SQL_ISRULE(pRight->getChild(1),boolean_term)))
+ pSearchCondition->replace(pRight, pRight->removeAt(1));
+ }
+}
+
+void OSQLParseNode::negateSearchCondition(OSQLParseNode*& pSearchCondition, bool bNegate)
+{
+ if(!pSearchCondition) // no where condition at entry point
+ return;
+ // '(' search_condition ')'
+ if (pSearchCondition->count() == 3 && SQL_ISRULE(pSearchCondition,boolean_primary))
+ {
+ OSQLParseNode* pRight = pSearchCondition->getChild(1);
+ negateSearchCondition(pRight,bNegate);
+ }
+ // search_condition SQL_TOKEN_OR boolean_term
+ else if (SQL_ISRULE(pSearchCondition,search_condition))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ if(bNegate)
+ {
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_term));
+ pNewNode->append(pSearchCondition->removeAt(sal_uInt32(0)));
+ pNewNode->append(new OSQLParseNode("AND",SQLNodeType::Keyword,SQL_TOKEN_AND));
+ pNewNode->append(pSearchCondition->removeAt(sal_uInt32(1)));
+ replaceAndReset(pSearchCondition,pNewNode);
+
+ pLeft = pNewNode->getChild(0);
+ pRight = pNewNode->getChild(2);
+ }
+
+ negateSearchCondition(pLeft,bNegate);
+ negateSearchCondition(pRight,bNegate);
+ }
+ // boolean_term SQL_TOKEN_AND boolean_factor
+ else if (SQL_ISRULE(pSearchCondition,boolean_term))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ if(bNegate)
+ {
+ OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::search_condition));
+ pNewNode->append(pSearchCondition->removeAt(sal_uInt32(0)));
+ pNewNode->append(new OSQLParseNode("OR",SQLNodeType::Keyword,SQL_TOKEN_OR));
+ pNewNode->append(pSearchCondition->removeAt(sal_uInt32(1)));
+ replaceAndReset(pSearchCondition,pNewNode);
+
+ pLeft = pNewNode->getChild(0);
+ pRight = pNewNode->getChild(2);
+ }
+
+ negateSearchCondition(pLeft,bNegate);
+ negateSearchCondition(pRight,bNegate);
+ }
+ // SQL_TOKEN_NOT ( boolean_primary )
+ else if (SQL_ISRULE(pSearchCondition,boolean_factor))
+ {
+ OSQLParseNode *pNot = pSearchCondition->removeAt(sal_uInt32(0));
+ delete pNot;
+ OSQLParseNode *pBooleanTest = pSearchCondition->removeAt(sal_uInt32(0));
+ // TODO is this needed // pBooleanTest->setParent(NULL);
+ replaceAndReset(pSearchCondition,pBooleanTest);
+
+ if (!bNegate)
+ negateSearchCondition(pSearchCondition, true); // negate all deeper values
+ }
+ // row_value_constructor comparison row_value_constructor
+ // row_value_constructor comparison any_all_some subquery
+ else if(bNegate && (SQL_ISRULE(pSearchCondition,comparison_predicate) || SQL_ISRULE(pSearchCondition,all_or_any_predicate)))
+ {
+ assert(pSearchCondition->count() == 3);
+ OSQLParseNode* pComparison = pSearchCondition->getChild(1);
+ if(SQL_ISRULE(pComparison, comparison))
+ {
+ assert(pComparison->count() == 2 ||
+ pComparison->count() == 4);
+ assert(SQL_ISTOKEN(pComparison->getChild(0), IS));
+
+ OSQLParseNode* pNot = pComparison->getChild(1);
+ OSQLParseNode* pNotNot = nullptr;
+ if(pNot->isRule()) // no NOT token (empty rule)
+ pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
+ else
+ {
+ assert(SQL_ISTOKEN(pNot,NOT));
+ pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
+ }
+ pComparison->replace(pNot, pNotNot);
+ delete pNot;
+ }
+ else
+ {
+ OSQLParseNode* pNewComparison;
+ switch(pComparison->getNodeType())
+ {
+ default:
+ case SQLNodeType::Equal:
+ assert(pComparison->getNodeType() == SQLNodeType::Equal &&
+ "OSQLParseNode::negateSearchCondition: unexpected node type!");
+ pNewComparison = new OSQLParseNode("<>",SQLNodeType::NotEqual,SQL_NOTEQUAL);
+ break;
+ case SQLNodeType::Less:
+ pNewComparison = new OSQLParseNode(">=",SQLNodeType::GreatEq,SQL_GREATEQ);
+ break;
+ case SQLNodeType::Great:
+ pNewComparison = new OSQLParseNode("<=",SQLNodeType::LessEq,SQL_LESSEQ);
+ break;
+ case SQLNodeType::LessEq:
+ pNewComparison = new OSQLParseNode(">",SQLNodeType::Great,SQL_GREAT);
+ break;
+ case SQLNodeType::GreatEq:
+ pNewComparison = new OSQLParseNode("<",SQLNodeType::Less,SQL_LESS);
+ break;
+ case SQLNodeType::NotEqual:
+ pNewComparison = new OSQLParseNode("=",SQLNodeType::Equal,SQL_EQUAL);
+ break;
+ }
+ pSearchCondition->replace(pComparison, pNewComparison);
+ delete pComparison;
+ }
+ }
+
+ else if(bNegate && (SQL_ISRULE(pSearchCondition,test_for_null) ||
+ SQL_ISRULE(pSearchCondition,in_predicate) ||
+ SQL_ISRULE(pSearchCondition,between_predicate) ))
+ {
+ OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+ sal_uInt32 nNotPos = 0;
+ if ( SQL_ISRULE( pSearchCondition, test_for_null ) )
+ nNotPos = 1;
+
+ OSQLParseNode* pNot = pPart2->getChild(nNotPos);
+ OSQLParseNode* pNotNot = nullptr;
+ if(pNot->isRule()) // no NOT token (empty rule)
+ pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
+ else
+ {
+ assert(SQL_ISTOKEN(pNot,NOT));
+ pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
+ }
+ pPart2->replace(pNot, pNotNot);
+ delete pNot;
+ }
+ else if(bNegate && SQL_ISRULE(pSearchCondition,like_predicate))
+ {
+ OSQLParseNode* pNot = pSearchCondition->getChild( 1 )->getChild( 0 );
+ OSQLParseNode* pNotNot = nullptr;
+ if(pNot->isRule())
+ pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
+ else
+ pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
+ pSearchCondition->getChild( 1 )->replace(pNot, pNotNot);
+ delete pNot;
+ }
+}
+
+void OSQLParseNode::eraseBraces(OSQLParseNode*& pSearchCondition)
+{
+ if (!(pSearchCondition && (SQL_ISRULE(pSearchCondition,boolean_primary) || (pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")))))
+ return;
+
+ OSQLParseNode* pRight = pSearchCondition->getChild(1);
+ absorptions(pRight);
+ // if child is not an or and tree then delete () around child
+ if(!(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || SQL_ISRULE(pSearchCondition->getChild(1),search_condition)) ||
+ SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || // and can always stand without ()
+ (SQL_ISRULE(pSearchCondition->getChild(1),search_condition) && SQL_ISRULE(pSearchCondition->getParent(),search_condition)))
+ {
+ OSQLParseNode* pNode = pSearchCondition->removeAt(1);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+}
+
+void OSQLParseNode::absorptions(OSQLParseNode*& pSearchCondition)
+{
+ if(!pSearchCondition) // no where condition at entry point
+ return;
+
+ eraseBraces(pSearchCondition);
+
+ if(SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ absorptions(pLeft);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ absorptions(pRight);
+ }
+
+ sal_uInt32 nPos = 0;
+ // a and a || a or a
+ OSQLParseNode* pNewNode = nullptr;
+ if(( SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
+ && *pSearchCondition->getChild(0) == *pSearchCondition->getChild(2))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ // ( a or b ) and a || ( b or c ) and a
+ // a and ( a or b ) || a and ( b or c )
+ else if ( SQL_ISRULE(pSearchCondition,boolean_term)
+ && (
+ ( SQL_ISRULE(pSearchCondition->getChild(nPos = 0),boolean_primary)
+ || SQL_ISRULE(pSearchCondition->getChild(nPos),search_condition)
+ )
+ || ( SQL_ISRULE(pSearchCondition->getChild(nPos = 2),boolean_primary)
+ || SQL_ISRULE(pSearchCondition->getChild(nPos),search_condition)
+ )
+ )
+ )
+ {
+ OSQLParseNode* p2ndSearch = pSearchCondition->getChild(nPos);
+ if ( SQL_ISRULE(p2ndSearch,boolean_primary) )
+ p2ndSearch = p2ndSearch->getChild(1);
+
+ if ( *p2ndSearch->getChild(0) == *pSearchCondition->getChild(2-nPos) ) // a and ( a or b) -> a or b
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
+ replaceAndReset(pSearchCondition,pNewNode);
+
+ }
+ else if ( *p2ndSearch->getChild(2) == *pSearchCondition->getChild(2-nPos) ) // a and ( b or a) -> a or b
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ else if ( p2ndSearch->getByRule(OSQLParseNode::search_condition) )
+ {
+ // a and ( b or c ) -> ( a and b ) or ( a and c )
+ // ( b or c ) and a -> ( a and b ) or ( a and c )
+ OSQLParseNode* pC = p2ndSearch->removeAt(sal_uInt32(2));
+ OSQLParseNode* pB = p2ndSearch->removeAt(sal_uInt32(0));
+ OSQLParseNode* pA = pSearchCondition->removeAt(sal_uInt32(2)-nPos);
+
+ OSQLParseNode* p1stAnd = MakeANDNode(pA,pB);
+ OSQLParseNode* p2ndAnd = MakeANDNode(new OSQLParseNode(*pA),pC);
+ pNewNode = MakeORNode(p1stAnd,p2ndAnd);
+ OSQLParseNode* pNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNode->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNode->append(pNewNode);
+ pNode->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+ OSQLParseNode::eraseBraces(p1stAnd);
+ OSQLParseNode::eraseBraces(p2ndAnd);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ }
+ // a or a and b || a or b and a
+ else if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(2),boolean_term))
+ {
+ if(*pSearchCondition->getChild(2)->getChild(0) == *pSearchCondition->getChild(0))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ else if(*pSearchCondition->getChild(2)->getChild(2) == *pSearchCondition->getChild(0))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ }
+ // a and b or a || b and a or a
+ else if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(0),boolean_term))
+ {
+ if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2))
+ {
+ pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
+ replaceAndReset(pSearchCondition,pNewNode);
+ }
+ }
+ eraseBraces(pSearchCondition);
+}
+
+void OSQLParseNode::compress(OSQLParseNode *&pSearchCondition)
+{
+ if(!pSearchCondition) // no WHERE condition at entry point
+ return;
+
+ OSQLParseNode::eraseBraces(pSearchCondition);
+
+ if(SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0);
+ compress(pLeft);
+
+ OSQLParseNode* pRight = pSearchCondition->getChild(2);
+ compress(pRight);
+ }
+ else if( SQL_ISRULE(pSearchCondition,boolean_primary) || (pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")))
+ {
+ OSQLParseNode* pRight = pSearchCondition->getChild(1);
+ compress(pRight);
+ // if child is not an or and tree then delete () around child
+ if(!(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || SQL_ISRULE(pSearchCondition->getChild(1),search_condition)) ||
+ (SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) && SQL_ISRULE(pSearchCondition->getParent(),boolean_term)) ||
+ (SQL_ISRULE(pSearchCondition->getChild(1),search_condition) && SQL_ISRULE(pSearchCondition->getParent(),search_condition)))
+ {
+ OSQLParseNode* pNode = pSearchCondition->removeAt(1);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ }
+
+ // or with two and trees where one element of the and trees are equal
+ if(!(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(0),boolean_term) && SQL_ISRULE(pSearchCondition->getChild(2),boolean_term)))
+ return;
+
+ if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)->getChild(0))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(2);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(2);
+ OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
+
+ OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNewRule->append(pNode);
+ pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+
+ OSQLParseNode::eraseBraces(pLeft);
+ OSQLParseNode::eraseBraces(pRight);
+
+ pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)),pNewRule);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)->getChild(0))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(sal_uInt32(0));
+ OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(2);
+ OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
+
+ OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNewRule->append(pNode);
+ pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+
+ OSQLParseNode::eraseBraces(pLeft);
+ OSQLParseNode::eraseBraces(pRight);
+
+ pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(1),pNewRule);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ else if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)->getChild(2))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(2);
+ OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(sal_uInt32(0));
+ OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
+
+ OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNewRule->append(pNode);
+ pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+
+ OSQLParseNode::eraseBraces(pLeft);
+ OSQLParseNode::eraseBraces(pRight);
+
+ pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)),pNewRule);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+ else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)->getChild(2))
+ {
+ OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(sal_uInt32(0));
+ OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(sal_uInt32(0));
+ OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
+
+ OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
+ pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
+ pNewRule->append(pNode);
+ pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
+
+ OSQLParseNode::eraseBraces(pLeft);
+ OSQLParseNode::eraseBraces(pRight);
+
+ pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(1),pNewRule);
+ replaceAndReset(pSearchCondition,pNode);
+ }
+}
+#if OSL_DEBUG_LEVEL > 1
+
+void OSQLParseNode::showParseTree( OUString& rString ) const
+{
+ OUStringBuffer aBuf;
+ showParseTree( aBuf, 0 );
+ rString = aBuf.makeStringAndClear();
+}
+
+
+void OSQLParseNode::showParseTree( OUStringBuffer& _inout_rBuffer, sal_uInt32 nLevel ) const
+{
+ for ( sal_uInt32 j=0; j<nLevel; ++j)
+ _inout_rBuffer.appendAscii( " " );
+
+ if ( !isToken() )
+ {
+ // Rule name as rule
+ _inout_rBuffer.appendAscii( "RULE_ID: " );
+ _inout_rBuffer.append( (sal_Int32)getRuleID() );
+ _inout_rBuffer.append( '(' );
+ _inout_rBuffer.append( OSQLParser::RuleIDToStr( getRuleID() ) );
+ _inout_rBuffer.append( ')' );
+ _inout_rBuffer.append( '\n' );
+
+ // Get the first sub tree
+ for (auto const& child : m_aChildren)
+ child->showParseTree( _inout_rBuffer, nLevel+1 );
+ }
+ else
+ {
+ // Found a token
+ switch (m_eNodeType)
+ {
+
+ case SQLNodeType::Keyword:
+ _inout_rBuffer.appendAscii( "SQL_KEYWORD: " );
+ _inout_rBuffer.append( OStringToOUString( OSQLParser::TokenIDToStr( getTokenID() ), RTL_TEXTENCODING_UTF8 ) );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::Name:
+ _inout_rBuffer.appendAscii( "SQL_NAME: " );
+ _inout_rBuffer.append( '"' );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '"' );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::String:
+ _inout_rBuffer.appendAscii( "SQL_STRING: " );
+ _inout_rBuffer.append( '\'' );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\'' );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::IntNum:
+ _inout_rBuffer.appendAscii( "SQL_INTNUM: " );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::ApproxNum:
+ _inout_rBuffer.appendAscii( "SQL_APPROXNUM: " );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::Punctuation:
+ _inout_rBuffer.appendAscii( "SQL_PUNCTUATION: " );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::Equal:
+ case SQLNodeType::Less:
+ case SQLNodeType::Great:
+ case SQLNodeType::LessEq:
+ case SQLNodeType::GreatEq:
+ case SQLNodeType::NotEqual:
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::AccessDate:
+ _inout_rBuffer.appendAscii( "SQL_ACCESS_DATE: " );
+ _inout_rBuffer.append( m_aNodeValue );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ case SQLNodeType::Concat:
+ _inout_rBuffer.appendAscii( "||" );
+ _inout_rBuffer.append( '\n' );
+ break;
+
+ default:
+ SAL_INFO( "connectivity.parse", "-- " << int( m_eNodeType ) );
+ SAL_WARN( "connectivity.parse", "OSQLParser::ShowParseTree: unzulaessiger NodeType" );
+ }
+ }
+}
+#endif // OSL_DEBUG_LEVEL > 0
+
+// Insert methods
+
+void OSQLParseNode::insert(sal_uInt32 nPos, OSQLParseNode* pNewSubTree)
+{
+ OSL_ENSURE(pNewSubTree != nullptr, "OSQLParseNode: invalid NewSubTree");
+ OSL_ENSURE(pNewSubTree->getParent() == nullptr, "OSQLParseNode: Node is not an orphan");
+
+ // Create connection to getParent
+ pNewSubTree->setParent( this );
+ m_aChildren.emplace(m_aChildren.begin() + nPos, pNewSubTree);
+}
+
+// removeAt methods
+
+OSQLParseNode* OSQLParseNode::removeAt(sal_uInt32 nPos)
+{
+ OSL_ENSURE(nPos < m_aChildren.size(),"Illegal position for removeAt");
+ auto aPos(m_aChildren.begin() + nPos);
+ auto pNode = std::move(*aPos);
+
+ // Set the getParent of the removed node to NULL
+ pNode->setParent( nullptr );
+
+ m_aChildren.erase(aPos);
+ return pNode.release();
+}
+
+// Replace methods
+
+OSQLParseNode* OSQLParseNode::replace(OSQLParseNode* pOldSubNode, OSQLParseNode* pNewSubNode )
+{
+ OSL_ENSURE(pOldSubNode != nullptr && pNewSubNode != nullptr, "OSQLParseNode: invalid nodes");
+ OSL_ENSURE(pNewSubNode->getParent() == nullptr, "OSQLParseNode: node already has getParent");
+ OSL_ENSURE(std::any_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pOldSubNode; }),
+ "OSQLParseNode::Replace() Node not element of parent");
+ OSL_ENSURE(std::none_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewSubNode; }),
+ "OSQLParseNode::Replace() Node already element of parent");
+
+ pOldSubNode->setParent( nullptr );
+ pNewSubNode->setParent( this );
+ auto it = std::find_if(m_aChildren.begin(), m_aChildren.end(),
+ [&pOldSubNode](const std::unique_ptr<OSQLParseNode>& rxChild) { return rxChild.get() == pOldSubNode; });
+ if (it != m_aChildren.end())
+ {
+ it->release();
+ it->reset(pNewSubNode);
+ }
+ return pOldSubNode;
+}
+
+void OSQLParseNode::parseLeaf(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
+{
+ // Found a leaf
+ // Append content to the output string
+ switch (m_eNodeType)
+ {
+ case SQLNodeType::Keyword:
+ {
+ if (!rString.isEmpty())
+ rString.append(" ");
+
+ const OString sT = OSQLParser::TokenIDToStr(m_nNodeID, rParam.bInternational ? &rParam.m_rContext : nullptr);
+ rString.append(OStringToOUString(sT,RTL_TEXTENCODING_UTF8));
+ } break;
+ case SQLNodeType::String:
+ if (!rString.isEmpty())
+ rString.append(" ");
+ rString.append(SetQuotation(m_aNodeValue, "\'", u"\'\'"));
+ break;
+ case SQLNodeType::Name:
+ if (!rString.isEmpty())
+ {
+ switch(rString[rString.getLength()-1])
+ {
+ case ' ' :
+ case '.' : break;
+ default :
+ if ( rParam.aMetaData.getCatalogSeparator().isEmpty()
+ || rString[rString.getLength() - 1] != rParam.aMetaData.getCatalogSeparator().toChar()
+ )
+ rString.append(" ");
+ break;
+ }
+ }
+ if (rParam.bQuote)
+ {
+ if (rParam.bPredicate)
+ {
+ rString.append("[");
+ rString.append(m_aNodeValue);
+ rString.append("]");
+ }
+ else
+ rString.append(SetQuotation(m_aNodeValue,
+ rParam.aMetaData.getIdentifierQuoteString(), rParam.aMetaData.getIdentifierQuoteString() ));
+ }
+ else
+ rString.append(m_aNodeValue);
+ break;
+ case SQLNodeType::AccessDate:
+ if (!rString.isEmpty())
+ rString.append(" ");
+ rString.append("#");
+ rString.append(m_aNodeValue);
+ rString.append("#");
+ break;
+
+ case SQLNodeType::IntNum:
+ case SQLNodeType::ApproxNum:
+ {
+ OUString aTmp = m_aNodeValue;
+ static constexpr OUStringLiteral strPoint(u".");
+ if (rParam.bInternational && rParam.bPredicate && rParam.sDecSep != strPoint)
+ aTmp = aTmp.replaceAll(strPoint, rParam.sDecSep);
+
+ if (!rString.isEmpty())
+ rString.append(" ");
+ rString.append(aTmp);
+
+ } break;
+ case SQLNodeType::Punctuation:
+ if ( getParent() && SQL_ISRULE(getParent(),cast_spec) && m_aNodeValue.toChar() == '(' ) // no spaces in front of '('
+ {
+ rString.append(m_aNodeValue);
+ break;
+ }
+ [[fallthrough]];
+ default:
+ if (!rString.isEmpty() && m_aNodeValue.toChar() != '.' && m_aNodeValue.toChar() != ':' )
+ {
+ switch( rString[rString.getLength() - 1] )
+ {
+ case ' ' :
+ case '.' : break;
+ default :
+ if ( rParam.aMetaData.getCatalogSeparator().isEmpty()
+ || rString[rString.getLength() - 1] != rParam.aMetaData.getCatalogSeparator().toChar()
+ )
+ rString.append(" ");
+ break;
+ }
+ }
+ rString.append(m_aNodeValue);
+ }
+}
+
+
+sal_Int32 OSQLParser::getFunctionReturnType(std::u16string_view _sFunctionName, const IParseContext* pContext)
+{
+ sal_Int32 nType = DataType::VARCHAR;
+ OString sFunctionName(OUStringToOString(_sFunctionName,RTL_TEXTENCODING_UTF8));
+
+ if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ASCII,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_BIT_LENGTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CHAR,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CHAR_LENGTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CONCAT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DIFFERENCE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_INSERT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LCASE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LEFT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LENGTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOCATE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOCATE_2,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LTRIM,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_OCTET_LENGTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_POSITION,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_REPEAT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_REPLACE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RIGHT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RTRIM,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SOUNDEX,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SPACE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SUBSTRING,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_UCASE,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_DATE,pContext))) nType = DataType::DATE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_TIME,pContext))) nType = DataType::TIME;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_TIMESTAMP,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURDATE,pContext))) nType = DataType::DATE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DATEDIFF,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DATEVALUE,pContext))) nType = DataType::DATE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURTIME,pContext))) nType = DataType::TIME;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYNAME,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFMONTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFWEEK,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFYEAR,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_EXTRACT,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_HOUR,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MINUTE,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MONTH,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MONTHNAME,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_NOW,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_QUARTER,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SECOND,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMESTAMPADD,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMESTAMPDIFF,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMEVALUE,pContext))) nType = DataType::TIMESTAMP;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_WEEK,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_YEAR,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ABS,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ACOS,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ASIN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ATAN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ATAN2,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CEILING,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COS,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COT,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DEGREES,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_EXP,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_FLOOR,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOGF,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOG,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOG10,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MOD,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_PI,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_POWER,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RADIANS,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RAND,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ROUND,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ROUNDMAGIC,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SIGN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SIN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SQRT,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TAN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TRUNCATE,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COUNT,pContext))) nType = DataType::INTEGER;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MAX,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MIN,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_AVG,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SUM,pContext))) nType = DataType::DOUBLE;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOWER,pContext))) nType = DataType::VARCHAR;
+ else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_UPPER,pContext))) nType = DataType::VARCHAR;
+
+ return nType;
+}
+
+sal_Int32 OSQLParser::getFunctionParameterType(sal_uInt32 _nTokenId, sal_uInt32 _nPos)
+{
+ sal_Int32 nType = DataType::VARCHAR;
+
+ if(_nTokenId == SQL_TOKEN_CHAR) nType = DataType::INTEGER;
+ else if(_nTokenId == SQL_TOKEN_INSERT)
+ {
+ if ( _nPos == 2 || _nPos == 3 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_LEFT)
+ {
+ if ( _nPos == 2 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_LOCATE)
+ {
+ if ( _nPos == 3 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_LOCATE_2)
+ {
+ if ( _nPos == 3 )
+ nType = DataType::INTEGER;
+ }
+ else if( _nTokenId == SQL_TOKEN_REPEAT || _nTokenId == SQL_TOKEN_RIGHT )
+ {
+ if ( _nPos == 2 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_SPACE )
+ {
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_SUBSTRING)
+ {
+ if ( _nPos != 1 )
+ nType = DataType::INTEGER;
+ }
+ else if(_nTokenId == SQL_TOKEN_DATEDIFF)
+ {
+ if ( _nPos != 1 )
+ nType = DataType::TIMESTAMP;
+ }
+ else if(_nTokenId == SQL_TOKEN_DATEVALUE)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_DAYNAME)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_DAYOFMONTH)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_DAYOFWEEK)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_DAYOFYEAR)
+ nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_EXTRACT) nType = DataType::VARCHAR;
+ else if(_nTokenId == SQL_TOKEN_HOUR) nType = DataType::TIME;
+ else if(_nTokenId == SQL_TOKEN_MINUTE) nType = DataType::TIME;
+ else if(_nTokenId == SQL_TOKEN_MONTH) nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_MONTHNAME) nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_NOW) nType = DataType::TIMESTAMP;
+ else if(_nTokenId == SQL_TOKEN_QUARTER) nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_SECOND) nType = DataType::TIME;
+ else if(_nTokenId == SQL_TOKEN_TIMESTAMPADD) nType = DataType::TIMESTAMP;
+ else if(_nTokenId == SQL_TOKEN_TIMESTAMPDIFF) nType = DataType::TIMESTAMP;
+ else if(_nTokenId == SQL_TOKEN_TIMEVALUE) nType = DataType::TIMESTAMP;
+ else if(_nTokenId == SQL_TOKEN_WEEK) nType = DataType::DATE;
+ else if(_nTokenId == SQL_TOKEN_YEAR) nType = DataType::DATE;
+
+ else if(_nTokenId == SQL_TOKEN_ABS) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ACOS) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ASIN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ATAN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ATAN2) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_CEILING) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_COS) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_COT) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_DEGREES) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_EXP) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_FLOOR) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_LOGF) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_LOG) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_LOG10) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_LN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_MOD) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_PI) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_POWER) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_RADIANS) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_RAND) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ROUND) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_ROUNDMAGIC) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_SIGN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_SIN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_SQRT) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_TAN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_TRUNCATE) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_COUNT) nType = DataType::INTEGER;
+ else if(_nTokenId == SQL_TOKEN_MAX) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_MIN) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_AVG) nType = DataType::DOUBLE;
+ else if(_nTokenId == SQL_TOKEN_SUM) nType = DataType::DOUBLE;
+
+ else if(_nTokenId == SQL_TOKEN_LOWER) nType = DataType::VARCHAR;
+ else if(_nTokenId == SQL_TOKEN_UPPER) nType = DataType::VARCHAR;
+
+ return nType;
+}
+
+
+const SQLError& OSQLParser::getErrorHelper() const
+{
+ return m_pData->aErrors;
+}
+
+
+OSQLParseNode::Rule OSQLParseNode::getKnownRuleID() const
+{
+ if ( !isRule() )
+ return UNKNOWN_RULE;
+ return OSQLParser::RuleIDToRule( getRuleID() );
+}
+
+OUString OSQLParseNode::getTableRange(const OSQLParseNode* _pTableRef)
+{
+ OSL_ENSURE(_pTableRef && _pTableRef->count() > 1 && _pTableRef->getKnownRuleID() == OSQLParseNode::table_ref,"Invalid node give, only table ref is allowed!");
+ const sal_uInt32 nCount = _pTableRef->count();
+ OUString sTableRange;
+ if ( nCount == 2 || (nCount == 3 && !_pTableRef->getChild(0)->isToken()) )
+ {
+ const OSQLParseNode* pNode = _pTableRef->getChild(nCount - (nCount == 2 ? 1 : 2));
+ OSL_ENSURE(pNode && (pNode->getKnownRuleID() == OSQLParseNode::table_primary_as_range_column
+ || pNode->getKnownRuleID() == OSQLParseNode::range_variable)
+ ,"SQL grammar changed!");
+ if ( !pNode->isLeaf() )
+ sTableRange = pNode->getChild(1)->getTokenValue();
+ } // if ( nCount == 2 || nCount == 3 )
+
+ return sTableRange;
+}
+
+OSQLParseNodesContainer::OSQLParseNodesContainer()
+{
+}
+
+OSQLParseNodesContainer::~OSQLParseNodesContainer()
+{
+}
+
+void OSQLParseNodesContainer::push_back(OSQLParseNode* _pNode)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_aNodes.push_back(_pNode);
+}
+
+void OSQLParseNodesContainer::erase(OSQLParseNode* _pNode)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( !m_aNodes.empty() )
+ {
+ std::vector< OSQLParseNode* >::iterator aFind = std::find(m_aNodes.begin(), m_aNodes.end(),_pNode);
+ if ( aFind != m_aNodes.end() )
+ m_aNodes.erase(aFind);
+ }
+}
+
+void OSQLParseNodesContainer::clear()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_aNodes.clear();
+}
+
+void OSQLParseNodesContainer::clearAndDelete()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ // clear the garbage collector
+ while ( !m_aNodes.empty() )
+ {
+ OSQLParseNode* pNode = m_aNodes[0];
+ while ( pNode->getParent() )
+ {
+ pNode = pNode->getParent();
+ }
+ delete pNode;
+ }
+}
+} // namespace connectivity
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/resource/sharedresources.cxx b/connectivity/source/resource/sharedresources.cxx
new file mode 100644
index 000000000..0f8bccefd
--- /dev/null
+++ b/connectivity/source/resource/sharedresources.cxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <resource/sharedresources.hxx>
+
+#include <unotools/resmgr.hxx>
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <sal/log.hxx>
+
+namespace connectivity
+{
+ namespace {
+
+ class SharedResources_Impl
+ {
+ private:
+ static SharedResources_Impl* s_pInstance;
+ static oslInterlockedCount s_nClients;
+
+ private:
+ std::locale m_aLocale;
+
+ public:
+ static void registerClient();
+ static void revokeClient();
+
+ static SharedResources_Impl&
+ getInstance();
+
+ OUString getResourceString(TranslateId pId) const;
+
+ private:
+ SharedResources_Impl();
+
+ static ::osl::Mutex& getMutex()
+ {
+ static ::osl::Mutex s_aMutex;
+ return s_aMutex;
+ }
+ };
+
+ }
+
+ SharedResources_Impl* SharedResources_Impl::s_pInstance( nullptr );
+ oslInterlockedCount SharedResources_Impl::s_nClients( 0 );
+
+ SharedResources_Impl::SharedResources_Impl()
+ : m_aLocale(Translate::Create("cnr"))
+ {
+ }
+
+ OUString SharedResources_Impl::getResourceString(TranslateId pId) const
+ {
+ return Translate::get(pId, m_aLocale);
+ }
+
+ void SharedResources_Impl::registerClient()
+ {
+ osl_atomic_increment( &s_nClients );
+ }
+
+ void SharedResources_Impl::revokeClient()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ if ( 0 == osl_atomic_decrement( &s_nClients ) )
+ {
+ delete s_pInstance;
+ s_pInstance = nullptr;
+ }
+ }
+
+
+ SharedResources_Impl& SharedResources_Impl::getInstance()
+ {
+ ::osl::MutexGuard aGuard( getMutex() );
+ OSL_ENSURE( s_nClients > 0, "SharedResources_Impl::getInstance: no active clients!" );
+
+ if ( !s_pInstance )
+ s_pInstance = new SharedResources_Impl;
+
+ return *s_pInstance;
+ }
+
+ namespace
+ {
+ size_t lcl_substitute( OUString& _inout_rString,
+ const char* _pAsciiPattern, std::u16string_view _rReplace )
+ {
+ size_t nOccurrences = 0;
+
+ OUString sPattern( OUString::createFromAscii( _pAsciiPattern ) );
+ sal_Int32 nIndex = 0;
+ while ( ( nIndex = _inout_rString.indexOf( sPattern ) ) > -1 )
+ {
+ ++nOccurrences;
+ _inout_rString = _inout_rString.replaceAt( nIndex, sPattern.getLength(), _rReplace );
+ }
+
+ return nOccurrences;
+ }
+ }
+
+ SharedResources::SharedResources()
+ {
+ SharedResources_Impl::registerClient();
+ }
+
+
+ SharedResources::~SharedResources()
+ {
+ SharedResources_Impl::revokeClient();
+ }
+
+
+ OUString SharedResources::getResourceString(TranslateId pResId) const
+ {
+ return SharedResources_Impl::getInstance().getResourceString(pResId);
+ }
+
+
+ OUString SharedResources::getResourceStringWithSubstitution(TranslateId pResId,
+ const char* _pAsciiPatternToReplace, const OUString& _rStringToSubstitute ) const
+ {
+ OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) );
+ if ( !lcl_substitute( sString, _pAsciiPatternToReplace, _rStringToSubstitute ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace << " with " << _rStringToSubstitute);
+ return sString;
+ }
+
+
+ OUString SharedResources::getResourceStringWithSubstitution(TranslateId pResId,
+ const char* _pAsciiPatternToReplace1, const OUString& _rStringToSubstitute1,
+ const char* _pAsciiPatternToReplace2, const OUString& _rStringToSubstitute2 ) const
+ {
+ OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) );
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace1, _rStringToSubstitute1 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace1 << " with " << _rStringToSubstitute1);
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace2, _rStringToSubstitute2 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace2 << " with " << _rStringToSubstitute2);
+ return sString;
+ }
+
+
+ OUString SharedResources::getResourceStringWithSubstitution(TranslateId pResId,
+ const char* _pAsciiPatternToReplace1, const OUString& _rStringToSubstitute1,
+ const char* _pAsciiPatternToReplace2, const OUString& _rStringToSubstitute2,
+ const char* _pAsciiPatternToReplace3, const OUString& _rStringToSubstitute3 ) const
+ {
+ OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) );
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace1, _rStringToSubstitute1 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace1 << " with " << _rStringToSubstitute1);
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace2, _rStringToSubstitute2 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace2 << " with " << _rStringToSubstitute2);
+ if( !lcl_substitute( sString, _pAsciiPatternToReplace3, _rStringToSubstitute3 ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace3 << " with " << _rStringToSubstitute3);
+ return sString;
+ }
+
+ OUString SharedResources::getResourceStringWithSubstitution(TranslateId pResId,
+ const std::vector< std::pair<const char* , OUString > >& _rStringToSubstitutes) const
+ {
+ OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) );
+ for(const auto& [rPattern, rReplace] : _rStringToSubstitutes)
+ if( !lcl_substitute( sString, rPattern, rReplace ) )
+ SAL_WARN("connectivity.resource", "Unable to substitute " << rPattern << " with " << rReplace);
+
+ return sString;
+ }
+
+
+} // namespace connectivity
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VCatalog.cxx b/connectivity/source/sdbcx/VCatalog.cxx
new file mode 100644
index 000000000..b30519fca
--- /dev/null
+++ b/connectivity/source/sdbcx/VCatalog.cxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/types.hxx>
+#include <sdbcx/VCatalog.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <TConnection.hxx>
+#include <connectivity/dbtools.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+IMPLEMENT_SERVICE_INFO(OCatalog,"com.sun.star.comp.connectivity.OCatalog","com.sun.star.sdbcx.DatabaseDefinition")
+
+OCatalog::OCatalog(const Reference< XConnection> &_xConnection) : OCatalog_BASE(m_aMutex)
+{
+ try
+ {
+ m_xMetaData = _xConnection->getMetaData();
+ }
+ catch(const Exception&)
+ {
+ OSL_FAIL("No Metadata available!");
+ }
+}
+
+OCatalog::~OCatalog()
+{
+}
+
+void SAL_CALL OCatalog::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_pTables)
+ m_pTables->disposing();
+ if(m_pViews)
+ m_pViews->disposing();
+ if(m_pGroups)
+ m_pGroups->disposing();
+ if(m_pUsers)
+ m_pUsers->disposing();
+
+ OCatalog_BASE::disposing();
+}
+
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL OCatalog::getTables( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OCatalog_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if(!m_pTables)
+ refreshTables();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pTables.get();
+}
+
+// XViewsSupplier
+Reference< XNameAccess > SAL_CALL OCatalog::getViews( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OCatalog_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if(!m_pViews)
+ refreshViews();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pViews.get();
+}
+
+// XUsersSupplier
+Reference< XNameAccess > SAL_CALL OCatalog::getUsers( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OCatalog_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if(!m_pUsers)
+ refreshUsers();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pUsers.get();
+}
+
+// XGroupsSupplier
+Reference< XNameAccess > SAL_CALL OCatalog::getGroups( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OCatalog_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if(!m_pGroups)
+ refreshGroups();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pGroups.get();
+}
+
+OUString OCatalog::buildName(const Reference< XRow >& _xRow)
+{
+ OUString sCatalog = _xRow->getString(1);
+ if ( _xRow->wasNull() )
+ sCatalog.clear();
+ OUString sSchema = _xRow->getString(2);
+ if ( _xRow->wasNull() )
+ sSchema.clear();
+ OUString sTable = _xRow->getString(3);
+ if ( _xRow->wasNull() )
+ sTable.clear();
+
+ OUString sComposedName(
+ ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation ) );
+ return sComposedName;
+}
+
+void OCatalog::fillNames(Reference< XResultSet >& _xResult,::std::vector< OUString>& _rNames)
+{
+ if ( _xResult.is() )
+ {
+ _rNames.reserve(20);
+ Reference< XRow > xRow(_xResult,UNO_QUERY);
+ while ( _xResult->next() )
+ {
+ _rNames.push_back( buildName(xRow) );
+ }
+ xRow.clear();
+ ::comphelper::disposeComponent(_xResult);
+ }
+}
+
+void ODescriptor::construct()
+{
+ sal_Int32 nAttrib = isNew() ? 0 : css::beans::PropertyAttribute::READONLY;
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME), PROPERTY_ID_NAME ,nAttrib,&m_Name,::cppu::UnoType<OUString>::get());
+}
+
+ODescriptor::~ODescriptor()
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VCollection.cxx b/connectivity/source/sdbcx/VCollection.cxx
new file mode 100644
index 000000000..804c8c361
--- /dev/null
+++ b/connectivity/source/sdbcx/VCollection.cxx
@@ -0,0 +1,582 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <algorithm>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/unreachable.hxx>
+#include <TConnection.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+
+namespace
+{
+ template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection
+ {
+ typedef std::multimap< OUString, T , ::comphelper::UStringMixLess> ObjectMap;
+ typedef typename ObjectMap::iterator ObjectIter;
+ typedef typename ObjectMap::value_type ObjectEntry;
+
+ // private:
+ // this combination of map and vector is used to have a fast name and index access
+ std::vector< ObjectIter > m_aElements; // hold the iterators which point to map
+ ObjectMap m_aNameMap; // hold the elements and a name
+ public:
+ OHardRefMap(bool _bCase)
+ : m_aNameMap(_bCase)
+ {
+ }
+
+ virtual bool exists(const OUString& _sName ) override
+ {
+ return m_aNameMap.find(_sName) != m_aNameMap.end();
+ }
+
+ virtual bool empty() override
+ {
+ return m_aNameMap.empty();
+ }
+
+ virtual void swapAll() override
+ {
+ std::vector< ObjectIter >(m_aElements).swap(m_aElements);
+ ObjectMap(m_aNameMap).swap(m_aNameMap);
+ }
+
+ virtual void swap() override
+ {
+ std::vector< ObjectIter >().swap(m_aElements);
+
+ OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" );
+ ObjectMap( m_aNameMap ).swap( m_aNameMap );
+ // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
+ // swapping. This way, it's ensured that the compare object held by these maps is preserved
+ // during the swap. If we would not do this, the UStringMixLess instance which is used would be
+ // default constructed (instead of being constructed from the same instance in m_aNameMap), and
+ // it's case-sensitive flag would have an unpredictable value.
+ }
+
+ virtual void clear() override
+ {
+ m_aElements.clear();
+ m_aNameMap.clear();
+ }
+
+ virtual void insert(const OUString& _sName,const ObjectType& _xObject) override
+ {
+ m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject)));
+ }
+
+ virtual void reFill(const ::std::vector< OUString> &_rVector) override
+ {
+ OSL_ENSURE(m_aNameMap.empty(),"OCollection::reFill: collection isn't empty");
+ m_aElements.reserve(_rVector.size());
+
+ for (auto const& elem : _rVector)
+ m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(elem,ObjectType())));
+ }
+
+ virtual bool rename(const OUString& _sOldName, const OUString& _sNewName) override
+ {
+ bool bRet = false;
+ ObjectIter aIter = m_aNameMap.find(_sOldName);
+ if ( aIter != m_aNameMap.end() )
+ {
+ typename std::vector< ObjectIter >::iterator aFind = std::find(m_aElements.begin(),m_aElements.end(),aIter);
+ if(m_aElements.end() != aFind)
+ {
+ (*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second));
+ m_aNameMap.erase(aIter);
+
+ bRet = true;
+ }
+ }
+ return bRet;
+ }
+
+ virtual sal_Int32 size() override
+ {
+ return static_cast<sal_Int32>(m_aNameMap.size());
+ }
+
+ virtual Sequence< OUString > getElementNames() override
+ {
+ Sequence< OUString > aNameList(m_aElements.size());
+
+ OUString* pStringArray = aNameList.getArray();
+ for(const auto& rIter : m_aElements)
+ {
+ *pStringArray = rIter->first;
+ ++pStringArray;
+ }
+
+ return aNameList;
+ }
+
+ virtual OUString getName(sal_Int32 _nIndex) override
+ {
+ return m_aElements[_nIndex]->first;
+ }
+
+ virtual void disposeAndErase(sal_Int32 _nIndex) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY);
+ ::comphelper::disposeComponent(xComp);
+ m_aElements[_nIndex]->second = T();
+
+ OUString sName = m_aElements[_nIndex]->first;
+ m_aElements.erase(m_aElements.begin()+_nIndex);
+ m_aNameMap.erase(sName);
+ }
+
+ virtual void disposeElements() override
+ {
+ for (auto & name : m_aNameMap)
+ {
+ Reference<XComponent> xComp(name.second.get(),UNO_QUERY);
+ if ( xComp.is() )
+ {
+ ::comphelper::disposeComponent(xComp);
+ name.second = T();
+ }
+ }
+ m_aElements.clear();
+ m_aNameMap.clear();
+ }
+
+ virtual sal_Int32 findColumn( const OUString& columnName ) override
+ {
+ ObjectIter aIter = m_aNameMap.find(columnName);
+ OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!");
+ return m_aElements.size() - (m_aElements.end() - std::find(m_aElements.begin(),m_aElements.end(),aIter));
+ }
+
+ virtual ObjectType getObject(sal_Int32 _nIndex) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ return m_aElements[_nIndex]->second;
+ }
+
+ virtual ObjectType getObject(const OUString& columnName) override
+ {
+ return m_aNameMap.find(columnName)->second;
+ }
+
+ virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ m_aElements[_nIndex]->second = _xObject;
+ }
+
+ bool isCaseSensitive() const override
+ {
+ return m_aNameMap.key_comp().isCaseSensitive();
+ }
+
+ };
+}
+
+IObjectCollection::~IObjectCollection() {}
+
+IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
+
+OCollection::OCollection(::cppu::OWeakObject& _rParent
+ , bool _bCase
+ , ::osl::Mutex& _rMutex
+ , const ::std::vector< OUString> &_rVector
+ , bool _bUseIndexOnly
+ , bool _bUseHardRef)
+ :m_aContainerListeners(_rMutex)
+ ,m_aRefreshListeners(_rMutex)
+ ,m_rParent(_rParent)
+ ,m_rMutex(_rMutex)
+ ,m_bUseIndexOnly(_bUseIndexOnly)
+{
+ if ( _bUseHardRef )
+ {
+ m_pElements.reset(new OHardRefMap< ObjectType >(_bCase));
+ }
+ else
+ {
+ m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase));
+ }
+ m_pElements->reFill(_rVector);
+}
+
+OCollection::~OCollection()
+{
+}
+
+Any SAL_CALL OCollection::queryInterface( const Type & rType )
+{
+ if ( m_bUseIndexOnly && rType == cppu::UnoType<XNameAccess>::get() )
+ {
+ return Any();
+ }
+ return OCollectionBase::queryInterface( rType );
+}
+
+Sequence< Type > SAL_CALL OCollection::getTypes()
+{
+ if ( m_bUseIndexOnly )
+ {
+ Sequence< Type > aTypes(OCollectionBase::getTypes());
+ Type* pBegin = aTypes.getArray();
+ Type* pEnd = pBegin + aTypes.getLength();
+
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ Type aType = cppu::UnoType<XNameAccess>::get();
+ for(;pBegin != pEnd; ++pBegin)
+ {
+ if ( *pBegin != aType )
+ aOwnTypes.push_back(*pBegin);
+ }
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+ }
+ return OCollectionBase::getTypes( );
+}
+
+void OCollection::clear_NoDispose()
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ m_pElements->clear();
+ m_pElements->swapAll();
+}
+
+
+void OCollection::disposing()
+{
+ m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
+ m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
+
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ disposeElements();
+
+ m_pElements->swap();
+}
+
+Any SAL_CALL OCollection::getByIndex( sal_Int32 Index )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ if (Index < 0 || Index >= m_pElements->size() )
+ throw IndexOutOfBoundsException(OUString::number(Index),static_cast<XTypeProvider*>(this));
+
+ return Any(getObject(Index));
+}
+
+Any SAL_CALL OCollection::getByName( const OUString& aName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ if ( !m_pElements->exists(aName) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_NO_ELEMENT_NAME,
+ "$name$", aName
+ ) );
+ throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) );
+ }
+
+ return Any(getObject(m_pElements->findColumn(aName)));
+}
+
+Sequence< OUString > SAL_CALL OCollection::getElementNames( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->getElementNames();
+}
+
+void SAL_CALL OCollection::refresh( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ disposeElements();
+
+ impl_refresh();
+ EventObject aEvt(static_cast<XTypeProvider*>(this));
+ m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
+}
+
+void OCollection::reFill(const ::std::vector< OUString> &_rVector)
+{
+ m_pElements->reFill(_rVector);
+}
+
+// XDataDescriptorFactory
+Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ return createDescriptor();
+}
+
+OUString OCollection::getNameForObject(const ObjectType& _xObject)
+{
+ OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!");
+ OUString sName;
+ _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName;
+ return sName;
+}
+
+// XAppend
+void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor )
+{
+ ::osl::ClearableMutexGuard aGuard(m_rMutex);
+
+ OUString sName = getNameForObject( descriptor );
+
+ if ( m_pElements->exists(sName) )
+ throw ElementExistException(sName,static_cast<XTypeProvider*>(this));
+
+ ObjectType xNewlyCreated = appendObject( sName, descriptor );
+ if ( !xNewlyCreated.is() )
+ throw RuntimeException();
+
+ ODescriptor* pDescriptor = comphelper::getFromUnoTunnel<ODescriptor>( xNewlyCreated );
+ if ( pDescriptor )
+ pDescriptor->setNew( false );
+
+ sName = getNameForObject( xNewlyCreated );
+ if ( !m_pElements->exists( sName ) ) // this may happen when the derived class included it itself
+ m_pElements->insert( sName, xNewlyCreated );
+
+ // notify our container listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(sName), Any(xNewlyCreated), Any());
+ aGuard.clear();
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+}
+
+// XDrop
+void SAL_CALL OCollection::dropByName( const OUString& elementName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ if ( !m_pElements->exists(elementName) )
+ throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this));
+
+ dropImpl(m_pElements->findColumn(elementName));
+}
+
+void SAL_CALL OCollection::dropByIndex( sal_Int32 index )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ if(index <0 || index >= getCount())
+ throw IndexOutOfBoundsException(OUString::number(index),static_cast<XTypeProvider*>(this));
+
+ dropImpl(index);
+}
+
+void OCollection::dropImpl(sal_Int32 _nIndex, bool _bReallyDrop)
+{
+ OUString elementName = m_pElements->getName(_nIndex);
+
+ if ( _bReallyDrop )
+ dropObject(_nIndex,elementName);
+
+ m_pElements->disposeAndErase(_nIndex);
+
+ // notify our container listeners
+ notifyElementRemoved(elementName);
+}
+
+void OCollection::notifyElementRemoved(const OUString& _sName)
+{
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_sName), Any(), Any());
+ // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementRemoved(aEvent);
+}
+
+sal_Int32 SAL_CALL OCollection::findColumn( const OUString& columnName )
+{
+ if ( !m_pElements->exists(columnName) )
+ {
+ ::dbtools::throwInvalidColumnException( columnName, static_cast< XIndexAccess*>(this) );
+ O3TL_UNREACHABLE;
+ }
+
+ return m_pElements->findColumn(columnName) + 1; // because columns start at one
+}
+
+Reference< XEnumeration > SAL_CALL OCollection::createEnumeration( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return new OEnumerationByIndex( static_cast< XIndexAccess*>(this));
+}
+
+void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+
+void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+void SAL_CALL OCollection::acquire() noexcept
+{
+ m_rParent.acquire();
+}
+
+void SAL_CALL OCollection::release() noexcept
+{
+ m_rParent.release();
+}
+
+Type SAL_CALL OCollection::getElementType( )
+{
+ return cppu::UnoType<XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL OCollection::hasElements( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return !m_pElements->empty();
+}
+
+sal_Int32 SAL_CALL OCollection::getCount( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->size();
+}
+
+sal_Bool SAL_CALL OCollection::hasByName( const OUString& aName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->exists(aName);
+}
+
+void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l )
+{
+ m_aRefreshListeners.addInterface(l);
+}
+
+void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l )
+{
+ m_aRefreshListeners.removeInterface(l);
+}
+
+void OCollection::insertElement(const OUString& _sElementName,const ObjectType& _xElement)
+{
+ OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists");
+ if ( !m_pElements->exists(_sElementName) )
+ m_pElements->insert(_sElementName,_xElement);
+}
+
+void OCollection::renameObject(const OUString& _sOldName, const OUString& _sNewName)
+{
+ OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist");
+ OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists");
+ OSL_ENSURE(!_sNewName.isEmpty(),"New name must not be empty!");
+ OSL_ENSURE(!_sOldName.isEmpty(),"Old name must not be empty!");
+
+ if ( m_pElements->rename(_sOldName,_sNewName) )
+ {
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_sNewName), Any(m_pElements->getObject(_sNewName)),Any(_sOldName));
+ // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementReplaced(aEvent);
+ }
+}
+
+ObjectType OCollection::getObject(sal_Int32 _nIndex)
+{
+ ObjectType xName = m_pElements->getObject(_nIndex);
+ if ( !xName.is() )
+ {
+ try
+ {
+ xName = createObject(m_pElements->getName(_nIndex));
+ }
+ catch(const SQLException& e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ try
+ {
+ dropImpl(_nIndex,false);
+ }
+ catch(const Exception& )
+ {
+ }
+ throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),anyEx);
+ }
+ m_pElements->setObject(_nIndex,xName);
+ }
+ return xName;
+}
+
+void OCollection::disposeElements()
+{
+ m_pElements->disposeElements();
+}
+
+Reference< XPropertySet > OCollection::createDescriptor()
+{
+ OSL_FAIL("createDescriptor() needs to be overridden when used!");
+ throw SQLException();
+}
+
+ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor )
+{
+ ObjectType xNewDescriptor( createDescriptor() );
+ ::comphelper::copyProperties( _descriptor, xNewDescriptor );
+ return xNewDescriptor;
+}
+
+ObjectType OCollection::appendObject( const OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
+{
+ return cloneDescriptor( descriptor );
+}
+
+void OCollection::dropObject(sal_Int32 /*_nPos*/, const OUString& /*_sElementName*/)
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VColumn.cxx b/connectivity/source/sdbcx/VColumn.cxx
new file mode 100644
index 000000000..398d64b49
--- /dev/null
+++ b/connectivity/source/sdbcx/VColumn.cxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <TConnection.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace cppu;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+
+
+OUString SAL_CALL OColumn::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VColumnDescriptor";
+ return "com.sun.star.sdbcx.VColumn";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OColumn::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.ColumnDescriptor"):OUString("com.sun.star.sdbcx.Column") };
+}
+
+sal_Bool SAL_CALL OColumn::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OColumn::OColumn(bool _bCase)
+ :OColumnDescriptor_BASE(m_aMutex)
+ ,ODescriptor(OColumnDescriptor_BASE::rBHelper,_bCase,true)
+ ,m_IsNullable(ColumnValue::NULLABLE)
+ ,m_Precision(0)
+ ,m_Scale(0)
+ ,m_Type(0)
+ ,m_IsAutoIncrement(false)
+ ,m_IsRowVersion(false)
+ ,m_IsCurrency(false)
+{
+ construct();
+}
+
+OColumn::OColumn( const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ const OUString& Description,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool IsAutoIncrement,
+ bool IsRowVersion,
+ bool IsCurrency,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName)
+ :OColumnDescriptor_BASE(m_aMutex)
+ ,ODescriptor(OColumnDescriptor_BASE::rBHelper,_bCase)
+ ,m_TypeName(TypeName)
+ ,m_Description(Description)
+ ,m_DefaultValue(DefaultValue)
+ ,m_IsNullable(IsNullable)
+ ,m_Precision(Precision)
+ ,m_Scale(Scale)
+ ,m_Type(Type)
+ ,m_IsAutoIncrement(IsAutoIncrement)
+ ,m_IsRowVersion(IsRowVersion)
+ ,m_IsCurrency(IsCurrency)
+ ,m_CatalogName(CatalogName)
+ ,m_SchemaName(SchemaName)
+ ,m_TableName(TableName)
+{
+ m_Name = Name;
+
+ construct();
+}
+
+OColumn::~OColumn()
+{
+}
+
+::cppu::IPropertyArrayHelper* OColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OColumn::getInfoHelper()
+{
+ return *OColumn_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+void SAL_CALL OColumn::acquire() noexcept
+{
+ OColumnDescriptor_BASE::acquire();
+}
+
+void SAL_CALL OColumn::release() noexcept
+{
+ OColumnDescriptor_BASE::release();
+}
+
+Any SAL_CALL OColumn::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ if(!aRet.hasValue())
+ {
+ if(!isNew())
+ aRet = OColumn_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OColumnDescriptor_BASE::queryInterface( rType);
+ }
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OColumn::getTypes( )
+{
+ if(isNew())
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OColumnDescriptor_BASE::getTypes());
+
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OColumn_BASE::getTypes(),OColumnDescriptor_BASE::getTypes());
+}
+
+void OColumn::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME), PROPERTY_ID_TYPENAME, nAttrib, &m_TypeName, cppu::UnoType<decltype(m_TypeName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION), PROPERTY_ID_DESCRIPTION, nAttrib, &m_Description, cppu::UnoType<decltype(m_Description)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), PROPERTY_ID_DEFAULTVALUE, nAttrib, &m_DefaultValue, cppu::UnoType<decltype(m_DefaultValue)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION), PROPERTY_ID_PRECISION, nAttrib, &m_Precision, cppu::UnoType<decltype(m_Precision)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib, &m_Type, cppu::UnoType<decltype(m_Type)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE), PROPERTY_ID_SCALE, nAttrib, &m_Scale, cppu::UnoType<decltype(m_Scale)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE), PROPERTY_ID_ISNULLABLE, nAttrib, &m_IsNullable, cppu::UnoType<decltype(m_IsNullable)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT), PROPERTY_ID_ISAUTOINCREMENT, nAttrib, &m_IsAutoIncrement, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISROWVERSION), PROPERTY_ID_ISROWVERSION, nAttrib, &m_IsRowVersion, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY), PROPERTY_ID_ISCURRENCY, nAttrib, &m_IsCurrency, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME, nAttrib, &m_CatalogName, cppu::UnoType<decltype(m_CatalogName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib, &m_SchemaName, cppu::UnoType<decltype(m_SchemaName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME), PROPERTY_ID_TABLENAME, nAttrib, &m_TableName, cppu::UnoType<decltype(m_TableName)>::get());
+}
+
+void OColumn::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OColumnDescriptor_BASE::rBHelper.bDisposed);
+
+}
+
+Reference< XPropertySet > SAL_CALL OColumn::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OColumnDescriptor_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OColumn> pNewColumn = new OColumn( m_Name,
+ m_TypeName,
+ m_DefaultValue,
+ m_Description,
+ m_IsNullable,
+ m_Precision,
+ m_Scale,
+ m_Type,
+ m_IsAutoIncrement,
+ m_IsRowVersion,
+ m_IsCurrency,
+ isCaseSensitive(),
+ m_CatalogName,
+ m_SchemaName,
+ m_TableName);
+ pNewColumn->setNew(true);
+ return pNewColumn;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OColumn::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+// XNamed
+OUString SAL_CALL OColumn::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OColumn::setName( const OUString& aName )
+{
+ m_Name = aName;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VDescriptor.cxx b/connectivity/source/sdbcx/VDescriptor.cxx
new file mode 100644
index 000000000..ce3b437d9
--- /dev/null
+++ b/connectivity/source/sdbcx/VDescriptor.cxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include <algorithm>
+
+namespace connectivity::sdbcx
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+
+
+ // = ODescriptor
+
+
+ ODescriptor::ODescriptor(::cppu::OBroadcastHelper& _rBHelper, bool _bCase, bool _bNew)
+ :ODescriptor_PBASE(_rBHelper)
+ ,m_aCase(_bCase)
+ ,m_bNew(_bNew)
+ {
+ }
+
+
+ // css::lang::XUnoTunnel
+ sal_Int64 SAL_CALL ODescriptor::getSomething( const Sequence< sal_Int8 >& rId )
+ {
+ return comphelper::getSomethingImpl(rId, this);
+ }
+
+
+ namespace
+ {
+ struct ResetROAttribute
+ {
+ void operator ()( Property& _rProperty ) const
+ {
+ _rProperty.Attributes &= ~PropertyAttribute::READONLY;
+ }
+ };
+ struct SetROAttribute
+ {
+ void operator ()( Property& _rProperty ) const
+ {
+ _rProperty.Attributes |= PropertyAttribute::READONLY;
+ }
+ };
+ }
+
+
+ ::cppu::IPropertyArrayHelper* ODescriptor::doCreateArrayHelper() const
+ {
+ Sequence< Property > aProperties;
+ describeProperties( aProperties );
+
+ auto [begin, end] = asNonConstRange(aProperties);
+ if ( isNew() )
+ std::for_each( begin, end, ResetROAttribute() );
+ else
+ std::for_each( begin, end, SetROAttribute() );
+
+ return new ::cppu::OPropertyArrayHelper( aProperties );
+ }
+
+
+ bool ODescriptor::isNew( const Reference< XInterface >& _rxDescriptor )
+ {
+ ODescriptor* pImplementation = comphelper::getFromUnoTunnel<ODescriptor>( _rxDescriptor );
+ return pImplementation && pImplementation->isNew();
+ }
+
+
+ const Sequence< sal_Int8 > & ODescriptor::getUnoTunnelId()
+ {
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+ }
+
+
+ Any SAL_CALL ODescriptor::queryInterface( const Type & rType )
+ {
+ Any aRet = ::cppu::queryInterface(rType,static_cast< XUnoTunnel*> (this));
+ return aRet.hasValue() ? aRet : ODescriptor_PBASE::queryInterface(rType);
+ }
+
+
+ void ODescriptor::setNew(bool _bNew)
+ {
+ m_bNew = _bNew;
+ }
+
+
+ Sequence< Type > SAL_CALL ODescriptor::getTypes( )
+ {
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XUnoTunnel>::get());
+ return aTypes.getTypes();
+ }
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VGroup.cxx b/connectivity/source/sdbcx/VGroup.cxx
new file mode 100644
index 000000000..73f6aa79c
--- /dev/null
+++ b/connectivity/source/sdbcx/VGroup.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdbcx/VGroup.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbexception.hxx>
+
+
+using namespace ::connectivity::sdbcx;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+
+IMPLEMENT_SERVICE_INFO(OGroup,"com.sun.star.sdbcx.VGroup","com.sun.star.sdbcx.Group");
+
+OGroup::OGroup(bool _bCase) : OGroup_BASE(m_aMutex)
+ , ODescriptor(OGroup_BASE::rBHelper,_bCase)
+{
+}
+
+OGroup::OGroup(const OUString& Name, bool _bCase) : OGroup_BASE(m_aMutex)
+ ,ODescriptor(OGroup_BASE::rBHelper,_bCase)
+{
+ m_Name = Name;
+}
+
+OGroup::~OGroup()
+{
+}
+
+Any SAL_CALL OGroup::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ return aRet.hasValue() ? aRet : OGroup_BASE::queryInterface( rType);
+}
+
+Sequence< Type > SAL_CALL OGroup::getTypes( )
+{
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OGroup_BASE::getTypes());
+}
+
+void OGroup::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_pUsers)
+ m_pUsers->disposing();
+}
+
+::cppu::IPropertyArrayHelper* OGroup::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+::cppu::IPropertyArrayHelper & OGroup::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+Reference< XNameAccess > SAL_CALL OGroup::getUsers( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_pUsers )
+ refreshUsers();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pUsers.get();
+}
+
+
+sal_Int32 SAL_CALL OGroup::getPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+
+ return 0;
+}
+
+sal_Int32 SAL_CALL OGroup::getGrantablePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+
+ return 0;
+}
+
+void SAL_CALL OGroup::grantPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+ throwFeatureNotImplementedSQLException( "XAuthorizable::grantPrivileges", *this );
+}
+
+void SAL_CALL OGroup::revokePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OGroup_BASE::rBHelper.bDisposed);
+ throwFeatureNotImplementedSQLException( "XAuthorizable::revokePrivileges", *this );
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OGroup::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OGroup::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OGroup::setName( const OUString& /*aName*/ )
+{
+ throwFeatureNotImplementedRuntimeException( "XNamed::setName", *this );
+}
+
+// XInterface
+void SAL_CALL OGroup::acquire() noexcept
+{
+ OGroup_BASE::acquire();
+}
+
+void SAL_CALL OGroup::release() noexcept
+{
+ OGroup_BASE::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VIndex.cxx b/connectivity/source/sdbcx/VIndex.cxx
new file mode 100644
index 000000000..e04cf2527
--- /dev/null
+++ b/connectivity/source/sdbcx/VIndex.cxx
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcx/VIndex.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <TConnection.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::connectivity::sdbcx;
+using namespace ::cppu;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OUString SAL_CALL OIndex::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VIndexDescriptor";
+ return "com.sun.star.sdbcx.VIndex";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OIndex::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.IndexDescriptor"):OUString("com.sun.star.sdbcx.Index") };
+}
+
+sal_Bool SAL_CALL OIndex::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OIndex::OIndex(bool _bCase) : ODescriptor_BASE(m_aMutex)
+ , ODescriptor(ODescriptor_BASE::rBHelper,_bCase,true)
+ ,m_IsUnique(false)
+ ,m_IsPrimaryKeyIndex(false)
+ ,m_IsClustered(false)
+{
+}
+
+OIndex::OIndex( const OUString& Name,
+ const OUString& Catalog,
+ bool _isUnique,
+ bool _isPrimaryKeyIndex,
+ bool _isClustered,
+ bool _bCase) : ODescriptor_BASE(m_aMutex)
+ ,ODescriptor(ODescriptor_BASE::rBHelper, _bCase)
+ ,m_Catalog(Catalog)
+ ,m_IsUnique(_isUnique)
+ ,m_IsPrimaryKeyIndex(_isPrimaryKeyIndex)
+ ,m_IsClustered(_isClustered)
+{
+ m_Name = Name;
+}
+
+OIndex::~OIndex( )
+{
+}
+
+::cppu::IPropertyArrayHelper* OIndex::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OIndex::getInfoHelper()
+{
+ return *OIndex_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+Any SAL_CALL OIndex::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ if(!aRet.hasValue())
+ {
+ if(!isNew())
+ aRet = OIndex_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = ODescriptor_BASE::queryInterface( rType);
+ }
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OIndex::getTypes( )
+{
+ if(isNew())
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes());
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes(),OIndex_BASE::getTypes());
+}
+
+void OIndex::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOG), PROPERTY_ID_CATALOG, nAttrib,&m_Catalog, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE), PROPERTY_ID_ISUNIQUE, nAttrib,&m_IsUnique, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISPRIMARYKEYINDEX),PROPERTY_ID_ISPRIMARYKEYINDEX, nAttrib,&m_IsPrimaryKeyIndex, cppu::UnoType<bool>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCLUSTERED), PROPERTY_ID_ISCLUSTERED, nAttrib,&m_IsClustered, cppu::UnoType<bool>::get());
+}
+
+void OIndex::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_pColumns)
+ m_pColumns->disposing();
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OIndex::getColumns( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODescriptor_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_pColumns )
+ refreshColumns();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OIndex::getColumns" );
+ }
+
+ return m_pColumns.get();
+}
+
+Reference< XPropertySet > SAL_CALL OIndex::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODescriptor_BASE::rBHelper.bDisposed);
+
+
+ return this;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OIndex::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OIndex::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OIndex::setName( const OUString& /*aName*/ )
+{
+}
+
+// XInterface
+void SAL_CALL OIndex::acquire() noexcept
+{
+ ODescriptor_BASE::acquire();
+}
+
+void SAL_CALL OIndex::release() noexcept
+{
+ ODescriptor_BASE::release();
+}
+
+void OIndex::refreshColumns()
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VIndexColumn.cxx b/connectivity/source/sdbcx/VIndexColumn.cxx
new file mode 100644
index 000000000..edd1ea93e
--- /dev/null
+++ b/connectivity/source/sdbcx/VIndexColumn.cxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcx/VIndexColumn.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+OUString SAL_CALL OIndexColumn::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VIndexColumnDescriptor";
+ return "com.sun.star.sdbcx.VIndexColumn";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OIndexColumn::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.IndexColumnDescriptor"):OUString("com.sun.star.sdbcx.IndexColumn") };
+}
+
+sal_Bool SAL_CALL OIndexColumn::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OIndexColumn::OIndexColumn(bool _bCase) : OColumn(_bCase), m_IsAscending(true)
+{
+ construct();
+}
+
+
+OIndexColumn::OIndexColumn( bool IsAscending,
+ const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName
+ ) : OColumn(Name,
+ TypeName,
+ DefaultValue,
+ OUString(),
+ IsNullable,
+ Precision,
+ Scale,
+ Type,
+ false/*IsAutoIncrement*/,
+ false/*IsRowVersion*/,
+ false/*IsCurrency*/,
+ _bCase,
+ CatalogName,
+ SchemaName,
+ TableName)
+ , m_IsAscending(IsAscending)
+{
+ construct();
+}
+
+::cppu::IPropertyArrayHelper* OIndexColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OIndexColumn::getInfoHelper()
+{
+ return *OIndexColumn_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+void OIndexColumn::construct()
+{
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING, nAttrib,&m_IsAscending, cppu::UnoType<bool>::get());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VKey.cxx b/connectivity/source/sdbcx/VKey.cxx
new file mode 100644
index 000000000..f267db161
--- /dev/null
+++ b/connectivity/source/sdbcx/VKey.cxx
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcx/VKey.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/KeyRule.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OUString SAL_CALL OKey::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VKeyDescriptor";
+ return "com.sun.star.sdbcx.VKey";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OKey::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.KeyDescriptor"):OUString("com.sun.star.sdbcx.Key") };
+}
+
+sal_Bool SAL_CALL OKey::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OKey::OKey(bool _bCase) : ODescriptor_BASE(m_aMutex)
+ , ODescriptor(ODescriptor_BASE::rBHelper, _bCase, true)
+ , m_aProps(std::make_shared<KeyProperties>())
+{
+}
+
+OKey::OKey(const OUString& Name,const std::shared_ptr<KeyProperties>& _rProps, bool _bCase)
+: ODescriptor_BASE(m_aMutex)
+ ,ODescriptor(ODescriptor_BASE::rBHelper, _bCase)
+ ,m_aProps(_rProps)
+{
+ m_Name = Name;
+}
+//OKey::OKey( const OUString& _Name,
+// const OUString& _ReferencedTable,
+// sal_Int32 _Type,
+// sal_Int32 _UpdateRule,
+// sal_Int32 _DeleteRule,
+// sal_Bool _bCase) : ODescriptor_BASE(m_aMutex)
+// ,ODescriptor(ODescriptor_BASE::rBHelper,_bCase)
+// ,m_ReferencedTable(_ReferencedTable)
+// ,m_Type(_Type)
+// ,m_UpdateRule(_UpdateRule)
+// ,m_DeleteRule(_DeleteRule)
+// ,m_pColumns(NULL)
+//{
+// m_Name = _Name;
+//}
+
+OKey::~OKey( )
+{
+}
+
+Any SAL_CALL OKey::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ if(!aRet.hasValue())
+ {
+ if(!isNew())
+ aRet = OKey_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = ODescriptor_BASE::queryInterface( rType);
+ }
+
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OKey::getTypes( )
+{
+ if(isNew())
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes());
+
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes(),OKey_BASE::getTypes());
+}
+
+void OKey::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REFERENCEDTABLE), PROPERTY_ID_REFERENCEDTABLE, nAttrib,&m_aProps->m_ReferencedTable, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib,&m_aProps->m_Type, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_UPDATERULE), PROPERTY_ID_UPDATERULE, nAttrib,&m_aProps->m_UpdateRule, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELETERULE), PROPERTY_ID_DELETERULE, nAttrib,&m_aProps->m_DeleteRule, ::cppu::UnoType<sal_Int32>::get());
+}
+
+void SAL_CALL OKey::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_pColumns)
+ m_pColumns->disposing();
+
+ ODescriptor_BASE::disposing();
+}
+
+::cppu::IPropertyArrayHelper* OKey::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & OKey::getInfoHelper()
+{
+ return *getArrayHelper(isNew() ? 1 : 0);
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OKey::getColumns( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODescriptor_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_pColumns )
+ refreshColumns();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pColumns.get();
+}
+
+Reference< XPropertySet > SAL_CALL OKey::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(ODescriptor_BASE::rBHelper.bDisposed);
+
+
+ return this;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OKey::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OKey::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OKey::setName( const OUString& /*aName*/ )
+{
+}
+
+// XInterface
+void SAL_CALL OKey::acquire() noexcept
+{
+ ODescriptor_BASE::acquire();
+}
+
+void SAL_CALL OKey::release() noexcept
+{
+ ODescriptor_BASE::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VKeyColumn.cxx b/connectivity/source/sdbcx/VKeyColumn.cxx
new file mode 100644
index 000000000..b6f69e65c
--- /dev/null
+++ b/connectivity/source/sdbcx/VKeyColumn.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdbcx/VKeyColumn.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <TConnection.hxx>
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace cppu;
+
+OUString SAL_CALL OKeyColumn::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VKeyColumnDescriptor";
+ return "com.sun.star.sdbcx.VKeyColumn";
+}
+
+css::uno::Sequence< OUString > SAL_CALL OKeyColumn::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.KeyColumnDescriptor"):OUString("com.sun.star.sdbcx.KeyColumn") };
+}
+
+sal_Bool SAL_CALL OKeyColumn::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OKeyColumn::OKeyColumn(bool _bCase) : OColumn(_bCase)
+{
+ construct();
+}
+
+OKeyColumn::OKeyColumn( const OUString& ReferencedColumn,
+ const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName
+ ) : OColumn(Name,
+ TypeName,
+ DefaultValue,
+ OUString(),
+ IsNullable,
+ Precision,
+ Scale,
+ Type,
+ false/*IsAutoIncrement*/,
+ false/*IsRowVersion*/,
+ false/*IsCurrency*/,
+ _bCase,
+ CatalogName,
+ SchemaName,
+ TableName)
+ , m_ReferencedColumn(ReferencedColumn)
+{
+ construct();
+}
+
+OKeyColumn::~OKeyColumn()
+{
+}
+
+::cppu::IPropertyArrayHelper* OKeyColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OKeyColumn::getInfoHelper()
+{
+ return *OKeyColumn_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+void OKeyColumn::construct()
+{
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RELATEDCOLUMN), PROPERTY_ID_RELATEDCOLUMN, nAttrib,&m_ReferencedColumn, ::cppu::UnoType<OUString>::get());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VTable.cxx b/connectivity/source/sdbcx/VTable.cxx
new file mode 100644
index 000000000..7a28bc5f4
--- /dev/null
+++ b/connectivity/source/sdbcx/VTable.cxx
@@ -0,0 +1,304 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <connectivity/sdbcx/VTable.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <TConnection.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::connectivity;
+using namespace ::connectivity::sdbcx;
+using namespace ::dbtools;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OUString SAL_CALL OTable::getImplementationName( )
+{
+ if(isNew())
+ return "com.sun.star.sdbcx.VTableDescriptor";
+ return "com.sun.star.sdbcx.Table";
+}
+
+
+css::uno::Sequence< OUString > SAL_CALL OTable::getSupportedServiceNames( )
+{
+ return { isNew()?OUString("com.sun.star.sdbcx.TableDescriptor"):OUString("com.sun.star.sdbcx.Table") };
+}
+
+sal_Bool SAL_CALL OTable::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+OTable::OTable(OCollection* _pTables,
+ bool _bCase)
+ : OTableDescriptor_BASE(m_aMutex)
+ ,ODescriptor(OTableDescriptor_BASE::rBHelper,_bCase,true)
+ ,m_pTables(_pTables)
+{
+}
+
+OTable::OTable( OCollection* _pTables,
+ bool _bCase,
+ const OUString& Name, const OUString& Type,
+ const OUString& Description,const OUString& SchemaName,
+ const OUString& CatalogName) : OTableDescriptor_BASE(m_aMutex)
+ ,ODescriptor(OTableDescriptor_BASE::rBHelper,_bCase)
+ ,m_CatalogName(CatalogName)
+ ,m_SchemaName(SchemaName)
+ ,m_Description(Description)
+ ,m_Type(Type)
+ ,m_pTables(_pTables)
+{
+ m_Name = Name;
+}
+
+OTable::~OTable()
+{
+}
+
+void OTable::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME,nAttrib,&m_CatalogName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib,&m_SchemaName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION), PROPERTY_ID_DESCRIPTION,nAttrib,&m_Description, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib,&m_Type, ::cppu::UnoType<OUString>::get());
+}
+
+void SAL_CALL OTable::acquire() noexcept
+{
+ OTableDescriptor_BASE::acquire();
+}
+
+void SAL_CALL OTable::release() noexcept
+{
+ OTableDescriptor_BASE::release();
+}
+
+
+Any SAL_CALL OTable::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ if(!aRet.hasValue())
+ {
+ if(!isNew())
+ aRet = OTable_BASE::queryInterface( rType);
+ if(isNew() && (rType == cppu::UnoType<XIndexesSupplier>::get()))
+ return Any();
+ if(!aRet.hasValue())
+ aRet = OTableDescriptor_BASE::queryInterface( rType);
+ }
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OTable::getTypes( )
+{
+ if(isNew())
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OTableDescriptor_BASE::getTypes());
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OTableDescriptor_BASE::getTypes(),OTable_BASE::getTypes());
+}
+
+void SAL_CALL OTable::disposing()
+{
+ ODescriptor::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_xKeys)
+ m_xKeys->disposing();
+ if(m_xColumns)
+ m_xColumns->disposing();
+ if(m_xIndexes)
+ m_xIndexes->disposing();
+
+ m_pTables = nullptr;
+}
+
+// XColumnsSupplier
+Reference< XNameAccess > SAL_CALL OTable::getColumns( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_xColumns )
+ refreshColumns();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_xColumns.get();
+}
+
+
+// XKeysSupplier
+Reference< XIndexAccess > SAL_CALL OTable::getKeys( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ Reference< XIndexAccess > xKeys;
+
+ try
+ {
+ if ( !m_xKeys )
+ refreshKeys();
+ xKeys = m_xKeys.get();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return xKeys;
+}
+
+cppu::IPropertyArrayHelper* OTable::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+cppu::IPropertyArrayHelper & OTable::getInfoHelper()
+{
+ return *getArrayHelper(isNew() ? 1 : 0);
+}
+
+Reference< XPropertySet > SAL_CALL OTable::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OTable> pTable = new OTable(m_pTables,isCaseSensitive(),m_Name,m_Type,m_Description,m_SchemaName,m_CatalogName);
+ pTable->setNew(true);
+ return pTable;
+}
+
+// XIndexesSupplier
+Reference< XNameAccess > SAL_CALL OTable::getIndexes( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_xIndexes )
+ refreshIndexes();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_xIndexes.get();
+}
+
+// XRename
+void SAL_CALL OTable::rename( const OUString& newName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ const OUString sOldComposedName = getName();
+ const Reference< XDatabaseMetaData> xMetaData = getMetaData();
+ if ( xMetaData.is() )
+ ::dbtools::qualifiedNameComponents(xMetaData,newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InDataManipulation);
+ else
+ m_Name = newName;
+
+ m_pTables->renameObject(sOldComposedName,newName);
+}
+
+Reference< XDatabaseMetaData> OTable::getMetaData() const
+{
+ return nullptr;
+}
+
+// XAlterTable
+void SAL_CALL OTable::alterColumnByName( const OUString& /*colName*/, const Reference< XPropertySet >& /*descriptor*/ )
+{
+ throwFeatureNotImplementedSQLException( "XAlterTable::alterColumnByName", *this );
+}
+
+void SAL_CALL OTable::alterColumnByIndex( sal_Int32 /*index*/, const Reference< XPropertySet >& /*descriptor*/ )
+{
+ throwFeatureNotImplementedSQLException( "XAlterTable::alterColumnByIndex", *this );
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OTable::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OTable::getName()
+{
+ // this is only correct for tables who haven't a schema or catalog name
+ OSL_ENSURE(m_CatalogName.isEmpty(),"getName(): forgot to override getName()!");
+ OSL_ENSURE(m_SchemaName.isEmpty(),"getName(): forgot to override getName()!");
+ return m_Name;
+}
+
+void SAL_CALL OTable::setName( const OUString& /*aName*/ )
+{
+}
+
+void OTable::refreshColumns()
+{
+}
+
+void OTable::refreshKeys()
+{
+}
+
+void OTable::refreshIndexes()
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VUser.cxx b/connectivity/source/sdbcx/VUser.cxx
new file mode 100644
index 000000000..a09d82183
--- /dev/null
+++ b/connectivity/source/sdbcx/VUser.cxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdbcx/VUser.hxx>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/sequence.hxx>
+
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+IMPLEMENT_SERVICE_INFO(OUser,"com.sun.star.sdbcx.VUser","com.sun.star.sdbcx.User");
+
+OUser::OUser(bool _bCase) : OUser_BASE(m_aMutex)
+ , ODescriptor(OUser_BASE::rBHelper,_bCase,true)
+{
+}
+
+OUser::OUser(const OUString& Name, bool _bCase) : OUser_BASE(m_aMutex)
+ ,ODescriptor(OUser_BASE::rBHelper,_bCase)
+{
+ m_Name = Name;
+}
+
+OUser::~OUser( )
+{
+}
+
+void OUser::disposing()
+{
+ OPropertySetHelper::disposing();
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if(m_pGroups)
+ m_pGroups->disposing();
+}
+
+Any SAL_CALL OUser::queryInterface( const Type & rType )
+{
+ Any aRet = ODescriptor::queryInterface( rType);
+ return aRet.hasValue() ? aRet : OUser_BASE::queryInterface( rType);
+}
+
+Sequence< Type > SAL_CALL OUser::getTypes( )
+{
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OUser_BASE::getTypes());
+}
+
+::cppu::IPropertyArrayHelper* OUser::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+
+}
+
+::cppu::IPropertyArrayHelper & OUser::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+// XUser
+void SAL_CALL OUser::changePassword( const OUString& /*objPassword*/, const OUString& /*newPassword*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XUser::changePassword", *this );
+}
+
+// XGroupsSupplier
+Reference< XNameAccess > SAL_CALL OUser::getGroups( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+
+ try
+ {
+ if ( !m_pGroups )
+ refreshGroups();
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave this method
+ throw;
+ }
+ catch( const Exception& )
+ {
+ // allowed
+ }
+
+ return m_pGroups.get();
+}
+
+
+SAL_WNOUNREACHABLE_CODE_PUSH
+
+sal_Int32 SAL_CALL OUser::getPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::changePassword", *this );
+ return 0;
+}
+
+sal_Int32 SAL_CALL OUser::getGrantablePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::getGrantablePrivileges", *this );
+ return 0;
+}
+
+SAL_WNOUNREACHABLE_CODE_POP
+
+
+void SAL_CALL OUser::grantPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::grantPrivileges", *this );
+}
+
+void SAL_CALL OUser::revokePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(OUser_BASE::rBHelper.bDisposed);
+ ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::revokePrivileges", *this );
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OUser::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+OUString SAL_CALL OUser::getName( )
+{
+ return m_Name;
+}
+
+void SAL_CALL OUser::setName( const OUString& /*aName*/ )
+{
+ OSL_FAIL( "OUser::setName: not implemented!" );
+ // not allowed to throw an SQLException here ...
+}
+
+// XInterface
+void SAL_CALL OUser::acquire() noexcept
+{
+ OUser_BASE::acquire();
+}
+
+void SAL_CALL OUser::release() noexcept
+{
+ OUser_BASE::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/sdbcx/VView.cxx b/connectivity/source/sdbcx/VView.cxx
new file mode 100644
index 000000000..b36817a40
--- /dev/null
+++ b/connectivity/source/sdbcx/VView.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 <connectivity/sdbcx/VView.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbtools.hxx>
+#include <TConnection.hxx>
+
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+IMPLEMENT_SERVICE_INFO(OView,"com.sun.star.sdbcx.VView","com.sun.star.sdbcx.View");
+
+OView::OView(bool _bCase,
+ const OUString& Name,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _xMetaData,
+ const OUString& Command,
+ const OUString& SchemaName,
+ const OUString& CatalogName) : ODescriptor(::comphelper::OMutexAndBroadcastHelper::m_aBHelper,_bCase)
+ ,m_CatalogName(CatalogName)
+ ,m_SchemaName(SchemaName)
+ ,m_Command(Command)
+ ,m_CheckOption(0)
+ ,m_xMetaData(_xMetaData)
+
+{
+ m_Name = Name;
+ construct();
+}
+
+OView::OView(bool _bCase, const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _xMetaData)
+ : ODescriptor(::comphelper::OMutexAndBroadcastHelper::m_aBHelper, _bCase, true)
+ ,m_xMetaData(_xMetaData)
+{
+ construct();
+}
+
+OView::~OView()
+{
+}
+
+void OView::construct()
+{
+ ODescriptor::construct();
+
+ sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME,nAttrib,&m_CatalogName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib,&m_SchemaName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND), PROPERTY_ID_COMMAND, nAttrib,&m_Command, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CHECKOPTION), PROPERTY_ID_CHECKOPTION,nAttrib,&m_CheckOption, ::cppu::UnoType<sal_Int32>::get());
+}
+
+Sequence< Type > SAL_CALL OView::getTypes( )
+{
+ return ::comphelper::concatSequences(ODescriptor::getTypes(),OView_BASE::getTypes());
+}
+
+Any SAL_CALL OView::queryInterface( const Type & rType )
+{
+ Any aRet = OView_BASE::queryInterface( rType);
+ return aRet.hasValue() ? aRet : ODescriptor::queryInterface( rType);
+}
+
+::cppu::IPropertyArrayHelper* OView::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & OView::getInfoHelper()
+{
+ return *getArrayHelper(isNew() ? 1 : 0);
+}
+
+OUString SAL_CALL OView::getName()
+{
+ OUString sComposedName;
+ if(m_xMetaData.is())
+ sComposedName = ::dbtools::composeTableName( m_xMetaData, m_CatalogName, m_SchemaName, m_Name, false, ::dbtools::EComposeRule::InDataManipulation );
+ else
+ {
+ Any aValue;
+ getFastPropertyValue(aValue,PROPERTY_ID_NAME);
+ aValue >>= sComposedName;
+ }
+ return sComposedName;
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OView::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void SAL_CALL OView::setName( const OUString& )
+{
+}
+
+void SAL_CALL OView::acquire() noexcept
+{
+ OView_BASE::acquire();
+}
+
+void SAL_CALL OView::release() noexcept
+{
+ OView_BASE::release();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */