From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- .../source/drivers/ado/ACallableStatement.cxx | 253 ++ connectivity/source/drivers/ado/ACatalog.cxx | 115 + connectivity/source/drivers/ado/AColumn.cxx | 248 ++ connectivity/source/drivers/ado/AColumns.cxx | 125 + connectivity/source/drivers/ado/AConnection.cxx | 568 ++++ .../source/drivers/ado/ADatabaseMetaData.cxx | 1034 ++++++++ .../source/drivers/ado/ADatabaseMetaDataImpl.cxx | 543 ++++ .../drivers/ado/ADatabaseMetaDataResultSet.cxx | 1242 +++++++++ .../ado/ADatabaseMetaDataResultSetMetaData.cxx | 210 ++ connectivity/source/drivers/ado/ADriver.cxx | 250 ++ connectivity/source/drivers/ado/AGroup.cxx | 142 + connectivity/source/drivers/ado/AGroups.cxx | 76 + connectivity/source/drivers/ado/AIndex.cxx | 121 + connectivity/source/drivers/ado/AIndexes.cxx | 82 + connectivity/source/drivers/ado/AKey.cxx | 134 + connectivity/source/drivers/ado/AKeys.cxx | 97 + .../source/drivers/ado/APreparedStatement.cxx | 455 ++++ connectivity/source/drivers/ado/AResultSet.cxx | 1158 ++++++++ .../source/drivers/ado/AResultSetMetaData.cxx | 247 ++ connectivity/source/drivers/ado/AStatement.cxx | 868 ++++++ connectivity/source/drivers/ado/ATable.cxx | 230 ++ connectivity/source/drivers/ado/ATables.cxx | 103 + connectivity/source/drivers/ado/AUser.cxx | 190 ++ connectivity/source/drivers/ado/AUsers.cxx | 77 + connectivity/source/drivers/ado/AView.cxx | 93 + connectivity/source/drivers/ado/AViews.cxx | 97 + connectivity/source/drivers/ado/Aolevariant.cxx | 687 +++++ connectivity/source/drivers/ado/Awrapado.cxx | 2008 ++++++++++++++ connectivity/source/drivers/ado/ado.component | 27 + connectivity/source/drivers/ado/adoimp.cxx | 325 +++ connectivity/source/drivers/calc/CCatalog.cxx | 62 + connectivity/source/drivers/calc/CConnection.cxx | 265 ++ .../source/drivers/calc/CDatabaseMetaData.cxx | 217 ++ connectivity/source/drivers/calc/CDriver.cxx | 95 + connectivity/source/drivers/calc/CTable.cxx | 652 +++++ connectivity/source/drivers/calc/CTables.cxx | 48 + connectivity/source/drivers/calc/calc.component | 27 + connectivity/source/drivers/component/CColumns.cxx | 44 + .../source/drivers/component/CDatabaseMetaData.cxx | 240 ++ .../drivers/component/CPreparedStatement.cxx | 34 + .../source/drivers/component/CResultSet.cxx | 172 ++ .../source/drivers/component/CStatement.cxx | 35 + connectivity/source/drivers/component/CTable.cxx | 190 ++ connectivity/source/drivers/dbase/DCatalog.cxx | 57 + connectivity/source/drivers/dbase/DColumns.cxx | 77 + connectivity/source/drivers/dbase/DConnection.cxx | 112 + .../source/drivers/dbase/DDatabaseMetaData.cxx | 386 +++ connectivity/source/drivers/dbase/DDriver.cxx | 118 + connectivity/source/drivers/dbase/DIndex.cxx | 608 +++++ .../source/drivers/dbase/DIndexColumns.cxx | 82 + connectivity/source/drivers/dbase/DIndexIter.cxx | 282 ++ connectivity/source/drivers/dbase/DIndexes.cxx | 116 + .../source/drivers/dbase/DPreparedStatement.cxx | 35 + connectivity/source/drivers/dbase/DResultSet.cxx | 211 ++ connectivity/source/drivers/dbase/DStatement.cxx | 35 + connectivity/source/drivers/dbase/DTable.cxx | 2769 ++++++++++++++++++++ connectivity/source/drivers/dbase/DTables.cxx | 127 + connectivity/source/drivers/dbase/dbase.component | 27 + connectivity/source/drivers/dbase/dindexnode.cxx | 1046 ++++++++ connectivity/source/drivers/evoab2/EApi.cxx | 135 + connectivity/source/drivers/evoab2/EApi.h | 160 ++ connectivity/source/drivers/evoab2/NCatalog.cxx | 86 + connectivity/source/drivers/evoab2/NCatalog.hxx | 43 + connectivity/source/drivers/evoab2/NColumns.cxx | 87 + connectivity/source/drivers/evoab2/NColumns.hxx | 44 + connectivity/source/drivers/evoab2/NConnection.cxx | 242 ++ connectivity/source/drivers/evoab2/NConnection.hxx | 106 + .../source/drivers/evoab2/NDatabaseMetaData.cxx | 1157 ++++++++ .../source/drivers/evoab2/NDatabaseMetaData.hxx | 218 ++ connectivity/source/drivers/evoab2/NDriver.cxx | 157 ++ connectivity/source/drivers/evoab2/NDriver.hxx | 74 + .../source/drivers/evoab2/NPreparedStatement.cxx | 319 +++ .../source/drivers/evoab2/NPreparedStatement.hxx | 108 + connectivity/source/drivers/evoab2/NResultSet.cxx | 1038 ++++++++ connectivity/source/drivers/evoab2/NResultSet.hxx | 182 ++ .../source/drivers/evoab2/NResultSetMetaData.cxx | 174 ++ .../source/drivers/evoab2/NResultSetMetaData.hxx | 77 + connectivity/source/drivers/evoab2/NStatement.cxx | 682 +++++ connectivity/source/drivers/evoab2/NStatement.hxx | 273 ++ connectivity/source/drivers/evoab2/NTable.cxx | 76 + connectivity/source/drivers/evoab2/NTable.hxx | 53 + connectivity/source/drivers/evoab2/NTables.cxx | 79 + connectivity/source/drivers/evoab2/NTables.hxx | 43 + connectivity/source/drivers/evoab2/evoab.component | 26 + connectivity/source/drivers/file/FCatalog.cxx | 103 + connectivity/source/drivers/file/FColumns.cxx | 80 + connectivity/source/drivers/file/FConnection.cxx | 432 +++ .../source/drivers/file/FDatabaseMetaData.cxx | 1055 ++++++++ .../source/drivers/file/FDateFunctions.cxx | 278 ++ connectivity/source/drivers/file/FDriver.cxx | 205 ++ connectivity/source/drivers/file/FNoException.cxx | 102 + .../source/drivers/file/FNumericFunctions.cxx | 242 ++ .../source/drivers/file/FPreparedStatement.cxx | 555 ++++ connectivity/source/drivers/file/FResultSet.cxx | 1593 +++++++++++ .../source/drivers/file/FResultSetMetaData.cxx | 188 ++ connectivity/source/drivers/file/FStatement.cxx | 711 +++++ .../source/drivers/file/FStringFunctions.cxx | 233 ++ connectivity/source/drivers/file/FTable.cxx | 185 ++ connectivity/source/drivers/file/FTables.cxx | 54 + connectivity/source/drivers/file/fanalyzer.cxx | 207 ++ connectivity/source/drivers/file/fcode.cxx | 373 +++ connectivity/source/drivers/file/fcomp.cxx | 886 +++++++ connectivity/source/drivers/file/quotedstring.cxx | 146 ++ connectivity/source/drivers/firebird/Blob.cxx | 391 +++ connectivity/source/drivers/firebird/Blob.hxx | 100 + connectivity/source/drivers/firebird/Catalog.cxx | 105 + connectivity/source/drivers/firebird/Catalog.hxx | 40 + connectivity/source/drivers/firebird/Clob.cxx | 141 + connectivity/source/drivers/firebird/Clob.hxx | 64 + connectivity/source/drivers/firebird/Column.cxx | 51 + connectivity/source/drivers/firebird/Column.hxx | 32 + connectivity/source/drivers/firebird/Columns.cxx | 41 + connectivity/source/drivers/firebird/Columns.hxx | 30 + .../source/drivers/firebird/Connection.cxx | 984 +++++++ .../source/drivers/firebird/Connection.hxx | 247 ++ .../source/drivers/firebird/DatabaseMetaData.cxx | 1803 +++++++++++++ .../source/drivers/firebird/DatabaseMetaData.hxx | 205 ++ connectivity/source/drivers/firebird/Driver.cxx | 228 ++ connectivity/source/drivers/firebird/Driver.hxx | 90 + connectivity/source/drivers/firebird/Indexes.cxx | 34 + connectivity/source/drivers/firebird/Indexes.hxx | 39 + connectivity/source/drivers/firebird/Keys.cxx | 54 + connectivity/source/drivers/firebird/Keys.hxx | 36 + .../source/drivers/firebird/PreparedStatement.cxx | 1058 ++++++++ .../source/drivers/firebird/PreparedStatement.hxx | 152 ++ connectivity/source/drivers/firebird/ResultSet.cxx | 926 +++++++ connectivity/source/drivers/firebird/ResultSet.hxx | 216 ++ .../source/drivers/firebird/ResultSetMetaData.cxx | 301 +++ .../source/drivers/firebird/ResultSetMetaData.hxx | 80 + connectivity/source/drivers/firebird/Statement.cxx | 176 ++ connectivity/source/drivers/firebird/Statement.hxx | 84 + .../drivers/firebird/StatementCommonBase.cxx | 486 ++++ .../drivers/firebird/StatementCommonBase.hxx | 134 + .../source/drivers/firebird/SubComponent.hxx | 111 + connectivity/source/drivers/firebird/Table.cxx | 245 ++ connectivity/source/drivers/firebird/Table.hxx | 81 + connectivity/source/drivers/firebird/Tables.cxx | 229 ++ connectivity/source/drivers/firebird/Tables.hxx | 60 + connectivity/source/drivers/firebird/User.cxx | 53 + connectivity/source/drivers/firebird/User.hxx | 46 + connectivity/source/drivers/firebird/Users.cxx | 78 + connectivity/source/drivers/firebird/Users.hxx | 53 + connectivity/source/drivers/firebird/Util.cxx | 440 ++++ connectivity/source/drivers/firebird/Util.hxx | 126 + connectivity/source/drivers/firebird/View.cxx | 85 + connectivity/source/drivers/firebird/View.hxx | 60 + connectivity/source/drivers/firebird/Views.cxx | 112 + connectivity/source/drivers/firebird/Views.hxx | 42 + .../drivers/firebird/firebird_sdbc.component | 19 + connectivity/source/drivers/flat/ECatalog.cxx | 58 + connectivity/source/drivers/flat/EColumns.cxx | 44 + connectivity/source/drivers/flat/EConnection.cxx | 176 ++ .../source/drivers/flat/EDatabaseMetaData.cxx | 244 ++ connectivity/source/drivers/flat/EDriver.cxx | 135 + .../source/drivers/flat/EPreparedStatement.cxx | 35 + connectivity/source/drivers/flat/EResultSet.cxx | 169 ++ connectivity/source/drivers/flat/EStatement.cxx | 34 + connectivity/source/drivers/flat/ETable.cxx | 961 +++++++ connectivity/source/drivers/flat/ETables.cxx | 44 + connectivity/source/drivers/flat/flat.component | 27 + connectivity/source/drivers/hsqldb/HCatalog.cxx | 148 ++ connectivity/source/drivers/hsqldb/HColumns.cxx | 76 + connectivity/source/drivers/hsqldb/HConnection.cxx | 337 +++ connectivity/source/drivers/hsqldb/HDriver.cxx | 894 +++++++ .../source/drivers/hsqldb/HStorageAccess.cxx | 511 ++++ connectivity/source/drivers/hsqldb/HStorageMap.cxx | 361 +++ connectivity/source/drivers/hsqldb/HTable.cxx | 386 +++ connectivity/source/drivers/hsqldb/HTables.cxx | 176 ++ .../source/drivers/hsqldb/HTerminateListener.cxx | 45 + .../source/drivers/hsqldb/HTerminateListener.hxx | 46 + connectivity/source/drivers/hsqldb/HTools.cxx | 53 + connectivity/source/drivers/hsqldb/HUser.cxx | 328 +++ connectivity/source/drivers/hsqldb/HUsers.cxx | 98 + connectivity/source/drivers/hsqldb/HView.cxx | 216 ++ connectivity/source/drivers/hsqldb/HViews.cxx | 148 ++ .../source/drivers/hsqldb/StorageFileAccess.cxx | 167 ++ .../drivers/hsqldb/StorageNativeInputStream.cxx | 292 +++ .../drivers/hsqldb/StorageNativeOutputStream.cxx | 195 ++ connectivity/source/drivers/hsqldb/accesslog.cxx | 78 + connectivity/source/drivers/hsqldb/accesslog.hxx | 135 + .../source/drivers/hsqldb/hsqldb.component | 27 + connectivity/source/drivers/jdbc/Array.cxx | 132 + connectivity/source/drivers/jdbc/Blob.cxx | 144 + connectivity/source/drivers/jdbc/Boolean.cxx | 38 + .../source/drivers/jdbc/CallableStatement.cxx | 354 +++ connectivity/source/drivers/jdbc/Class.cxx | 70 + connectivity/source/drivers/jdbc/Clob.cxx | 132 + connectivity/source/drivers/jdbc/ConnectionLog.cxx | 110 + .../source/drivers/jdbc/ContextClassLoader.cxx | 111 + .../source/drivers/jdbc/DatabaseMetaData.cxx | 1463 +++++++++++ connectivity/source/drivers/jdbc/Date.cxx | 38 + .../source/drivers/jdbc/DriverPropertyInfo.cxx | 40 + connectivity/source/drivers/jdbc/Exception.cxx | 37 + connectivity/source/drivers/jdbc/InputStream.cxx | 113 + connectivity/source/drivers/jdbc/JBigDecimal.cxx | 79 + connectivity/source/drivers/jdbc/JConnection.cxx | 803 ++++++ connectivity/source/drivers/jdbc/JDriver.cxx | 231 ++ connectivity/source/drivers/jdbc/JStatement.cxx | 864 ++++++ connectivity/source/drivers/jdbc/Object.cxx | 481 ++++ .../source/drivers/jdbc/PreparedStatement.cxx | 697 +++++ connectivity/source/drivers/jdbc/Reader.cxx | 178 ++ connectivity/source/drivers/jdbc/Ref.cxx | 48 + connectivity/source/drivers/jdbc/ResultSet.cxx | 1013 +++++++ .../source/drivers/jdbc/ResultSetMetaData.cxx | 200 ++ connectivity/source/drivers/jdbc/SQLException.cxx | 87 + connectivity/source/drivers/jdbc/SQLWarning.cxx | 37 + connectivity/source/drivers/jdbc/String.cxx | 47 + connectivity/source/drivers/jdbc/Throwable.cxx | 59 + connectivity/source/drivers/jdbc/Timestamp.cxx | 189 ++ connectivity/source/drivers/jdbc/jdbc.component | 37 + connectivity/source/drivers/jdbc/tools.cxx | 261 ++ .../source/drivers/macab/MacabAddressBook.cxx | 249 ++ .../source/drivers/macab/MacabAddressBook.hxx | 60 + connectivity/source/drivers/macab/MacabCatalog.cxx | 112 + connectivity/source/drivers/macab/MacabCatalog.hxx | 51 + connectivity/source/drivers/macab/MacabColumns.cxx | 94 + connectivity/source/drivers/macab/MacabColumns.hxx | 42 + .../source/drivers/macab/MacabConnection.cxx | 316 +++ .../source/drivers/macab/MacabConnection.hxx | 110 + .../source/drivers/macab/MacabDatabaseMetaData.cxx | 1073 ++++++++ .../source/drivers/macab/MacabDatabaseMetaData.hxx | 195 ++ connectivity/source/drivers/macab/MacabDriver.cxx | 310 +++ connectivity/source/drivers/macab/MacabDriver.hxx | 161 ++ connectivity/source/drivers/macab/MacabGroup.cxx | 93 + connectivity/source/drivers/macab/MacabGroup.hxx | 38 + connectivity/source/drivers/macab/MacabHeader.cxx | 330 +++ connectivity/source/drivers/macab/MacabHeader.hxx | 61 + .../drivers/macab/MacabPreparedStatement.cxx | 343 +++ .../drivers/macab/MacabPreparedStatement.hxx | 111 + connectivity/source/drivers/macab/MacabRecord.cxx | 336 +++ connectivity/source/drivers/macab/MacabRecord.hxx | 71 + connectivity/source/drivers/macab/MacabRecords.cxx | 1160 ++++++++ connectivity/source/drivers/macab/MacabRecords.hxx | 125 + .../source/drivers/macab/MacabResultSet.cxx | 1094 ++++++++ .../source/drivers/macab/MacabResultSet.hxx | 213 ++ .../drivers/macab/MacabResultSetMetaData.cxx | 216 ++ .../drivers/macab/MacabResultSetMetaData.hxx | 80 + .../source/drivers/macab/MacabStatement.cxx | 631 +++++ .../source/drivers/macab/MacabStatement.hxx | 169 ++ connectivity/source/drivers/macab/MacabTable.cxx | 86 + connectivity/source/drivers/macab/MacabTable.hxx | 54 + connectivity/source/drivers/macab/MacabTables.cxx | 80 + connectivity/source/drivers/macab/MacabTables.hxx | 49 + connectivity/source/drivers/macab/macab1.component | 26 + .../source/drivers/macab/macabcondition.cxx | 244 ++ .../source/drivers/macab/macabcondition.hxx | 165 ++ connectivity/source/drivers/macab/macaborder.cxx | 75 + connectivity/source/drivers/macab/macaborder.hxx | 64 + .../source/drivers/macab/macabutilities.hxx | 138 + .../drivers/mozab/bootstrap/MMozillaBootstrap.cxx | 138 + .../drivers/mozab/bootstrap/MMozillaBootstrap.hxx | 78 + .../source/drivers/mozab/bootstrap/MNSFolders.cxx | 159 ++ .../source/drivers/mozab/bootstrap/MNSFolders.hxx | 28 + .../drivers/mozab/bootstrap/MNSINIParser.cxx | 94 + .../drivers/mozab/bootstrap/MNSINIParser.hxx | 54 + .../drivers/mozab/bootstrap/MNSProfileDiscover.cxx | 210 ++ .../drivers/mozab/bootstrap/MNSProfileDiscover.hxx | 80 + connectivity/source/drivers/mozab/bootstrap/README | 3 + .../drivers/mozab/bootstrap/mozbootstrap.component | 26 + .../source/drivers/mysql_jdbc/YCatalog.cxx | 132 + .../source/drivers/mysql_jdbc/YColumns.cxx | 72 + connectivity/source/drivers/mysql_jdbc/YDriver.cxx | 416 +++ connectivity/source/drivers/mysql_jdbc/YTable.cxx | 327 +++ connectivity/source/drivers/mysql_jdbc/YTables.cxx | 208 ++ connectivity/source/drivers/mysql_jdbc/YUser.cxx | 325 +++ connectivity/source/drivers/mysql_jdbc/YUsers.cxx | 91 + connectivity/source/drivers/mysql_jdbc/YViews.cxx | 138 + .../source/drivers/mysql_jdbc/mysql_jdbc.component | 27 + .../source/drivers/mysqlc/mysqlc.component | 15 + .../source/drivers/mysqlc/mysqlc_catalog.cxx | 70 + .../source/drivers/mysqlc/mysqlc_catalog.hxx | 38 + .../source/drivers/mysqlc/mysqlc_column.cxx | 45 + .../source/drivers/mysqlc/mysqlc_column.hxx | 32 + .../source/drivers/mysqlc/mysqlc_columns.cxx | 28 + .../source/drivers/mysqlc/mysqlc_columns.hxx | 29 + .../source/drivers/mysqlc/mysqlc_connection.cxx | 524 ++++ .../source/drivers/mysqlc/mysqlc_connection.hxx | 190 ++ .../drivers/mysqlc/mysqlc_databasemetadata.cxx | 1051 ++++++++ .../drivers/mysqlc/mysqlc_databasemetadata.hxx | 233 ++ .../source/drivers/mysqlc/mysqlc_driver.cxx | 149 ++ .../source/drivers/mysqlc/mysqlc_driver.hxx | 88 + .../source/drivers/mysqlc/mysqlc_general.cxx | 357 +++ .../source/drivers/mysqlc/mysqlc_general.hxx | 116 + .../source/drivers/mysqlc/mysqlc_indexes.cxx | 25 + .../source/drivers/mysqlc/mysqlc_indexes.hxx | 34 + connectivity/source/drivers/mysqlc/mysqlc_keys.cxx | 19 + connectivity/source/drivers/mysqlc/mysqlc_keys.hxx | 25 + .../drivers/mysqlc/mysqlc_prepared_resultset.cxx | 1129 ++++++++ .../drivers/mysqlc/mysqlc_prepared_resultset.hxx | 253 ++ .../drivers/mysqlc/mysqlc_preparedstatement.cxx | 580 ++++ .../drivers/mysqlc/mysqlc_preparedstatement.hxx | 157 ++ .../source/drivers/mysqlc/mysqlc_propertyids.hxx | 44 + .../source/drivers/mysqlc/mysqlc_resultset.cxx | 1112 ++++++++ .../source/drivers/mysqlc/mysqlc_resultset.hxx | 275 ++ .../drivers/mysqlc/mysqlc_resultsetmetadata.cxx | 212 ++ .../drivers/mysqlc/mysqlc_resultsetmetadata.hxx | 103 + .../source/drivers/mysqlc/mysqlc_services.cxx | 110 + .../source/drivers/mysqlc/mysqlc_statement.cxx | 390 +++ .../source/drivers/mysqlc/mysqlc_statement.hxx | 175 ++ .../source/drivers/mysqlc/mysqlc_subcomponent.hxx | 138 + .../source/drivers/mysqlc/mysqlc_table.cxx | 160 ++ .../source/drivers/mysqlc/mysqlc_table.hxx | 65 + .../source/drivers/mysqlc/mysqlc_tables.cxx | 157 ++ .../source/drivers/mysqlc/mysqlc_tables.hxx | 56 + .../source/drivers/mysqlc/mysqlc_types.cxx | 700 +++++ .../source/drivers/mysqlc/mysqlc_types.hxx | 45 + connectivity/source/drivers/mysqlc/mysqlc_user.cxx | 55 + connectivity/source/drivers/mysqlc/mysqlc_user.hxx | 45 + connectivity/source/drivers/mysqlc/mysqlc_view.cxx | 98 + connectivity/source/drivers/mysqlc/mysqlc_view.hxx | 72 + .../source/drivers/mysqlc/mysqlc_views.cxx | 113 + .../source/drivers/mysqlc/mysqlc_views.hxx | 50 + connectivity/source/drivers/odbc/OConnection.cxx | 547 ++++ .../source/drivers/odbc/ODatabaseMetaData.cxx | 1717 ++++++++++++ .../drivers/odbc/ODatabaseMetaDataResultSet.cxx | 1330 ++++++++++ connectivity/source/drivers/odbc/ODriver.cxx | 192 ++ connectivity/source/drivers/odbc/OFunctions.cxx | 245 ++ .../source/drivers/odbc/OPreparedStatement.cxx | 924 +++++++ connectivity/source/drivers/odbc/ORealDriver.cxx | 291 ++ connectivity/source/drivers/odbc/OResultSet.cxx | 1847 +++++++++++++ .../source/drivers/odbc/OResultSetMetaData.cxx | 291 ++ connectivity/source/drivers/odbc/OStatement.cxx | 1140 ++++++++ connectivity/source/drivers/odbc/OTools.cxx | 797 ++++++ connectivity/source/drivers/odbc/odbc.component | 26 + .../postgresql/postgresql-sdbc-impl.component | 17 + .../drivers/postgresql/postgresql-sdbc.component | 17 + .../source/drivers/postgresql/pq_array.cxx | 122 + .../source/drivers/postgresql/pq_array.hxx | 97 + .../source/drivers/postgresql/pq_baseresultset.cxx | 613 +++++ .../source/drivers/postgresql/pq_baseresultset.hxx | 203 ++ .../source/drivers/postgresql/pq_connection.cxx | 571 ++++ .../source/drivers/postgresql/pq_connection.hxx | 194 ++ .../drivers/postgresql/pq_databasemetadata.cxx | 2511 ++++++++++++++++++ .../drivers/postgresql/pq_databasemetadata.hxx | 237 ++ .../source/drivers/postgresql/pq_driver.cxx | 148 ++ .../source/drivers/postgresql/pq_driver.hxx | 116 + .../postgresql/pq_fakedupdateableresultset.cxx | 214 ++ .../postgresql/pq_fakedupdateableresultset.hxx | 106 + .../drivers/postgresql/pq_preparedstatement.cxx | 738 ++++++ .../drivers/postgresql/pq_preparedstatement.hxx | 221 ++ .../source/drivers/postgresql/pq_resultset.cxx | 308 +++ .../source/drivers/postgresql/pq_resultset.hxx | 94 + .../drivers/postgresql/pq_resultsetmetadata.cxx | 441 ++++ .../drivers/postgresql/pq_resultsetmetadata.hxx | 127 + .../drivers/postgresql/pq_sequenceresultset.cxx | 125 + .../drivers/postgresql/pq_sequenceresultset.hxx | 92 + .../postgresql/pq_sequenceresultsetmetadata.cxx | 191 ++ .../postgresql/pq_sequenceresultsetmetadata.hxx | 89 + .../source/drivers/postgresql/pq_statement.cxx | 888 +++++++ .../source/drivers/postgresql/pq_statement.hxx | 198 ++ .../source/drivers/postgresql/pq_statics.cxx | 626 +++++ .../source/drivers/postgresql/pq_statics.hxx | 239 ++ .../source/drivers/postgresql/pq_tools.cxx | 1249 +++++++++ .../source/drivers/postgresql/pq_tools.hxx | 176 ++ .../drivers/postgresql/pq_updateableresultset.cxx | 550 ++++ .../drivers/postgresql/pq_updateableresultset.hxx | 169 ++ .../source/drivers/postgresql/pq_xbase.cxx | 215 ++ .../source/drivers/postgresql/pq_xbase.hxx | 131 + .../source/drivers/postgresql/pq_xcolumn.cxx | 95 + .../source/drivers/postgresql/pq_xcolumn.hxx | 82 + .../source/drivers/postgresql/pq_xcolumns.cxx | 560 ++++ .../source/drivers/postgresql/pq_xcolumns.hxx | 122 + .../source/drivers/postgresql/pq_xcontainer.cxx | 409 +++ .../source/drivers/postgresql/pq_xcontainer.hxx | 188 ++ .../source/drivers/postgresql/pq_xindex.cxx | 186 ++ .../source/drivers/postgresql/pq_xindex.hxx | 123 + .../source/drivers/postgresql/pq_xindexcolumn.cxx | 96 + .../source/drivers/postgresql/pq_xindexcolumn.hxx | 83 + .../source/drivers/postgresql/pq_xindexcolumns.cxx | 267 ++ .../source/drivers/postgresql/pq_xindexcolumns.hxx | 110 + .../source/drivers/postgresql/pq_xindexes.cxx | 302 +++ .../source/drivers/postgresql/pq_xindexes.hxx | 102 + connectivity/source/drivers/postgresql/pq_xkey.cxx | 182 ++ connectivity/source/drivers/postgresql/pq_xkey.hxx | 119 + .../source/drivers/postgresql/pq_xkeycolumn.cxx | 95 + .../source/drivers/postgresql/pq_xkeycolumn.hxx | 82 + .../source/drivers/postgresql/pq_xkeycolumns.cxx | 238 ++ .../source/drivers/postgresql/pq_xkeycolumns.hxx | 101 + .../source/drivers/postgresql/pq_xkeys.cxx | 294 +++ .../source/drivers/postgresql/pq_xkeys.hxx | 101 + .../source/drivers/postgresql/pq_xtable.cxx | 394 +++ .../source/drivers/postgresql/pq_xtable.hxx | 161 ++ .../source/drivers/postgresql/pq_xtables.cxx | 369 +++ .../source/drivers/postgresql/pq_xtables.hxx | 91 + .../source/drivers/postgresql/pq_xuser.cxx | 172 ++ .../source/drivers/postgresql/pq_xuser.hxx | 93 + .../source/drivers/postgresql/pq_xusers.cxx | 202 ++ .../source/drivers/postgresql/pq_xusers.hxx | 82 + .../source/drivers/postgresql/pq_xview.cxx | 218 ++ .../source/drivers/postgresql/pq_xview.hxx | 92 + .../source/drivers/postgresql/pq_xviews.cxx | 219 ++ .../source/drivers/postgresql/pq_xviews.hxx | 88 + connectivity/source/drivers/writer/WCatalog.cxx | 60 + connectivity/source/drivers/writer/WConnection.cxx | 246 ++ .../source/drivers/writer/WDatabaseMetaData.cxx | 112 + connectivity/source/drivers/writer/WDriver.cxx | 90 + connectivity/source/drivers/writer/WTable.cxx | 250 ++ connectivity/source/drivers/writer/WTables.cxx | 45 + .../source/drivers/writer/writer.component | 17 + 399 files changed, 107257 insertions(+) create mode 100644 connectivity/source/drivers/ado/ACallableStatement.cxx create mode 100644 connectivity/source/drivers/ado/ACatalog.cxx create mode 100644 connectivity/source/drivers/ado/AColumn.cxx create mode 100644 connectivity/source/drivers/ado/AColumns.cxx create mode 100644 connectivity/source/drivers/ado/AConnection.cxx create mode 100644 connectivity/source/drivers/ado/ADatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/ado/ADatabaseMetaDataImpl.cxx create mode 100644 connectivity/source/drivers/ado/ADatabaseMetaDataResultSet.cxx create mode 100644 connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData.cxx create mode 100644 connectivity/source/drivers/ado/ADriver.cxx create mode 100644 connectivity/source/drivers/ado/AGroup.cxx create mode 100644 connectivity/source/drivers/ado/AGroups.cxx create mode 100644 connectivity/source/drivers/ado/AIndex.cxx create mode 100644 connectivity/source/drivers/ado/AIndexes.cxx create mode 100644 connectivity/source/drivers/ado/AKey.cxx create mode 100644 connectivity/source/drivers/ado/AKeys.cxx create mode 100644 connectivity/source/drivers/ado/APreparedStatement.cxx create mode 100644 connectivity/source/drivers/ado/AResultSet.cxx create mode 100644 connectivity/source/drivers/ado/AResultSetMetaData.cxx create mode 100644 connectivity/source/drivers/ado/AStatement.cxx create mode 100644 connectivity/source/drivers/ado/ATable.cxx create mode 100644 connectivity/source/drivers/ado/ATables.cxx create mode 100644 connectivity/source/drivers/ado/AUser.cxx create mode 100644 connectivity/source/drivers/ado/AUsers.cxx create mode 100644 connectivity/source/drivers/ado/AView.cxx create mode 100644 connectivity/source/drivers/ado/AViews.cxx create mode 100644 connectivity/source/drivers/ado/Aolevariant.cxx create mode 100644 connectivity/source/drivers/ado/Awrapado.cxx create mode 100644 connectivity/source/drivers/ado/ado.component create mode 100644 connectivity/source/drivers/ado/adoimp.cxx create mode 100644 connectivity/source/drivers/calc/CCatalog.cxx create mode 100644 connectivity/source/drivers/calc/CConnection.cxx create mode 100644 connectivity/source/drivers/calc/CDatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/calc/CDriver.cxx create mode 100644 connectivity/source/drivers/calc/CTable.cxx create mode 100644 connectivity/source/drivers/calc/CTables.cxx create mode 100644 connectivity/source/drivers/calc/calc.component create mode 100644 connectivity/source/drivers/component/CColumns.cxx create mode 100644 connectivity/source/drivers/component/CDatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/component/CPreparedStatement.cxx create mode 100644 connectivity/source/drivers/component/CResultSet.cxx create mode 100644 connectivity/source/drivers/component/CStatement.cxx create mode 100644 connectivity/source/drivers/component/CTable.cxx create mode 100644 connectivity/source/drivers/dbase/DCatalog.cxx create mode 100644 connectivity/source/drivers/dbase/DColumns.cxx create mode 100644 connectivity/source/drivers/dbase/DConnection.cxx create mode 100644 connectivity/source/drivers/dbase/DDatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/dbase/DDriver.cxx create mode 100644 connectivity/source/drivers/dbase/DIndex.cxx create mode 100644 connectivity/source/drivers/dbase/DIndexColumns.cxx create mode 100644 connectivity/source/drivers/dbase/DIndexIter.cxx create mode 100644 connectivity/source/drivers/dbase/DIndexes.cxx create mode 100644 connectivity/source/drivers/dbase/DPreparedStatement.cxx create mode 100644 connectivity/source/drivers/dbase/DResultSet.cxx create mode 100644 connectivity/source/drivers/dbase/DStatement.cxx create mode 100644 connectivity/source/drivers/dbase/DTable.cxx create mode 100644 connectivity/source/drivers/dbase/DTables.cxx create mode 100644 connectivity/source/drivers/dbase/dbase.component create mode 100644 connectivity/source/drivers/dbase/dindexnode.cxx create mode 100644 connectivity/source/drivers/evoab2/EApi.cxx create mode 100644 connectivity/source/drivers/evoab2/EApi.h create mode 100644 connectivity/source/drivers/evoab2/NCatalog.cxx create mode 100644 connectivity/source/drivers/evoab2/NCatalog.hxx create mode 100644 connectivity/source/drivers/evoab2/NColumns.cxx create mode 100644 connectivity/source/drivers/evoab2/NColumns.hxx create mode 100644 connectivity/source/drivers/evoab2/NConnection.cxx create mode 100644 connectivity/source/drivers/evoab2/NConnection.hxx create mode 100644 connectivity/source/drivers/evoab2/NDatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/evoab2/NDatabaseMetaData.hxx create mode 100644 connectivity/source/drivers/evoab2/NDriver.cxx create mode 100644 connectivity/source/drivers/evoab2/NDriver.hxx create mode 100644 connectivity/source/drivers/evoab2/NPreparedStatement.cxx create mode 100644 connectivity/source/drivers/evoab2/NPreparedStatement.hxx create mode 100644 connectivity/source/drivers/evoab2/NResultSet.cxx create mode 100644 connectivity/source/drivers/evoab2/NResultSet.hxx create mode 100644 connectivity/source/drivers/evoab2/NResultSetMetaData.cxx create mode 100644 connectivity/source/drivers/evoab2/NResultSetMetaData.hxx create mode 100644 connectivity/source/drivers/evoab2/NStatement.cxx create mode 100644 connectivity/source/drivers/evoab2/NStatement.hxx create mode 100644 connectivity/source/drivers/evoab2/NTable.cxx create mode 100644 connectivity/source/drivers/evoab2/NTable.hxx create mode 100644 connectivity/source/drivers/evoab2/NTables.cxx create mode 100644 connectivity/source/drivers/evoab2/NTables.hxx create mode 100644 connectivity/source/drivers/evoab2/evoab.component create mode 100644 connectivity/source/drivers/file/FCatalog.cxx create mode 100644 connectivity/source/drivers/file/FColumns.cxx create mode 100644 connectivity/source/drivers/file/FConnection.cxx create mode 100644 connectivity/source/drivers/file/FDatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/file/FDateFunctions.cxx create mode 100644 connectivity/source/drivers/file/FDriver.cxx create mode 100644 connectivity/source/drivers/file/FNoException.cxx create mode 100644 connectivity/source/drivers/file/FNumericFunctions.cxx create mode 100644 connectivity/source/drivers/file/FPreparedStatement.cxx create mode 100644 connectivity/source/drivers/file/FResultSet.cxx create mode 100644 connectivity/source/drivers/file/FResultSetMetaData.cxx create mode 100644 connectivity/source/drivers/file/FStatement.cxx create mode 100644 connectivity/source/drivers/file/FStringFunctions.cxx create mode 100644 connectivity/source/drivers/file/FTable.cxx create mode 100644 connectivity/source/drivers/file/FTables.cxx create mode 100644 connectivity/source/drivers/file/fanalyzer.cxx create mode 100644 connectivity/source/drivers/file/fcode.cxx create mode 100644 connectivity/source/drivers/file/fcomp.cxx create mode 100644 connectivity/source/drivers/file/quotedstring.cxx create mode 100644 connectivity/source/drivers/firebird/Blob.cxx create mode 100644 connectivity/source/drivers/firebird/Blob.hxx create mode 100644 connectivity/source/drivers/firebird/Catalog.cxx create mode 100644 connectivity/source/drivers/firebird/Catalog.hxx create mode 100644 connectivity/source/drivers/firebird/Clob.cxx create mode 100644 connectivity/source/drivers/firebird/Clob.hxx create mode 100644 connectivity/source/drivers/firebird/Column.cxx create mode 100644 connectivity/source/drivers/firebird/Column.hxx create mode 100644 connectivity/source/drivers/firebird/Columns.cxx create mode 100644 connectivity/source/drivers/firebird/Columns.hxx create mode 100644 connectivity/source/drivers/firebird/Connection.cxx create mode 100644 connectivity/source/drivers/firebird/Connection.hxx create mode 100644 connectivity/source/drivers/firebird/DatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/firebird/DatabaseMetaData.hxx create mode 100644 connectivity/source/drivers/firebird/Driver.cxx create mode 100644 connectivity/source/drivers/firebird/Driver.hxx create mode 100644 connectivity/source/drivers/firebird/Indexes.cxx create mode 100644 connectivity/source/drivers/firebird/Indexes.hxx create mode 100644 connectivity/source/drivers/firebird/Keys.cxx create mode 100644 connectivity/source/drivers/firebird/Keys.hxx create mode 100644 connectivity/source/drivers/firebird/PreparedStatement.cxx create mode 100644 connectivity/source/drivers/firebird/PreparedStatement.hxx create mode 100644 connectivity/source/drivers/firebird/ResultSet.cxx create mode 100644 connectivity/source/drivers/firebird/ResultSet.hxx create mode 100644 connectivity/source/drivers/firebird/ResultSetMetaData.cxx create mode 100644 connectivity/source/drivers/firebird/ResultSetMetaData.hxx create mode 100644 connectivity/source/drivers/firebird/Statement.cxx create mode 100644 connectivity/source/drivers/firebird/Statement.hxx create mode 100644 connectivity/source/drivers/firebird/StatementCommonBase.cxx create mode 100644 connectivity/source/drivers/firebird/StatementCommonBase.hxx create mode 100644 connectivity/source/drivers/firebird/SubComponent.hxx create mode 100644 connectivity/source/drivers/firebird/Table.cxx create mode 100644 connectivity/source/drivers/firebird/Table.hxx create mode 100644 connectivity/source/drivers/firebird/Tables.cxx create mode 100644 connectivity/source/drivers/firebird/Tables.hxx create mode 100644 connectivity/source/drivers/firebird/User.cxx create mode 100644 connectivity/source/drivers/firebird/User.hxx create mode 100644 connectivity/source/drivers/firebird/Users.cxx create mode 100644 connectivity/source/drivers/firebird/Users.hxx create mode 100644 connectivity/source/drivers/firebird/Util.cxx create mode 100644 connectivity/source/drivers/firebird/Util.hxx create mode 100644 connectivity/source/drivers/firebird/View.cxx create mode 100644 connectivity/source/drivers/firebird/View.hxx create mode 100644 connectivity/source/drivers/firebird/Views.cxx create mode 100644 connectivity/source/drivers/firebird/Views.hxx create mode 100644 connectivity/source/drivers/firebird/firebird_sdbc.component create mode 100644 connectivity/source/drivers/flat/ECatalog.cxx create mode 100644 connectivity/source/drivers/flat/EColumns.cxx create mode 100644 connectivity/source/drivers/flat/EConnection.cxx create mode 100644 connectivity/source/drivers/flat/EDatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/flat/EDriver.cxx create mode 100644 connectivity/source/drivers/flat/EPreparedStatement.cxx create mode 100644 connectivity/source/drivers/flat/EResultSet.cxx create mode 100644 connectivity/source/drivers/flat/EStatement.cxx create mode 100644 connectivity/source/drivers/flat/ETable.cxx create mode 100644 connectivity/source/drivers/flat/ETables.cxx create mode 100644 connectivity/source/drivers/flat/flat.component create mode 100644 connectivity/source/drivers/hsqldb/HCatalog.cxx create mode 100644 connectivity/source/drivers/hsqldb/HColumns.cxx create mode 100644 connectivity/source/drivers/hsqldb/HConnection.cxx create mode 100644 connectivity/source/drivers/hsqldb/HDriver.cxx create mode 100644 connectivity/source/drivers/hsqldb/HStorageAccess.cxx create mode 100644 connectivity/source/drivers/hsqldb/HStorageMap.cxx create mode 100644 connectivity/source/drivers/hsqldb/HTable.cxx create mode 100644 connectivity/source/drivers/hsqldb/HTables.cxx create mode 100644 connectivity/source/drivers/hsqldb/HTerminateListener.cxx create mode 100644 connectivity/source/drivers/hsqldb/HTerminateListener.hxx create mode 100644 connectivity/source/drivers/hsqldb/HTools.cxx create mode 100644 connectivity/source/drivers/hsqldb/HUser.cxx create mode 100644 connectivity/source/drivers/hsqldb/HUsers.cxx create mode 100644 connectivity/source/drivers/hsqldb/HView.cxx create mode 100644 connectivity/source/drivers/hsqldb/HViews.cxx create mode 100644 connectivity/source/drivers/hsqldb/StorageFileAccess.cxx create mode 100644 connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx create mode 100644 connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx create mode 100644 connectivity/source/drivers/hsqldb/accesslog.cxx create mode 100644 connectivity/source/drivers/hsqldb/accesslog.hxx create mode 100644 connectivity/source/drivers/hsqldb/hsqldb.component create mode 100644 connectivity/source/drivers/jdbc/Array.cxx create mode 100644 connectivity/source/drivers/jdbc/Blob.cxx create mode 100644 connectivity/source/drivers/jdbc/Boolean.cxx create mode 100644 connectivity/source/drivers/jdbc/CallableStatement.cxx create mode 100644 connectivity/source/drivers/jdbc/Class.cxx create mode 100644 connectivity/source/drivers/jdbc/Clob.cxx create mode 100644 connectivity/source/drivers/jdbc/ConnectionLog.cxx create mode 100644 connectivity/source/drivers/jdbc/ContextClassLoader.cxx create mode 100644 connectivity/source/drivers/jdbc/DatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/jdbc/Date.cxx create mode 100644 connectivity/source/drivers/jdbc/DriverPropertyInfo.cxx create mode 100644 connectivity/source/drivers/jdbc/Exception.cxx create mode 100644 connectivity/source/drivers/jdbc/InputStream.cxx create mode 100644 connectivity/source/drivers/jdbc/JBigDecimal.cxx create mode 100644 connectivity/source/drivers/jdbc/JConnection.cxx create mode 100644 connectivity/source/drivers/jdbc/JDriver.cxx create mode 100644 connectivity/source/drivers/jdbc/JStatement.cxx create mode 100644 connectivity/source/drivers/jdbc/Object.cxx create mode 100644 connectivity/source/drivers/jdbc/PreparedStatement.cxx create mode 100644 connectivity/source/drivers/jdbc/Reader.cxx create mode 100644 connectivity/source/drivers/jdbc/Ref.cxx create mode 100644 connectivity/source/drivers/jdbc/ResultSet.cxx create mode 100644 connectivity/source/drivers/jdbc/ResultSetMetaData.cxx create mode 100644 connectivity/source/drivers/jdbc/SQLException.cxx create mode 100644 connectivity/source/drivers/jdbc/SQLWarning.cxx create mode 100644 connectivity/source/drivers/jdbc/String.cxx create mode 100644 connectivity/source/drivers/jdbc/Throwable.cxx create mode 100644 connectivity/source/drivers/jdbc/Timestamp.cxx create mode 100644 connectivity/source/drivers/jdbc/jdbc.component create mode 100644 connectivity/source/drivers/jdbc/tools.cxx create mode 100644 connectivity/source/drivers/macab/MacabAddressBook.cxx create mode 100644 connectivity/source/drivers/macab/MacabAddressBook.hxx create mode 100644 connectivity/source/drivers/macab/MacabCatalog.cxx create mode 100644 connectivity/source/drivers/macab/MacabCatalog.hxx create mode 100644 connectivity/source/drivers/macab/MacabColumns.cxx create mode 100644 connectivity/source/drivers/macab/MacabColumns.hxx create mode 100644 connectivity/source/drivers/macab/MacabConnection.cxx create mode 100644 connectivity/source/drivers/macab/MacabConnection.hxx create mode 100644 connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx create mode 100644 connectivity/source/drivers/macab/MacabDriver.cxx create mode 100644 connectivity/source/drivers/macab/MacabDriver.hxx create mode 100644 connectivity/source/drivers/macab/MacabGroup.cxx create mode 100644 connectivity/source/drivers/macab/MacabGroup.hxx create mode 100644 connectivity/source/drivers/macab/MacabHeader.cxx create mode 100644 connectivity/source/drivers/macab/MacabHeader.hxx create mode 100644 connectivity/source/drivers/macab/MacabPreparedStatement.cxx create mode 100644 connectivity/source/drivers/macab/MacabPreparedStatement.hxx create mode 100644 connectivity/source/drivers/macab/MacabRecord.cxx create mode 100644 connectivity/source/drivers/macab/MacabRecord.hxx create mode 100644 connectivity/source/drivers/macab/MacabRecords.cxx create mode 100644 connectivity/source/drivers/macab/MacabRecords.hxx create mode 100644 connectivity/source/drivers/macab/MacabResultSet.cxx create mode 100644 connectivity/source/drivers/macab/MacabResultSet.hxx create mode 100644 connectivity/source/drivers/macab/MacabResultSetMetaData.cxx create mode 100644 connectivity/source/drivers/macab/MacabResultSetMetaData.hxx create mode 100644 connectivity/source/drivers/macab/MacabStatement.cxx create mode 100644 connectivity/source/drivers/macab/MacabStatement.hxx create mode 100644 connectivity/source/drivers/macab/MacabTable.cxx create mode 100644 connectivity/source/drivers/macab/MacabTable.hxx create mode 100644 connectivity/source/drivers/macab/MacabTables.cxx create mode 100644 connectivity/source/drivers/macab/MacabTables.hxx create mode 100644 connectivity/source/drivers/macab/macab1.component create mode 100644 connectivity/source/drivers/macab/macabcondition.cxx create mode 100644 connectivity/source/drivers/macab/macabcondition.hxx create mode 100644 connectivity/source/drivers/macab/macaborder.cxx create mode 100644 connectivity/source/drivers/macab/macaborder.hxx create mode 100644 connectivity/source/drivers/macab/macabutilities.hxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.hxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/MNSFolders.cxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/MNSFolders.hxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/MNSINIParser.cxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/MNSINIParser.hxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.cxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.hxx create mode 100644 connectivity/source/drivers/mozab/bootstrap/README create mode 100644 connectivity/source/drivers/mozab/bootstrap/mozbootstrap.component create mode 100644 connectivity/source/drivers/mysql_jdbc/YCatalog.cxx create mode 100644 connectivity/source/drivers/mysql_jdbc/YColumns.cxx create mode 100644 connectivity/source/drivers/mysql_jdbc/YDriver.cxx create mode 100644 connectivity/source/drivers/mysql_jdbc/YTable.cxx create mode 100644 connectivity/source/drivers/mysql_jdbc/YTables.cxx create mode 100644 connectivity/source/drivers/mysql_jdbc/YUser.cxx create mode 100644 connectivity/source/drivers/mysql_jdbc/YUsers.cxx create mode 100644 connectivity/source/drivers/mysql_jdbc/YViews.cxx create mode 100644 connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component create mode 100644 connectivity/source/drivers/mysqlc/mysqlc.component create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_catalog.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_catalog.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_column.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_column.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_columns.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_columns.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_connection.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_connection.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_driver.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_driver.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_general.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_general.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_indexes.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_indexes.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_keys.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_keys.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_services.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_statement.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_statement.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_table.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_table.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_tables.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_tables.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_types.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_types.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_user.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_user.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_view.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_view.hxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_views.cxx create mode 100644 connectivity/source/drivers/mysqlc/mysqlc_views.hxx create mode 100644 connectivity/source/drivers/odbc/OConnection.cxx create mode 100644 connectivity/source/drivers/odbc/ODatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx create mode 100644 connectivity/source/drivers/odbc/ODriver.cxx create mode 100644 connectivity/source/drivers/odbc/OFunctions.cxx create mode 100644 connectivity/source/drivers/odbc/OPreparedStatement.cxx create mode 100644 connectivity/source/drivers/odbc/ORealDriver.cxx create mode 100644 connectivity/source/drivers/odbc/OResultSet.cxx create mode 100644 connectivity/source/drivers/odbc/OResultSetMetaData.cxx create mode 100644 connectivity/source/drivers/odbc/OStatement.cxx create mode 100644 connectivity/source/drivers/odbc/OTools.cxx create mode 100644 connectivity/source/drivers/odbc/odbc.component create mode 100644 connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component create mode 100644 connectivity/source/drivers/postgresql/postgresql-sdbc.component create mode 100644 connectivity/source/drivers/postgresql/pq_array.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_array.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_baseresultset.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_baseresultset.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_connection.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_connection.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_databasemetadata.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_databasemetadata.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_driver.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_driver.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_preparedstatement.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_preparedstatement.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_resultset.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_resultset.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_statement.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_statement.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_statics.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_statics.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_tools.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_tools.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_updateableresultset.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_updateableresultset.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xbase.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xbase.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xcolumn.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xcolumn.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xcolumns.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xcolumns.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xcontainer.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xcontainer.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xindex.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xindex.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xindexes.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xindexes.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xkey.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xkey.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xkeys.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xkeys.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xtable.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xtable.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xtables.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xtables.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xuser.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xuser.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xusers.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xusers.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xview.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xview.hxx create mode 100644 connectivity/source/drivers/postgresql/pq_xviews.cxx create mode 100644 connectivity/source/drivers/postgresql/pq_xviews.hxx create mode 100644 connectivity/source/drivers/writer/WCatalog.cxx create mode 100644 connectivity/source/drivers/writer/WConnection.cxx create mode 100644 connectivity/source/drivers/writer/WDatabaseMetaData.cxx create mode 100644 connectivity/source/drivers/writer/WDriver.cxx create mode 100644 connectivity/source/drivers/writer/WTable.cxx create mode 100644 connectivity/source/drivers/writer/WTables.cxx create mode 100644 connectivity/source/drivers/writer/writer.component (limited to 'connectivity/source/drivers') 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 +#include +#include + +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(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(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 +#include +#include +#include +#include +#include +#include +#include + + +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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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{}); +} + +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::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RELATEDCOLUMN), PROPERTY_ID_RELATEDCOLUMN, nAttrib,&m_ReferencedColumn, ::cppu::UnoType::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(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 pColumn = getFromUnoTunnel( descriptor ); + Reference< XPropertySet > xColumn; + if ( !pColumn.is() ) + { + // m_pConnection->throwGenericSQLException( STR_INVALID_COLUMN_DESCRIPTOR_ERROR,static_cast(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(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(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(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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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(&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(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(ADOS::getField(pRecordset,nPos++).get_Value().getInt32()); + if ( aInfo->eType == adWChar && aInfo->aSimpleType.aTypeName == s_sVarChar ) + aInfo->eType = adVarWChar; + aInfo->aSimpleType.nType = static_cast(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{}); +} + +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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#ifdef DELETE +#undef DELETE +#endif +#include +#include +#include +#include + +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 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::const_iterator aIter = m_aLiteralInfo.find(_nId); + if(aIter != m_aLiteralInfo.end() && (*aIter).second.fSupported) + nSize = (static_cast((*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::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::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(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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::get(), + cppu::UnoType::get(), + cppu::UnoType::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 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((*m_aValueRangeIter).second[m_aValue.getInt32()]); + else if(m_aStrValueRange.size() && (m_aStrValueRangeIter = m_aStrValueRange.find(columnIndex)) != m_aStrValueRange.end()) + return static_cast((*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((*m_aValueRangeIter).second[m_aValue.getInt32()]); + else if(m_aStrValueRange.size() && (m_aStrValueRangeIter = m_aStrValueRange.find(columnIndex)) != m_aStrValueRange.end()) + return static_cast((*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::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType::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 aMap + { + {DB_PT_UNKNOWN, ProcedureResult::UNKNOWN}, + {DB_PT_PROCEDURE, ProcedureResult::NONE}, + {DB_PT_FUNCTION, ProcedureResult::RETURN} + }; + m_aValueRange[4] = aMap; + + rtl::Reference 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 aCurrencyMapping; + m_aValueRange[11] = aCurrencyMapping; + + rtl::Reference 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 +#include +#include + +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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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(xTunnel)) + { + auto foundConnection = std::any_of(m_xConnections.begin(), m_xConnections.end(), + [&pSearchConnection](const css::uno::WeakReferenceHelper& rxConnection) { + return static_cast(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 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 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 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 +#include +#include +#include +#include +#include +#include + +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{}); +} + + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(descriptor); + if ( pGroup == nullptr ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_GROUP_DESCRIPTOR_ERROR,static_cast(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 +#include +#include +#include +#include +#include +#include + +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{}); +} + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(descriptor); + if ( pIndex == nullptr ) + m_pConnection->throwGenericSQLException( STR_INVALID_INDEX_DESCRIPTOR_ERROR,static_cast(this) ); + + ADOIndexes* pIndexes = m_aCollection; + if ( FAILED( pIndexes->Append( OLEVariant( _rForName ), OLEVariant( pIndex->getImpl() ) ) ) ) + { + ADOS::ThrowException(m_pConnection->getConnection(),static_cast(this)); + m_pConnection->throwGenericSQLException( STR_INVALID_INDEX_DESCRIPTOR_ERROR,static_cast(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 +#include +#include +#include +#include +#include + +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{}); +} + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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( descriptor ); + if ( pKey == nullptr) + m_pConnection->throwGenericSQLException( STR_INVALID_KEY_DESCRIPTOR_ERROR,static_cast(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(aKey)), + adKeyPrimary, // must be every time adKeyPrimary + vOptional)) ) + { + ADOS::ThrowException(m_pConnection->getConnection(),static_cast(this)); + // just make sure that an SQLExceptionis thrown here + m_pConnection->throwGenericSQLException( STR_INVALID_KEY_DESCRIPTOR_ERROR,static_cast(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(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 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::get(), + cppu::UnoType::get(), + cppu::UnoType::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>(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 pSet = new OResultSet(m_RecordSet,this); + pSet->construct(); + pSet->setMetaData(getMetaData()); + m_xResultSet = WeakReference(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;iget_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::comphelper; + + +#include + +#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::get(), + cppu::UnoType::get(), + cppu::UnoType::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 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(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 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 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(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(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(m_aBookmarks.size()),"Invalid Index for vector"); + if(nPos < 0 || nPos >= static_cast(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(m_aBookmarks.size()),"Invalid Index for vector"); + if(nPos < 0 || nPos >= static_cast(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(m_aBookmarks.size())) || (nPos1 >= 0 && nPos2 < static_cast(m_aBookmarks.size())),"Invalid Index for vector"); + + CompareEnum eNum; + m_pRecordSet->CompareBookmarks(m_aBookmarks[nPos1],m_aBookmarks[nPos2],&eNum); + return static_cast(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(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(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(iget_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::get(), 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType::get(), 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), + PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType::get(), PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType::get(), PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType::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 + +#include + +#include +#include +#include +#include +#include + +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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef max + +#include +#include + +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::get(), + cppu::UnoType::get(), + cppu::UnoType::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( + 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(sqlType); + if (!m_aTypeInfo.empty()) + { + std::vector::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(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(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 pSet = new OResultSet(aSet,this); + pSet->construct(); + + m_xResultSet = WeakReference(pSet); + + return pSet; +} + + +Reference< XConnection > SAL_CALL OStatement_Base::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + return static_cast>(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(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 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::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, + cppu::UnoType::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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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{}); +} + +// 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(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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( descriptor ); + if ( pTable == nullptr ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_TABLE_DESCRIPTOR_ERROR,static_cast(this) ); + + OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid"); + if(!m_aCollection.Append(pTable->getImpl())) + ADOS::ThrowException(m_pCatalog->getConnection()->getConnection(),static_cast(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(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(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 +#include +#include +#include +#include +#include +#include +#include + +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{}); +} + + +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::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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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( descriptor ); + if ( pUser == nullptr ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_USER_DESCRIPTOR_ERROR,static_cast(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 +#include +#include +#include +#include +#include +#include + +#include + + +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{}); +} + + +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(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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( descriptor ); + if ( pView == nullptr ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_VIEW_DESCRIPTOR_ERROR,static_cast(this) ); + + WpADOCommand aCommand; + aCommand.Create(); + if ( !aCommand.IsValid() ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_VIEW_NO_COMMAND_ERROR,static_cast(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(this)); + + OTables* pTables = static_cast(static_cast(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(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(&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(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(&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(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(n / 4294967296.0); + cyVal.Lo = static_cast(n - (static_cast(cyVal.Hi) * 4294967296.0)); + } + else { + cyVal.Hi = static_cast(-n / 4294967296.0); + cyVal.Lo = static_cast(-n - (static_cast(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(reinterpret_cast(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(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::get()); + break; + case VT_I4: + aValue.setValue( & lVal, cppu::UnoType::get()); + break; + case VT_R4: + aValue.setValue( & fltVal, cppu::UnoType::get()); + break; + case VT_R8: + aValue.setValue(& dblVal, cppu::UnoType::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::get()); + break; + } + case VT_BOOL: + { + aValue <<= (boolVal == VARIANT_TRUE); + break; + } + case VT_I1: + aValue.setValue( & cVal, cppu::UnoType::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::get()); + break; + case VT_UI4: + aValue.setValue( & ulVal, cppu::UnoType::get()); + break; + case VT_INT: + aValue.setValue( & intVal, cppu::UnoType::get()); + break; + case VT_UINT: + aValue.setValue( & uintVal, cppu::UnoType::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 +#include +#include +#include +#include +#include +#include + +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(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 pInterface2; + if (!FAILED(pInterface2.CoGetClassObject(ADOS::CLSID_ADOCOMMAND_21, CLSCTX_INPROC_SERVER))) + { + sal::systools::COMReference pCommand; + + HRESULT hr = pInterface2->CreateInstanceLic(nullptr, + nullptr, + ADOS::IID_ADOCOMMAND_21, + ADOS::GetKeyStr(), + reinterpret_cast(&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 pInterface2; + if (!FAILED(pInterface2.CoGetClassObject(ADOS::CLSID_ADORECORDSET_21, CLSCTX_INPROC_SERVER))) + { + sal::systools::COMReference pRec; + HRESULT hr = pInterface2->CreateInstanceLic(nullptr, + nullptr, + ADOS::IID_ADORECORDSET_21, + ADOS::GetKeyStr(), + reinterpret_cast(&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 @@ + + + + + + + + + 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 +#include +#include +#include +#include +#include +#include +#include + + +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 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 +#include +#include +#include +#include + +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 aVector; + Sequence aTypes; + OCalcConnection::ODocHolder aDocHolder(static_cast(m_pConnection)); + Reference xResult = m_xMetaData->getTables(Any(), "%", "%", aTypes); + + if (xResult.is()) + { + Reference 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& xSheets, const OUString& rName ) +{ + Any aAny = xSheets->getByName( rName ); + Reference xSheet; + if ( !(aAny >>= xSheet) ) + return false; + + // test if sheet is hidden + + Reference 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 xCursor = xSheet->createCursor(); + Reference 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 = xCursor->getCellByPosition( 0, 0 ); + if ( xCell.is() && xCell->getType() == CellContentType_EMPTY ) + return true; + } + } + + return false; +} + +static bool lcl_IsUnnamed( const Reference& xRanges, const OUString& rName ) +{ + bool bUnnamed = false; + + Any aAny = xRanges->getByName( rName ); + Reference xRange; + if ( aAny >>= xRange ) + { + Reference 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 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(m_pConnection)); + const Reference& xDoc = aDocHolder.getDoc(); + if ( !xDoc.is() ) + throw SQLException(); + Reference 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 xDocProp( xDoc, UNO_QUERY ); + if ( xDocProp.is() ) + { + Any aRangesAny = xDocProp->getPropertyValue("DatabaseRanges"); + Reference xRanges; + if ( aRangesAny >>= xRanges ) + { + Sequence< OUString > aDBNames = xRanges->getElementNames(); + sal_Int32 nDBCount = aDBNames.getLength(); + for (sal_Int32 nRange=0; nRangesetRows(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 +#include +#include +#include +#include +#include + +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 const&) +{ + rtl::Reference ret; + try { + ret = new ODriver(context); + } catch (...) { + } + if (ret) + ret->acquire(); + return static_cast(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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& xUsedRange, sal_Int32& rEndCol, sal_Int32& rEndRow ) +{ + // update rEndCol, rEndRow if any non-empty cell in xUsedRange is right/below + + const Reference xUsedQuery( xUsedRange, UNO_QUERY ); + if ( !xUsedQuery.is() ) + return; + + const sal_Int16 nContentFlags = + CellFlags::STRING | CellFlags::VALUE | CellFlags::DATETIME | CellFlags::FORMULA | CellFlags::ANNOTATION; + + const Reference xUsedRanges = xUsedQuery->queryContentCells( nContentFlags ); + const Sequence aAddresses = xUsedRanges->getRangeAddresses(); + + const sal_Int32 nCount = aAddresses.getLength(); + const CellRangeAddress* pData = aAddresses.getConstArray(); + for ( sal_Int32 i=0; i& xSheet, sal_Int32& rColumnCount, sal_Int32& rRowCount ) +{ + Reference xCursor = xSheet->createCursor(); + Reference 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 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 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 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 ) +{ + CellContentType eCellType = xCell->getType(); + if ( eCellType == CellContentType_FORMULA ) + { + Reference 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 lcl_GetUsedCell( const Reference& xSheet, sal_Int32 nDocColumn, sal_Int32 nDocRow ) +{ + Reference xCell = xSheet->getCellByPosition( nDocColumn, nDocRow ); + if ( xCell.is() && xCell->getType() == CellContentType_EMPTY ) + { + // get first non-empty cell + + Reference xAddr( xSheet, UNO_QUERY ); + if (xAddr.is()) + { + CellRangeAddress aTotalRange = xAddr->getRangeAddress(); + sal_Int32 nLastRow = aTotalRange.EndRow; + Reference xQuery( xSheet->getCellRangeByPosition( nDocColumn, nDocRow, nDocColumn, nLastRow ), UNO_QUERY ); + if (xQuery.is()) + { + // queryIntersection to get a ranges object + Reference xRanges = xQuery->queryIntersection( aTotalRange ); + if (xRanges.is()) + { + Reference xCells = xRanges->getCells(); + if (xCells.is()) + { + Reference 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& xSheet, sal_Int32 nDocColumn, sal_Int32 nDocRow ) +{ + // look for any text cell or text result in the column + + Reference xAddr( xSheet, UNO_QUERY ); + if (!xAddr) + return false; + CellRangeAddress aTotalRange = xAddr->getRangeAddress(); + sal_Int32 nLastRow = aTotalRange.EndRow; + Reference xQuery( xSheet->getCellRangeByPosition( nDocColumn, nDocRow, nDocColumn, nLastRow ), UNO_QUERY ); + if (!xQuery) + return false; + + // are there text cells in the column? + Reference xTextContent = xQuery->queryContentCells( CellFlags::STRING ); + if ( xTextContent.is() && xTextContent->hasElements() ) + return true; + + // are there formulas with text results in the column? + Reference xTextFormula = xQuery->queryFormulaCells( FormulaResult::STRING ); + if ( xTextFormula.is() && xTextFormula->hasElements() ) + return true; + + return false; +} + +static void lcl_GetColumnInfo( const Reference& xSheet, const Reference& 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 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 xDataCell = lcl_GetUsedCell( xSheet, nDocColumn, nDataRow ); + + Reference 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 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& 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 = 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( 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(rtl::math::round( fTime * static_cast(::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( nIntTime % ::tools::Time::nanoSecPerSec ); + nIntTime /= ::tools::Time::nanoSecPerSec; + aTime.Seconds = static_cast( nIntTime % 60 ); + nIntTime /= 60; + aTime.Minutes = static_cast( nIntTime % 60 ); + nIntTime /= 60; + OSL_ENSURE( nIntTime < 24, "error in time calculation" ); + aTime.Hours = static_cast(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(fDays); + sal_Int64 nIntTime = ::rtl::math::round( fTime * static_cast(::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( nIntTime % ::tools::Time::nanoSecPerSec ); + nIntTime /= ::tools::Time::nanoSecPerSec; + aDateTime.Seconds = static_cast( nIntTime % 60 ); + nIntTime /= 60; + aDateTime.Minutes = static_cast( nIntTime % 60 ); + nIntTime /= 60; + OSL_ENSURE( nIntTime < 24, "error in time calculation" ); + aDateTime.Hours = static_cast(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( 'A' + nColumn ) ); + else + { + OUStringBuffer aBuffer(2); + aBuffer.setLength( 2 ); + aBuffer[0] = static_cast( 'A' + ( nColumn / 26 ) - 1 ); + aBuffer[1] = static_cast( '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 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 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 xDocProp( xDoc, UNO_QUERY ); + if ( xDocProp.is() ) + { + Reference xRanges(xDocProp->getPropertyValue("DatabaseRanges"),UNO_QUERY); + + if ( xRanges.is() && xRanges->hasByName( m_Name ) ) + { + Reference xDBRange(xRanges->getByName( m_Name ),UNO_QUERY); + Reference xRefer( xDBRange, UNO_QUERY ); + if ( xRefer.is() ) + { + // Header flag is always stored with database range + // Get flag from FilterDescriptor + + bool bRangeHeader = true; + Reference xFiltProp( xDBRange->getFilterDescriptor(), UNO_QUERY ); + if ( xFiltProp.is() ) + xFiltProp->getPropertyValue("ContainsHeader") >>= bRangeHeader; + + Reference xSheetRange( xRefer->getReferredCells(), UNO_QUERY ); + Reference 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 xSupp( xDoc, UNO_QUERY ); + if (xSupp.is()) + m_xFormats = xSupp->getNumberFormats(); + + Reference 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{}); +} + +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 + +#include +#include +#include +#include +#include + +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 pTable = new OCalcTable(this, static_cast(static_cast(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 @@ + + + + + + + + + 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 +#include + +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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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 +#include + +using namespace connectivity::component; +using namespace connectivity::file; +using namespace com::sun::star::uno; + +rtl::Reference 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 +#include +#include +#include +#include +#include +#include + +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::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 +#include + +using namespace connectivity::component; +using namespace connectivity::file; +using namespace com::sun::star::uno; + +rtl::Reference 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 +#include +#include + +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 aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!( *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get())) + aOwnTypes.push_back(*pBegin); + } + aOwnTypes.push_back(cppu::UnoType::get()); + + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +Any SAL_CALL OComponentTable::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::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(m_nFilePos + nOffset); + break; + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::BOOKMARK: + m_nFilePos = static_cast(nOffset); + break; + } + + if (m_nFilePos > static_cast(nNumberOfRecords)) + m_nFilePos = static_cast(nNumberOfRecords) + 1; + + if (m_nFilePos == 0 || m_nFilePos == static_cast(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 +#include +#include +#include +#include + +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 aVector; + Sequence aTypes; + Reference xResult = m_xMetaData->getTables(Any(), "%", "%", aTypes); + + if (xResult.is()) + { + Reference 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 +#include +#include + +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(m_pTable); + + const ::rtl::Reference& 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 +#include +#include +#include +#include +#include +#include + +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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(xIndex); + if(pIndex) + { + aRow[11] = new ORowSetValueDecorator(static_cast(pIndex->getHeader().db_maxkeys)); + aRow[12] = new ORowSetValueDecorator(static_cast(pIndex->getHeader().db_pagecount)); + } + + Reference 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 +#include +#include +#include +#include + +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 const&) +{ + rtl::Reference ret; + try { + ret = new ODriver(context); + } catch (...) { + } + if (ret) + ret->acquire(); + return static_cast(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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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{}); +} + +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 ODbaseIndex::createIterator() +{ + openIndexFile(); + return std::make_unique(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 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 xStmt; + utl::SharedUNOComponent 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 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(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(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(xSet,UNO_QUERY); + + if(xSet->last()) + { + Reference< XUnoTunnel> xTunnel(xSet, UNO_QUERY_THROW); + ODbaseResultSet* pDbaseRes = comphelper::getFromUnoTunnel(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 +#include +#include +#include + +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& 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 +#include + +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(m_pOperator) != nullptr) + nRes = GetNotNull(bFirst); + else if (dynamic_cast(m_pOperator) != nullptr) + nRes = GetNull(bFirst); + else if (dynamic_cast(m_pOperator) != nullptr) + nRes = GetLike(bFirst); + else if (dynamic_cast(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(*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 +#include +#include +#include +#include +#include + +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 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 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 xTunnel(descriptor,UNO_QUERY); + if(xTunnel.is()) + { + ODbaseIndex* pIndex = comphelper::getFromUnoTunnel(xTunnel); + if(!pIndex) + throw SQLException(); + pIndex->CreateImpl(); + } + + return createObject( _rForName ); +} + +// XDrop +void ODbaseIndexes::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/) +{ + auto pIndex = comphelper::getFromUnoTunnel(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 +#include + +using namespace connectivity::dbase; +using namespace connectivity::file; +using namespace com::sun::star::uno; + +rtl::Reference 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::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(_xIndex); + if(pIndex) + { + std::unique_ptr 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 +#include + +using namespace connectivity::dbase; +using namespace connectivity::file; +using namespace com::sun::star::uno; + + +rtl::Reference 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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((365.25 * iy0) - 0.75) + + static_cast(i18nutil::monthDaysWithoutJanFeb * (im0 + 1) ) + + aDateTime.Day + 1720994; + } // if ( rDateTime.Year <= 0 ) + else + { + _nJulianDate = static_cast(365.25 * iy0) + + static_cast(i18nutil::monthDaysWithoutJanFeb * (im0 + 1)) + + aDateTime.Day + 1720994; + } + double JD = _nJulianDate + 0.5; + _nJulianDate = static_cast( 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( (static_cast(_nJulianDate) - 1867216.25 ) / 36524.25 ); + ka = ka + 1 + ialp - ( ialp >> 2 ); + } + sal_Int64 kb = ka + 1524; + sal_Int64 kc = static_cast((static_cast(kb) - 122.1) / 365.25); + sal_Int64 kd = static_cast(static_cast(kc) * 365.25); + sal_Int64 ke = static_cast(static_cast(kb - kd) / i18nutil::monthDaysWithoutJanFeb); + _rDateTime.Day = static_cast(kb - kd - static_cast( static_cast(ke) * i18nutil::monthDaysWithoutJanFeb )); + if ( ke > 13 ) + _rDateTime.Month = static_cast(ke - 13); + else + _rDateTime.Month = static_cast(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(kc - 4716); + else if ( _rDateTime.Month > 2 ) + _rDateTime.Year = static_cast(kc - 4716); + else + _rDateTime.Year = static_cast(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(d_h); + _rDateTime.Minutes = static_cast((d_h - static_cast(_rDateTime.Hours)) * 60.0); + _rDateTime.Seconds = static_cast(((d_m - static_cast(_rDateTime.Minutes)) * 60.0) + - (static_cast(_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(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(aDBFColumn.db_fnm), strlen(reinterpret_cast(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(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(sHeader[0]) != 0xFF || static_cast(sHeader[1]) != 0xFF || static_cast(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(), 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 aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(*pBegin != cppu::UnoType::get() && + *pBegin != cppu::UnoType::get()) + { + aOwnTypes.push_back(*pBegin); + } + } + aOwnTypes.push_back(cppu::UnoType::get()); + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +Any SAL_CALL ODbaseTable::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType::get()|| + rType == cppu::UnoType::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{}); +} + +bool ODbaseTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns & _rCols, bool bRetrieveData) +{ + if (!m_pBuffer) + return false; + + // Read the data + bool bIsCurRecordDeleted = static_cast(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(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(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(m_aScales[i-1]))); + else + d = static_cast(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(o3tl::toInt32(aStr.subView( 0, 4 ))); + const sal_uInt16 nMonth = static_cast(o3tl::toInt32(aStr.subView( 4, 2 ))); + const sal_uInt16 nDay = static_cast(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(), comphelper::getProcessComponentContext()); + if (aContent.isDocument()) + { + // Only if the file exists with length > 0 raise an error + std::unique_ptr 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(), 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(), 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(), 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(), 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 xColumns(getColumns(),UNO_QUERY); + Reference xCol; + const OUString sPropType = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE); + + try + { + const sal_Int32 nCount = xColumns->getCount(); + for(sal_Int32 i=0;igetByIndex(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;igetByIndex(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(nPrecision), 255U) ); // field length + nRecLength = nRecLength + static_cast(std::min(static_cast(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(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& _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(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& _xCols) +{ + // fill buffer with blanks + if (!AllocBuffer()) + return false; + + // position on desired record: + std::size_t nPos = m_aHeader.headerLength + static_cast(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(m_nFilePos-1) * m_aHeader.recordLength; + m_pFileStream->Seek(nFilePos); + + OValueRefRow aRow = new OValueRefVector(_rCols.size()); + + if (!fetchRow(aRow,_rCols,true)) + return false; + + Reference xCol; + OUString aColName; + ::comphelper::UStringMixEqual aCase(isCaseSensitive()); + for (sal_Int32 i = 0; i < m_xColumns->getCount(); i++) + { + Reference 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 xTunnel(xIndex,UNO_QUERY); + OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!"); + ODbaseIndex* pIndex = comphelper::getFromUnoTunnel(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(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 ODbaseTable::isUniqueByColumnName(sal_Int32 _nColumnPos) +{ + if(!m_xIndexes) + refreshIndexes(); + if(m_xIndexes->hasElements()) + { + Reference 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 xIndex; + for(sal_Int32 i=0;igetCount();++i) + { + xIndex.set(m_xIndexes->getByIndex(i), css::uno::UNO_QUERY); + if(xIndex.is() && getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE)))) + { + Reference xCols(Reference(xIndex,UNO_QUERY_THROW)->getColumns()); + if(xCols->hasByName(sColName)) + return xIndex; + + } + } + } + return Reference(); +} + +static double toDouble(std::string_view rString) +{ + return ::rtl::math::stringToDouble( rString, '.', ',' ); +} + + +bool ODbaseTable::UpdateBuffer(OValueRefVector& rRow, const OValueRefRow& pOrgRow, const Reference& _xCols, const bool bForceAllFields) +{ + OSL_ENSURE(m_pBuffer,"Buffer is NULL!"); + if ( !m_pBuffer ) + return false; + sal_Int32 nByteOffset = 1; + + // Update fields: + Reference xCol; + Reference xIndex; + OUString aColName; + const sal_Int32 nColumnCount = m_xColumns->getCount(); + std::vector< Reference > aIndexedCols(nColumnCount); + + ::comphelper::UStringMixEqual aCase(isCaseSensitive()); + + Reference 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 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 xTunnel(xIndex,UNO_QUERY); + OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!"); + ODbaseIndex* pIndex = comphelper::getFromUnoTunnel(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 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 xTunnel(aIndexedCols[i],UNO_QUERY); + OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!"); + ODbaseIndex* pIndex = comphelper::getFromUnoTunnel(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(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(aDate.Year), + static_cast(aDate.Month), + static_cast(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(d * pow(10.0,static_cast(m_aScales[i]))); + else + nValue = static_cast(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 > 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 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(sHeader[0]) * 256 + + static_cast(sHeader[1])) * 256 + + static_cast(sHeader[2])) * 256 + + static_cast(sHeader[3]); + else + nOldSize = ((static_cast(sHeader[3]) * 256 + + static_cast(sHeader[2])) * 256 + + static_cast(sHeader[1])) * 256 + + static_cast(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(nWriteSize % 256); + } + else + { + (*m_pMemoStream).WriteUChar( 0x00 ); + nWriteSize += 8; + for (int i = 0; i < 4; nWriteSize >>= 8) + nHeader[i++] = static_cast(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 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 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 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 pNewTable = new ODbaseTable(m_pTables,static_cast(m_pConnection)); + Reference xHoldTable = pNewTable; + pNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),Any(sTempName)); + Reference 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 xProp; + m_xColumns->getByIndex(i) >>= xProp; + Reference xColumn(xProp,UNO_QUERY); + Reference 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 xProp; + m_xColumns->getByIndex(i) >>= xProp; + Reference xColumn(xProp,UNO_QUERY); + Reference 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(), 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(m_pConnection))); + xNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),Any(sTempName)); + { + Reference xAppend(xNewTable->getColumns(),UNO_QUERY); + bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(); + // copy the structure + for(sal_Int32 i=0;i < m_xColumns->getCount();++i) + { + Reference xProp; + m_xColumns->getByIndex(i) >>= xProp; + Reference xColumn(xProp,UNO_QUERY); + Reference xCpy; + if(xColumn.is()) + xCpy = xColumn->createDataDescriptor(); + else + { + xCpy = new OColumn(bCase); + ::comphelper::copyProperties(xProp,xCpy); + } + + xAppend->appendByDescriptor(xCpy); + } + Reference 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(m_pConnection))); + xNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),Any(sTempName)); + { + Reference 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 xProp; + m_xColumns->getByIndex(i) >>= xProp; + Reference xColumn(xProp,UNO_QUERY); + Reference 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(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(m_nFilePos + nOffset); + break; + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::BOOKMARK: + m_nFilePos = static_cast(nOffset); + break; + } + + if (m_nFilePos > static_cast(nNumberOfRecords)) + m_nFilePos = static_cast(nNumberOfRecords) + 1; + + if (m_nFilePos == 0 || m_nFilePos == static_cast(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(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(sHeader[0]) != 0xFF || static_cast(sHeader[1]) != 0xFF || static_cast(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(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(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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 pRet = new ODbaseTable(this, static_cast(static_cast(m_rParent).getConnection()), + _rName,"TABLE"); + + pRet->construct(); + return pRet; +} + +void ODbaseTables::impl_refresh( ) +{ + static_cast(&m_rParent)->refreshTables(); +} + +Reference< XPropertySet > ODbaseTables::createDescriptor() +{ + return new ODbaseTable(this, static_cast(static_cast(m_rParent).getConnection())); +} + +// XAppend +sdbcx::ObjectType ODbaseTables::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + auto pTable = comphelper::getFromUnoTunnel(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(m_rParent).getConnection(),_sElementName),false,nullptr)) + return; + } + + if ( xTunnel.is() ) + { + ODbaseTable* pTable = comphelper::getFromUnoTunnel(xTunnel); + if(pTable) + pTable->DropImpl(); + } + else + { + const OUString sError( static_cast(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 @@ + + + + + + + + + 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 +#include +#include +#include +#include +#include + +#include +#include + + +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(nMaxCount-1), static_cast(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 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(&pBuf[0]), aText.getStr(), + std::min(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 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 +#include +#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(&eds_check_version) }, + { "e_contact_field_name", reinterpret_cast(&e_contact_field_name) }, + { "e_contact_get", reinterpret_cast(&e_contact_get) }, + { "e_contact_get_type", reinterpret_cast(&e_contact_get_type) }, + { "e_contact_field_id", reinterpret_cast(&e_contact_field_id) }, + { "e_book_new", reinterpret_cast(&e_book_new) }, + { "e_book_open", reinterpret_cast(&e_book_open) }, + { "e_book_get_source", reinterpret_cast(&e_book_get_source) }, + { "e_book_get_contacts", reinterpret_cast(&e_book_get_contacts) }, + { "e_book_query_field_test", reinterpret_cast(&e_book_query_field_test) }, + { "e_book_query_and", reinterpret_cast(&e_book_query_and) }, + { "e_book_query_or", reinterpret_cast(&e_book_query_or) }, + { "e_book_query_not", reinterpret_cast(&e_book_query_not) }, + { "e_book_query_ref", reinterpret_cast(&e_book_query_ref) }, + { "e_book_query_unref", reinterpret_cast(&e_book_query_unref) }, + { "e_book_query_from_string", reinterpret_cast(&e_book_query_from_string) }, + { "e_book_query_to_string", reinterpret_cast(&e_book_query_to_string) }, + { "e_book_query_field_exists", reinterpret_cast(&e_book_query_field_exists) } +}; + +const ApiMap aNewApiMap[] = +{ + { "e_source_registry_list_sources", reinterpret_cast(&e_source_registry_list_sources) }, + { "e_source_registry_new_sync", reinterpret_cast(&e_source_registry_new_sync) }, + { "e_source_has_extension", reinterpret_cast(&e_source_has_extension) }, + { "e_source_get_extension", reinterpret_cast(&e_source_get_extension) }, + { "e_source_backend_get_backend_name", reinterpret_cast(&e_source_backend_get_backend_name) }, + { "e_source_get_display_name", reinterpret_cast(&e_source_get_display_name) }, + { "e_source_get_uid", reinterpret_cast(&e_source_get_uid) }, + { "e_source_registry_ref_source", reinterpret_cast(&e_source_registry_ref_source) }, + { "e_client_open_sync", reinterpret_cast(&e_client_open_sync) }, + { "e_client_get_source", reinterpret_cast(&e_client_get_source) }, + { "e_book_client_get_contacts_sync", reinterpret_cast(&e_book_client_get_contacts_sync) }, + { "e_client_util_free_object_slist", reinterpret_cast(&e_client_util_free_object_slist) } +}; + +//>= direct read access API (>= 3.8) +const ApiMap aClientApiMap38[] = +{ + { "e_book_client_connect_direct_sync", reinterpret_cast(&e_book_client_connect_direct_sync) } +}; + +template 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( + 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 + +// 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 +#include + + +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 + +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 +#include + +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 + +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 +#include "NPreparedStatement.hxx" +#include "NStatement.hxx" +#include +#include +#include +#include + +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 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 +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#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(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(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 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(nFields); i++) + { + if( match( columnNamePattern, getFieldName( i ), '\0' ) ) + { + aRow[5] = new ORowSetValueDecorator( static_cast( 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 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 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(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 + +#include + +#include "NConnection.hxx" +#include +#include + + +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 +#include +#include +#include +#include +#include +#include + +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 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 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 + +#include + +#include +#include +#include +#include + +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 +#include +#include +#include + +#include + +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 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 +#include +#include +#include +#include +#include + +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 +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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(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(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(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(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(G_PARAM_SPEC_VALUE_TYPE(pSpec)) << ") (0x" + << std::hex << static_cast(nType) << ") " << (pSpec->name ? pSpec->name : "")); + return false; + } + + g_value_init( pStackValue, nType ); + if ( bIsSplittedColumn ) + { + const SplitEvoColumns* evo_addr( get_evo_addr() ); + for (int i=0;i( _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(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(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(); + + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + PropertyAttribute::READONLY, + &m_nFetchSize, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + PropertyAttribute::READONLY, + &m_nResultSetType, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + PropertyAttribute::READONLY, + &m_nFetchDirection, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + PropertyAttribute::READONLY, + &m_nResultSetConcurrency, + cppu::UnoType::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(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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + { + private: + std::unique_ptr m_pVersionHelper; + + OCommonStatement* m_pStatement; + OEvoabConnection* m_pConnection; + rtl::Reference m_xMetaData; + ::dbtools::WarningsContainer m_aWarnings; + + bool m_bWasNull; + // + sal_Int32 m_nFetchSize; + sal_Int32 m_nResultSetType; + sal_Int32 m_nFetchDirection; + sal_Int32 m_nResultSetConcurrency; + // + + // 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 +#include + +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 &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 +#include +#include "NConnection.hxx" +#include +#include + +namespace connectivity::evoab +{ + + //************ Class: ResultSetMetaData + + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE; + + class OEvoabResultSetMetaData : public OResultSetMetaData_BASE + { + OUString m_aTableName; + std::vector m_aEvoabFields; + + protected: + virtual ~OEvoabResultSetMetaData() override; + public: + explicit OEvoabResultSetMetaData(const OUString& _aTableName); + /// @throws css::sdbc::SQLException + void setEvoabFields(const ::rtl::Reference &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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "NStatement.hxx" +#include "NConnection.hxx" +#include "NDatabaseMetaData.hxx" +#include "NResultSet.hxx" +#include +#include +#include +#include + +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::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, + 0, + &m_nMaxFieldSize, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, + 0, + &m_nMaxRows, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, + 0, + &m_nQueryTimeOut, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + 0, + &m_nFetchSize, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + 0, + &m_nResultSetType, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + 0, + &m_nFetchDirection, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, + 0, + &m_bEscapeProcessing, + cppu::UnoType::get() + ); + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + 0, + &m_nResultSetConcurrency, + cppu::UnoType::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::get(), + cppu::UnoType::get(), + cppu::UnoType::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; icount(); ++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( "" ); + 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 pResult = new OEvoabResultSet( this, m_xConnection.get() ); + pResult->construct( _rQueryData ); + + // done + m_xResultSet = Reference(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "EApi.h" +#include "NConnection.hxx" + +#include + +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 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 m_xConnection; + connectivity::OSQLParser m_aParser; + connectivity::OSQLParseTreeIterator m_aSQLIterator; + connectivity::OSQLParseNode *m_pParseTree; + + // + 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: + + 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 + +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 + +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 +#include +#include "NCatalog.hxx" +#include +#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(m_rParent).getConnection(), + aName, + xRow->getString(4), + xRow->getString(5), + "", + ""); + } + } + + ::comphelper::disposeComponent(xResult); + + return xRet; +} + +void OEvoabTables::impl_refresh( ) +{ + static_cast(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 +#include + +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 @@ + + + + + + + + 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 +#include +#include +#include +#include + +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::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::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 aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!(*pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::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 +#include +#include +#include +#include + +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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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 xParent(Reference(aFile.get(),UNO_QUERY_THROW)->getParent(),UNO_QUERY_THROW); + Reference 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 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 xContent; + Sequence< OUString > aProps { "Title" }; + try + { + Reference 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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 = xDynamicResultSet->getStaticResultSet(); + + Reference 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 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(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 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 +#include +#include +#include +#include + +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(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(aDate.GetDayOfYear()); +} + +ORowSetValue OOp_Month::operate(const ORowSetValue& lhs) const +{ + if (lhs.isNull()) + return lhs; + + css::util::Date aD = lhs.getDate(); + return static_cast(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& 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(aDate.GetWeekOfYear(static_cast(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(aT.Hours); +} + +ORowSetValue OOp_Minute::operate(const ORowSetValue& lhs) const +{ + if (lhs.isNull()) + return lhs; + + css::util::Time aT = lhs.getTime(); + return static_cast(aT.Minutes); +} + +ORowSetValue OOp_Second::operate(const ORowSetValue& lhs) const +{ + if (lhs.isNull()) + return lhs; + + css::util::Time aT = lhs.getTime(); + return static_cast(aT.Seconds); +} + +ORowSetValue OOp_CurDate::operate(const std::vector& lhs) const +{ + if (!lhs.empty()) + return ORowSetValue(); + + Date aCurDate(Date::SYSTEM); + return aCurDate.GetUNODate(); +} + +ORowSetValue OOp_CurTime::operate(const std::vector& lhs) const +{ + if (!lhs.empty()) + return ORowSetValue(); + + tools::Time aCurTime(tools::Time::SYSTEM); + return aCurTime.GetUNOTime(); +} + +ORowSetValue OOp_Now::operate(const std::vector& 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +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 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(connection)) + { + for (auto const& elem : m_xConnections) + { + if (static_cast( 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 +#include +#include +#include +#include +#include +#include +#include + +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(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 OResultSet::GetOrderbyKeyValue(OValueRefRow const & _rRow) +{ + sal_uInt32 nBookmarkValue = std::abs((*_rRow)[0]->getValue().getInt32()); + + std::unique_ptr pKeyValue = OKeyValue::createKeyValue(nBookmarkValue); + + for (auto const& elem : m_aOrderbyColumnNumber) + { + OSL_ENSURE(elem < static_cast(_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 +#include +#include +#include + +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& 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& 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& /*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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 OPreparedStatement::makeResultSet() +{ + closeResultSet(); + + rtl::Reference xResultSet(createResultSet()); + m_xResultSet = uno::Reference(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::get(), + cppu::UnoType::get(), + cppu::UnoType::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 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 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(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 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 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(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& _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 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 xProp; + if(SQL_ISRULE(_pNode,column_ref)) + { + OUString sColumnName,sTableRange; + m_aSQLIterator.getColumnRange(_pNode,sColumnName,sTableRange); + if ( !sColumnName.isEmpty() ) + { + Reference 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY,&m_nResultSetType, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, 0,&m_nFetchDirection, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY,PropertyAttribute::READONLY,&m_nResultSetConcurrency, ::cppu::UnoType::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::get(), + cppu::UnoType::get(), + cppu::UnoType::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(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 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 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(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(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(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 xIndexSup; + m_pTable->queryInterface(cppu::UnoType::get()) >>= xIndexSup; + + Reference xIndexes; + if(xIndexSup.is()) + { + xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY); + Reference 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 xIndex(xIndexes->getByIndex(i),UNO_QUERY); + Reference 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(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 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(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& _rxColumns, + const Reference& _xNames, + bool _bSetColumnMapping, + const Reference& _xMetaData, + std::vector& _rColMapping) +{ + ::comphelper::UStringMixEqual aCase(_xMetaData->supportsMixedCaseQuotedIdentifiers()); + + Reference 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 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(_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 xTunnel(_xTable, UNO_QUERY_THROW); + m_pTable = comphelper::getFromUnoTunnel(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 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 +#include +#include +#include +#include +#include + + +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& _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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), PROPERTY_ID_MAXFIELDSIZE, nAttrib,&m_nMaxFieldSize, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), PROPERTY_ID_MAXROWS, nAttrib,&m_nMaxRows, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), PROPERTY_ID_QUERYTIMEOUT, nAttrib,&m_nQueryTimeOut, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, nAttrib,&m_nFetchSize, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, nAttrib,&m_nResultSetType, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, nAttrib,&m_nFetchDirection, ::cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),PROPERTY_ID_ESCAPEPROCESSING, nAttrib,&m_bEscapeProcessing,cppu::UnoType::get()); + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY, nAttrib,&m_nResultSetConcurrency, ::cppu::UnoType::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::get(), + cppu::UnoType::get(), + cppu::UnoType::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 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 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 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 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 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(rTabs.begin()->second); + OSL_ENSURE(m_pTable.is(),"No table!"); + if ( m_pTable.is() ) + m_xColNames = m_pTable->getColumns(); + Reference 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 xColumns = m_aSQLIterator.getSelectColumns(); + m_aColMapping.resize(xColumns->size() + 1); + for (sal_Int32 i=0; i(m_aColMapping.size()); ++i) + m_aColMapping[i] = i; + + Reference 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(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 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(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 xCol; + m_xColNames->getByName(aColumnName) >>= xCol; + sal_Int32 nId = Reference(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 + +#include +#include + +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& lhs) const +{ + if (lhs.empty()) + return ORowSetValue(); + + OUStringBuffer sRet(static_cast(lhs.size())); + std::vector::const_reverse_iterator aIter = lhs.rbegin(); + std::vector::const_reverse_iterator aEnd = lhs.rend(); + for (; aIter != aEnd; ++aIter) + { + if (!aIter->isNull()) + { + char c = static_cast(aIter->getInt32()); + + sRet.appendAscii(&c, 1); + } + } + + return sRet.makeStringAndClear(); +} + +ORowSetValue OOp_Concat::operate(const std::vector& lhs) const +{ + if (lhs.empty()) + return ORowSetValue(); + + OUStringBuffer sRet; + std::vector::const_reverse_iterator aIter = lhs.rbegin(); + std::vector::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& 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& 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& 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& 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 +#include +#include +#include +#include +#include + +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::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::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{}); +} + +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 OFileTable::createStream_simpleError( const OUString& _rFileName, StreamMode _eOpenMode) +{ + std::unique_ptr 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 +#include + +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(m_rParent).refreshTables(); +} + +Any SAL_CALL OTables::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::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 +#include +#include +#include +#include +#include + +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 pCompiler = new OPredicateCompiler(this); + pCompiler->setOrigColumns(m_aCompiler->getOrigColumns()); + ::rtl::Reference 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; jstart(pSQLParseNode); +} + + +void OSQLAnalyzer::bindRow(OCodeList& rCodeList,const OValueRefRow& _pRow) +{ + for (auto const& code : rCodeList) + { + OOperandAttr* pAttr = dynamic_cast(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(_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& _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 +#include +#include +#include +#include +#include + +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(_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 "-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 aValues; + std::vector 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(code.get()); + if (pOperand) + m_aStack.push(pOperand); + else + static_cast(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(code.get()); + if (pOperand) + m_aStack.push(pOperand); + else + static_cast(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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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& 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(), 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(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(nDataRemaining, SAL_MAX_UINT16); + aErr = isc_get_segment(m_statusVector, + &m_blobHandle, + &nBytesRead, + nReadSize, + reinterpret_cast(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(), 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(), 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 + +#include + +#include +#include + +#include + +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& 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 + +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 xViews + = m_xMetaData->getTables(css::uno::Any(), "%", "%", { "VIEW" }); + + if (!xViews.is()) + return; + + ::std::vector 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 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 + +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 + +#include "Clob.hxx" +#include "Blob.hxx" + +#include +#include + +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 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 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(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 & /*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 + +#include +#include +#include + +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 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 + +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::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 + +namespace connectivity::firebird + { + class Column; + typedef ::comphelper::OIdPropertyArrayUsageHelper 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 + +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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +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 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& rId) +{ + return comphelper::getSomethingImpl(rId, this); +} + +// static +const css::uno::Sequence & 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(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(nAction)); + + aRequest.append(char(isc_spb_dbname)); // .fdb + sal_uInt16 nFDBLength = sFDBPath.getLength(); + aRequest.append(static_cast(nFDBLength & 0xFF)); // least significant byte first + aRequest.append(static_cast((nFDBLength >> 8) & 0xFF)); + aRequest.append(sFDBPath); + + aRequest.append(char(isc_spb_bkp_file)); // .fbk + sal_uInt16 nFBKLength = sFBKPath.getLength(); + aRequest.append(static_cast(nFBKLength & 0xFF)); + aRequest.append(static_cast((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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& rId) override; + static const css::uno::Sequence & 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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(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 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(-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(xBlob->getBytes(1, SAL_MAX_INT32).getArray()), + SAL_MAX_INT32, + RTL_TEXTENCODING_UTF8); + } + else + { + aDescription = OUString(reinterpret_cast(xBlob->getBytes(1, static_cast(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 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 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 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 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 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 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 + +#include + +#include "Connection.hxx" + +#include +#include +#include + +namespace connectivity::firebird + { + + //************ Class: ODatabaseMetaData + + + typedef ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData> ODatabaseMetaData_BASE; + + class ODatabaseMetaData : public ODatabaseMetaData_BASE + { + ::rtl::Reference 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +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 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(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 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 +#include +#include +#include +#include +#include + +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 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& 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& 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 + +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 + +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 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 + +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 +#include + +#include "Connection.hxx" +#include "PreparedStatement.hxx" +#include "ResultSet.hxx" +#include "ResultSetMetaData.hxx" +#include "Util.hxx" + +#include +#include +#include +#include +#include + +#include + +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(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(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(BlobSubtype::Clob) ); + setClob(nParameterIndex, sInput ); + break; + case SQL_SHORT: + { + sal_Int32 int32Value = sInput.toInt32(); + if ( (int32Value < std::numeric_limits::min()) || + (int32Value > std::numeric_limits::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 +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(-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(nValue), + dType); + break; + case DataType::INTEGER: + setValue< sal_Int32 >(nIndex, + static_cast(nValue), + dType); + break; + case DataType::BIGINT: + setValue< sal_Int64 >(nIndex, + static_cast(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(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(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(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(parameterIndex, + static_cast( toNumericWithoutDecimalPlace(sValue) ), + dType); + break; + case SQL_LONG: + case SQL_DOUBLE: + setValue< sal_Int32 >(parameterIndex, + static_cast( 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(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(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 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(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 + +#include +#include +#include +#include +#include + +#include + +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 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + PropertyAttribute::READONLY, + &m_nFetchSize, + cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + PropertyAttribute::READONLY, + &m_nResultSetType, + cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + PropertyAttribute::READONLY, + &m_nFetchDirection, + cppu::UnoType::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + PropertyAttribute::READONLY, + &m_nResultSetConcurrency, + cppu::UnoType::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 +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(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + sal_Int64 nDecimalCountExp = pow10Integer(nDecimalCount); + + if(nAllDigits < 0) + { + sRetBuffer.append('-'); + nAllDigits = -nAllDigits; // abs + } + + sRetBuffer.append(static_cast(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 +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(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + else + { + ORowSetValue row = retrieveValue< ORowSetValue >(nColumnIndex, 0); + if constexpr ( std::is_same_v ) + return row.getLong(); + else if constexpr ( std::is_same_v ) + return row.getInt32(); + else if constexpr ( std::is_same_v ) + return row.getInt16(); + else if constexpr ( std::is_same_v ) + return row.getFloat(); + else if constexpr ( std::is_same_v ) + return row.getDouble(); + else if constexpr ( std::is_same_v ) + 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(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(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(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(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(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(nColumnIndex); + case SQL_LONG: + return makeNumericString(nColumnIndex); + case SQL_DOUBLE: + // TODO FIXME 64 bits? + case SQL_INT64: + return makeNumericString(nColumnIndex); + default: + assert(false); + return OUString(); // never reached + } + } + else if(aSqlType == SQL_BLOB && aSqlSubType == static_cast(BlobSubtype::Clob) ) + { + uno::Reference 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(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); +} + +template +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(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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 + { + 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 OUString makeNumericString( + const sal_Int32 nColumnIndex); + + template T retrieveValue(const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + + template 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 +#include +#include +#include +#include + +#include + +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 xStmt= m_pConnection->createStatement(); + + Reference xRes = + xStmt->executeQuery(sSql); + Reference 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 xStmt =m_pConnection ->createStatement(); + + Reference xRes = + xStmt->executeQuery(sSql); + Reference 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 xStmt= m_pConnection->createStatement(); + + Reference xRes = + xStmt->executeQuery(sSql); + Reference xRow ( xRes, UNO_QUERY); + if(xRes->next()) + { + return static_cast(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 + +#include +#include + +#include + +namespace connectivity::firebird + { + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> + OResultSetMetaData_BASE; + + class OResultSetMetaData : public OResultSetMetaData_BASE + { + protected: + ::rtl::Reference 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 +#include +#include + +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 +#include + +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 +#include +#include +#include +#include +#include + +#include + +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::get(), + ::cppu::UnoType::get(), + ::cppu::UnoType::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(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(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::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, + cppu::UnoType::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(isc_vax_integer(aResultsBuffer+1, 2)); + return static_cast(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(*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(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 + +#include + +#include "Connection.hxx" +#include "SubComponent.hxx" + +#include + +#include +#include + +#include +#include +#include +#include + +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 + + { + protected: + ::osl::Mutex m_aMutex; + + css::uno::Reference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created + // for this Statement + + ::rtl::Reference 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 +#include +#include + +namespace cppu { class IPropertyArrayHelper; } +namespace com::sun::star::lang { class XComponent; } + +namespace connectivity::firebird + { + /// @throws css::lang::DisposedException + void checkDisposed(bool _bThrow); + + + template + 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. +
+ 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 + sal_Int32 OPropertyArrayUsageHelper< TYPE >::s_nRefCount = 0; + + template + ::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper< TYPE >::s_pProps = nullptr; + + template + ::osl::Mutex OPropertyArrayUsageHelper< TYPE >::s_aMutex; + + + template + OPropertyArrayUsageHelper::OPropertyArrayUsageHelper() + { + ::osl::MutexGuard aGuard(s_aMutex); + ++s_nRefCount; + } + + + template + OPropertyArrayUsageHelper::~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 + ::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper::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 + +#include +#include +#include + +#include +#include +#include + +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::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 + +#include + +#include "Tables.hxx" + +#include + +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 + +#include + +#include +#include +#include +#include + +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(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 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 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 xColumnSup(rDescriptor,UNO_QUERY); + Reference 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;igetByIndex(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(static_cast(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(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 +#include + +#include + +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 +#include + +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 +#include + +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 +#include + +#include +#include +#include + +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(&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(aSubType) == NumberSubType::Other ) + aSubType = static_cast(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(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(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(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(malloc(sizeof(char)*pVar->sqllen)); + break; + case SQL_VARYING: + pVar->sqldata = static_cast(malloc(sizeof(char)*pVar->sqllen + 2)); + break; + case SQL_SHORT: + pVar->sqldata = static_cast(malloc(sizeof(sal_Int16))); + break; + case SQL_LONG: + pVar->sqldata = static_cast(malloc(sizeof(sal_Int32))); + break; + case SQL_FLOAT: + pVar->sqldata = static_cast(malloc(sizeof(float))); + break; + case SQL_DOUBLE: + pVar->sqldata = static_cast(malloc(sizeof(double))); + break; + case SQL_D_FLOAT: + pVar->sqldata = static_cast(malloc(sizeof(double))); + break; + case SQL_TIMESTAMP: + pVar->sqldata = static_cast(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(malloc(sizeof(ISC_QUAD))); + break; + case SQL_TYPE_TIME: + pVar->sqldata = static_cast(malloc(sizeof(ISC_TIME))); + break; + case SQL_TYPE_DATE: + pVar->sqldata = static_cast(malloc(sizeof(ISC_DATE))); + break; + case SQL_INT64: + pVar->sqldata = static_cast(malloc(sizeof(sal_Int64))); + break; + case SQL_BOOLEAN: + pVar->sqldata = static_cast(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(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 + +#include + +#include + +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 + +#include + +namespace connectivity::firebird +{ +View::View(const css::uno::Reference& _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 SAL_CALL View::getTypes() +{ + return ::comphelper::concatSequences(View_Base::getTypes(), View_IBASE::getTypes()); +} + +css::uno::Sequence SAL_CALL View::getImplementationId() +{ + return css::uno::Sequence(); +} + +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 statement = m_xConnection->createStatement(); + css::uno::Reference xResult = statement->executeQuery(aCommand); + + css::uno::Reference 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 + +#include +#include + +#include +#include + +namespace connectivity::firebird +{ +typedef ::connectivity::sdbcx::OView View_Base; +typedef ::cppu::ImplHelper1 View_IBASE; + +class View : public View_Base, public View_IBASE +{ +public: + View(const css::uno::Reference& _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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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 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 +#include +#include + +connectivity::firebird::Views::Views( + const css::uno::Reference& _rxConnection, ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, const ::std::vector& _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(m_rParent).refreshViews(); +} + +css::uno::Reference 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& 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 xObject(getObject(_nPos)); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject); + if (!bIsNew) + { + OUString aSql("DROP VIEW"); + + css::uno::Reference xProp(xObject, css::uno::UNO_QUERY); + aSql += ::dbtools::composeTableName(m_xMetaData, xProp, + ::dbtools::EComposeRule::InTableDefinitions, true); + + css::uno::Reference xConnection = m_xMetaData->getConnection(); + css::uno::Reference 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& descriptor) +{ + css::uno::Reference 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 xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + connectivity::firebird::Tables* pTables = static_cast( + static_cast(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 +#include +namespace connectivity::firebird +{ +class Views final : public connectivity::sdbcx::OCollection +{ + css::uno::Reference m_xConnection; + css::uno::Reference m_xMetaData; + bool m_bInDrop; + + // OCollection + virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference createDescriptor() override; + virtual sdbcx::ObjectType + appendObject(const OUString& _rForName, + const css::uno::Reference& descriptor) override; + + void createView(const css::uno::Reference& descriptor); + +public: + Views(const css::uno::Reference& _rxConnection, + ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector& _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 @@ + + + + + + + + + + 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 + +#include +#include +#include +#include + +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 aVector; + Sequence aTypes; + Reference xResult = m_xMetaData->getTables(Any(), "%", "%", aTypes); + + if (xResult.is()) + { + Reference 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 +#include + +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(m_pTable); + const ::rtl::Reference& 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 +#include +#include +#include +#include +#include +#include +#include + +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 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 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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include + + +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 const&) +{ + rtl::Reference ret; + try { + ret = new ODriver(context); + } catch (...) { + } + if (ret) + ret->acquire(); + return static_cast(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 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 +#include + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace ::com::sun::star::uno; + +rtl::Reference 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 +#include +#include +#include +#include +#include +#include + +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::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::get()|| rType == cppu::UnoType::get() + || rType == cppu::UnoType::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 aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!(*pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::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 +#include + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace css::uno; + +rtl::Reference 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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 aColumnNames; + vector 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 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(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 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 aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!(*pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get()|| + *pBegin == cppu::UnoType::get())) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +Any SAL_CALL OFlatTable::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::get()|| + rType == cppu::UnoType::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{}); +} + +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(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(m_pFileStream->Tell()); + return true; +} + + +void OFlatTable::setRowPos(const vector::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 +#include +#include + +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 pRet = new OFlatTable(this, static_cast(static_cast(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 @@ + + + + + + + + + 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 +#include +#include +#include +#include +#include +#include +#include + + +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 xRes = m_xMetaData->getTableTypes(); + Reference 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::get()) + return Any(); + + return OCatalog::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OHCatalog::getTypes( ) +{ + Sequence< Type > aTypes = OCatalog::getTypes(); + std::vector aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if ( *pBegin != cppu::UnoType::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 +#include + + +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::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 +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "HTerminateListener.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +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 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 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; + 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 = xStorage->openStreamElement(sProperties,ElementModes::READ); + if ( xStream.is() ) + { + std::unique_ptr 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 = xStorage->openStreamElement(sScript, ElementModes::READ); + if (xStream.is()) + { + std::unique_ptr 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 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 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(xOrig); + if ( pMetaConnection ) + pMetaConnection->setURL(url); + + Reference 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 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 xBroad(xStorage,UNO_QUERY); + if ( xBroad.is() ) + { + Reference 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(_aIter->first.get(),UNO_QUERY); + + if ( _xConnection.is() ) + { + Reference xStmt = _xConnection->createStatement(); + if ( xStmt.is() ) + { + Reference xRes = xStmt->executeQuery("SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS WHERE USER_NAME ='SA'"); + Reference xRow(xRes,UNO_QUERY); + if ( xRow.is() && xRes->next() ) + bLastOne = xRow->getInt(1) == 1; + if ( bLastOne ) + xStmt->execute("SHUTDOWN"); + } + } + } + catch(Exception&) + { + } + if ( bLastOne ) + { + // Reference 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 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 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 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(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 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 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 +#include +#include +#include "accesslog.hxx" +#include +#include + +#include + +#include + +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 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 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 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 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(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 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(&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 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(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 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(BUFFER_SIZE); + diff = diff - BUFFER_SIZE; + } + else + { + n = static_cast(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 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(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 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((v >> 24) & 0xFF), + static_cast((v >> 16) & 0xFF), + static_cast((v >> 8) & 0xFF), + static_cast((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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 mapped; + map.mapInterface( + reinterpret_cast(&mapped), storage.get(), + cppu::UnoType::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(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& _xListener) + { + TStorages& rMap = lcl_getStorageMap(); + TStorages::iterator aFind = rMap.find(_sKey); + if ( aFind == rMap.end() ) + return; + + try + { + if ( _xListener.is() ) + { + Reference xBroad(aFind->second.mapStorage(),UNO_QUERY); + if ( xBroad.is() ) + xBroad->removeTransactionListener(_xListener); + Reference 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(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(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +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::get()); +} + +::cppu::IPropertyArrayHelper* OHSQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & OHSQLTable::getInfoHelper() +{ + return *static_cast(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{}); +} + +// 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 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& _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 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 aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pIter = aTypes.getConstArray(); + const Type* pEnd = pIter + aTypes.getLength(); + for(;pIter != pEnd;++pIter) + { + if( *pIter != cppu::UnoType::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::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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(m_rParent).getConnection() + ,sTable + ,xRow->getString(4) + ,xRow->getString(5) + ,sSchema + ,sCatalog + ,nPrivileges); + } + ::comphelper::disposeComponent(xResult); + } + + return xRet; +} + +void OTables::impl_refresh( ) +{ + static_cast(m_rParent).refreshTables(); +} + +void OTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference< XPropertySet > OTables::createDescriptor() +{ + return new OHSQLTable(this,static_cast(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(m_rParent).getConnection(); + + + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,_sElementName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + + OUString aSql( "DROP " ); + + Reference 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(static_cast(m_rParent).getPrivateViews()); + if ( pViews && pViews->hasByName(_sElementName) ) + pViews->dropByNameImpl(_sElementName); + } +} + +void OTables::createTable( const Reference< XPropertySet >& descriptor ) +{ + Reference< XConnection > xConnection = static_cast(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(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 + +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 +#include + + +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 + + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::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 xMeta = m_xConnection->getMetaData(); + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(xMeta,objName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + Reference 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 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 xMeta = m_xConnection->getMetaData(); + OUString sGrant = "GRANT " + sPrivs + + " ON " + ::dbtools::quoteTableName(xMeta,objName,::dbtools::EComposeRule::InDataManipulation) + + " TO " + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), m_Name); + + Reference 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 xMeta = m_xConnection->getMetaData(); + OUString sGrant = "REVOKE " + sPrivs + + " ON " + ::dbtools::quoteTableName(xMeta,objName,::dbtools::EComposeRule::InDataManipulation) + + " FROM " + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), m_Name); + + Reference 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 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 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 +#include +#include +#include +#include +#include + +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 +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + + +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 TO + // 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 +#include +#include +#include +#include +#include +#include + +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(m_rParent).refreshTables(); +} + +void HViews::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference< XPropertySet > HViews::createDescriptor() +{ + Reference xConnection = static_cast(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 xProp(xObject,UNO_QUERY); + aSql += ::dbtools::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InTableDefinitions, true ); + + Reference xConnection = static_cast(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 = static_cast(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(static_cast(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 +#endif +#include +#include +#include +#include + +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 +#endif +#include +#include +#include +#include + +#include +#include +#include "accesslog.hxx" + +#include + + +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 pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper,"No stream helper!"); + if ( pHelper ) + { + Reference xIn = pHelper->getInputStream(); + if ( xIn.is() ) + { + try + { + sal_Int64 tmpLongVal = n; + sal_Int32 tmpIntVal; + + try + { + do { + if (tmpLongVal >= std::numeric_limits::max() ) + tmpIntVal = std::numeric_limits::max(); + else // Casting is safe here. + tmpIntVal = static_cast(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 pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper,"No stream helper!"); + Reference xIn = pHelper ? pHelper->getInputStream() : Reference(); + 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 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(&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 +#endif + +#include +#include +#include "accesslog.hxx" +#include +#include +#include +#include +#include + +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 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 + +#ifdef HSQLDB_DBG + +#include + +#include "accesslog.hxx" +#include "hsqldb/HStorageMap.hxx" + +#include + +namespace connectivity::hsqldb +{ + typedef std::map 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 +#include +#include + +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 @@ + + + + + + + + + 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 +#include +#include + +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 +#include +#include +#include + +#include + +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(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(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( + const_cast(pattern.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between and + // ; 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(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 +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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::get(), + cppu::UnoType::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(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(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 (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(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(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(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(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 (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 (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 +#include + +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(object), "", "()V"); + if (id == nullptr) + { + ThrowSQLException(t.pEnv, nullptr); + } + auto const obj = t.pEnv->NewObject(static_cast(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 +#include +#include +#include +#include + +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(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(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(args[0].l)); + } //t.pEnv + return static_cast(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 + +#include +#include +#include + +#include + + +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(_rDate.Year), static_cast(_rDate.Month), static_cast(_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(_rTime.Hours), static_cast(_rTime.Minutes), static_cast(_rTime.Seconds), static_cast(_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(_rDateTime.Year), static_cast(_rDateTime.Month), static_cast(_rDateTime.Day), + static_cast(_rDateTime.Hours), static_cast(_rDateTime.Minutes), static_cast(_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 +#include + + +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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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; iSetObjectArrayElement( pObjArray, static_cast(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 + 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(args[0].l)); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + if(args[1].l) + { + t.pEnv->DeleteLocalRef(static_cast(args[1].l)); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + if(!tableNamePattern.isEmpty()) + { + t.pEnv->DeleteLocalRef(static_cast(args[2].l)); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + //for(INT16 i=0;iDeleteLocalRef( static_cast(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(args[0].l)); + if(args[1].l) + t.pEnv->DeleteLocalRef(static_cast(args[1].l)); + if(!table.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast(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(args[0].l)); + if(args[1].l) + t.pEnv->DeleteLocalRef(static_cast(args[1].l)); + if(!table.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast(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 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 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(args[0].l)); + if(args[1].l) + t.pEnv->DeleteLocalRef(static_cast(args[1].l)); + if(!primaryTable.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast(args[2].l)); + if(foreignCatalog.hasValue()) + t.pEnv->DeleteLocalRef(static_cast(args[3].l)); + if(args[4].l) + t.pEnv->DeleteLocalRef(static_cast(args[4].l)); + if(!foreignTable.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast(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 = ""; + 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(args[0].l) ); + if ( args[1].l ) + t.pEnv->DeleteLocalRef( static_cast(args[1].l) ); + if ( args[2].l ) + t.pEnv->DeleteLocalRef( static_cast(args[2].l) ); + if ( args[3].l ) + t.pEnv->DeleteLocalRef( static_cast(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( + const_cast(types.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between and + // ; 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(args[0].l)); + if(!schemaPattern.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast(args[1].l)); + if(!typeNamePattern.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast(args[2].l)); + if(args[3].l) + t.pEnv->DeleteLocalRef(static_cast(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 + +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 + +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 +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 +#include + +#include +#include +#include + +#include + +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 +#include +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, "",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, "",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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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(), "", "([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 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 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 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(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(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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +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::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::get(), + cppu::UnoType::get(), + cppu::UnoType::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::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(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(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::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, + cppu::UnoType::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(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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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& _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(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(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(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(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(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(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(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(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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::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(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 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("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( + const_cast(x.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between and + // ; 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( + const_cast(aSeq.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between and + // ; 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, "", 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( + const_cast(aSeq.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between and + // ; 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, "", 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(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(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 +#include +#include +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(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 + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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::get(), + cppu::UnoType::get(), + cppu::UnoType::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(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(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 (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(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(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(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(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(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 (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 (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( + const_cast(x.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between and + // ; 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 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::get(), + PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType::get(), + PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType::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 +#include + +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 + +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 +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 +#include +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(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 + +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 +#include +#include +#include + +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(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 @@ + + + + + + + + + + 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 +#include +#include +#include +#include +#include +#include +#include + +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(args[1].l)); + t.pEnv->DeleteLocalRef(static_cast(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, "",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(_rTemp.getStr()), _rTemp.getLength()); + pEnv->ExceptionClear(); + OSL_ENSURE(pStr,"Could not create a jsstring object!"); + return pStr; +} + + +std::unique_ptr connectivity::createStringPropertyArray(const Sequence< PropertyValue >& info ) +{ + std::unique_ptr 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(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, "", 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, "", 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 + +#include +#include +#include +#include +#include + +using namespace connectivity::macab; +using namespace ::com::sun::star::uno; + +namespace { + +void manageDuplicateGroups(std::vector _xGroups) +{ + /* If we have two cases of groups, say, family, this makes it: + * family + * family (2) + */ + std::vector::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 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(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(const_cast(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 +#include + +#include +#include +#include +#include + +namespace connectivity::macab +{ + class MacabAddressBook + { + protected: + ABAddressBookRef m_aAddressBook; + MacabRecords *m_xMacabRecords; + std::vector m_xMacabGroups; + bool m_bRetrievedGroups; + + public: + MacabAddressBook(); + ~MacabAddressBook(); + static const OUString & getDefaultTableName(); + + MacabRecords *getMacabRecords(); + std::vector 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 + +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 + +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 +#include + +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 + +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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include + +namespace connectivity::macab +{ + + typedef ::cppu::WeakComponentImplHelper 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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((*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 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 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 +#include + +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 +#include +#include +#include +#include +#include +#include + +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( 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 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 +#include +#include +#include +#include +#include + +// 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 + init 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 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 + @precond m_hConnectorModule is not + */ + 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(ABRecordCopyValue(_xGroup, kABGroupNameProperty)); + m_sName = CFStringToOUString(sGroupName); + CFRelease(sGroupName); + + // The _group's_ records (remember MacabGroup inherits from MacabRecords) + recordsSize = static_cast(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(const_cast(CFArrayGetValueAtIndex(xGroupMembers,i))); + if(xPerson != nullptr) + { + sGroupMemberUID = static_cast(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 +#include +#include +#include + + +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 +#include +#include + +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(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(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(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(_field1->value), + static_cast(_field2->value), + 0); // 0 = no options (like ignore case) + + return static_cast(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 + +#include + +#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 +#include +#include +#include +#include + +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(m_aParameterRow->size())) + m_aParameterRow->resize(nParams); +} + +void MacabPreparedStatement::setMacabFields() const +{ + ::rtl::Reference 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(m_aParameterRow->size())) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString( + STR_INVALID_PARA_COUNT + ) ); + ::dbtools::throwGenericSQLException(sError,*const_cast(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 +#include +#include +#include + +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 + +#include +#include +#include +#include +#include + +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(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(_field1->value), + static_cast(_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(_field1->value), + static_cast(_field2->value), + nullptr); // NULL = unused variable + break; + + case kABIntegerProperty: + case kABRealProperty: + result = CFNumberCompare( + static_cast(_field1->value), + static_cast(_field2->value), + nullptr); // NULL = unused variable + break; + + default: + result = kCFCompareEqualTo; // can't compare + } + + return static_cast(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(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(_aField->value)); + break; + case kABDateProperty: + { + DateTime aTime = CFDateToDateTime(static_cast(_aField->value)); + fieldString = DBTypeConversion::toDateTimeString(aTime); + } + break; + case kABIntegerProperty: + { + CFNumberType numberType = CFNumberGetType( static_cast(_aField->value) ); + sal_Int64 nVal; + // Should we check for the wrong type here, e.g., a float? + bool m_bSuccess = !CFNumberGetValue(static_cast(_aField->value), numberType, &nVal); + if(m_bSuccess) + fieldString = OUString::number(nVal); + } + break; + case kABRealProperty: + { + CFNumberType numberType = CFNumberGetType( static_cast(_aField->value) ); + double nVal; + // Should we check for the wrong type here, e.g., an int? + bool m_bSuccess = !CFNumberGetValue(static_cast(_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 + +#include + +#include +#include +#include + +#include +#include +#include +#include + +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 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 + +#include +#include +#include + +#include "MacabRecords.hxx" +#include "MacabRecord.hxx" +#include "MacabHeader.hxx" +#include "macabutilities.hxx" + +#include +#include +#include +#include +#include + +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(_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(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(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(CFArrayGetCount(_records)); + sal_Int32 numProperties = static_cast(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::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(CFArrayGetValueAtIndex(allProperties, i)); + for(std::vector::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::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(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(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(const_cast(_propertyValue))); + CFStringRef multiLabel, localizedMultiLabel; + OUString multiLabelString; + OUString multiPropertyString; + OUString headerNameString; + ABPropertyType multiType = static_cast(ABMultiValuePropertyType(static_cast(const_cast(_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(const_cast(_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(const_cast(_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> multiHeaders; + ABPropertyType multiType = static_cast(ABMultiValuePropertyType(static_cast(const_cast(_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(const_cast(_propertyValue)), i); + multiValue = ABMultiValueCopyValueAtIndex(static_cast(const_cast(_propertyValue)), i); + std::unique_ptr 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(); + multiLengthSecondLevel += hdr->getSize(); + } + else + { + hdr = std::make_unique(); + } + 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(CFDictionaryGetCount(static_cast(_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(malloc(sizeof(CFStringRef)*numRecords)); + dictValues = static_cast(malloc(sizeof(CFTypeRef)*numRecords)); + CFDictionaryGetKeysAndValues(static_cast(_propertyValue), reinterpret_cast(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(CFArrayGetCount(static_cast(_propertyValue))); + sal_Int32 i,j,k; + CFTypeRef arrValue; + ABPropertyType arrType; + std::vector> 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(_propertyValue), i); + arrType = getABTypeFromCFType( CFGetTypeID(arrValue) ); + arrLabelString = propertyNameString + OUString::number(i); + arrLabel = OUStringToCFString(arrLabelString); + auto hdr = std::unique_ptr(createHeaderForProperty(arrType, arrValue, arrLabel)); + if (!hdr) + hdr = std::make_unique(); + 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(CFArrayGetCount(recordProperties)); + + sal_Int32 i; + + CFTypeRef propertyValue; + ABPropertyType propertyType; + + CFStringRef propertyName, localizedPropertyName; + OUString propertyNameString; + for(i = 0; i < numProperties; i++) + { + propertyName = static_cast(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(CFArrayGetCount(static_cast(_propertyValue))); + sal_Int32 i; + OUString newPropertyName; + + /* Going through each element... */ + for(i = 0; i < arrLength; i++) + { + const void *arrValue = CFArrayGetValueAtIndex(static_cast(_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(CFDictionaryGetCount(static_cast(_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(malloc(sizeof(CFStringRef)*numRecords)); + dictValues = static_cast(malloc(sizeof(CFTypeRef)*numRecords)); + CFDictionaryGetKeysAndValues(static_cast(_propertyValue), reinterpret_cast(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(const_cast(_propertyValue))); + CFStringRef multiLabel, localizedMultiLabel; + CFTypeRef multiValue; + OUString multiLabelString, newPropertyName; + ABPropertyType multiType = static_cast(ABMultiValuePropertyType(static_cast(const_cast(_propertyValue))) - 0x100); + + /* Go through each element... */ + for(i = 0; i < multiLength; i++) + { + /* Label and value */ + multiLabel = ABMultiValueCopyLabelAtIndex(static_cast(const_cast(_propertyValue)), i); + multiValue = ABMultiValueCopyValueAtIndex(static_cast(const_cast(_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(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 + +#include +#include + +#include "MacabRecord.hxx" +#include "MacabHeader.hxx" + +#include +#include +#include +#include +#include + +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_CFTypes; + + /* For required properties */ + std::vector 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 pConnection = static_cast< MacabConnection *>(m_xStatement->getConnection().get()); + + m_aMacabRecords = pConnection->getAddressBook()->getMacabRecords(m_sTableName); +} + +void MacabResultSet::someMacabRecords(const MacabCondition *pCondition) +{ + rtl::Reference 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::get(), + cppu::UnoType::get(), + cppu::UnoType::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(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(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(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(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(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(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(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(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(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(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(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(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::get(), + PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), + PROPERTY_ID_ISBOOKMARKABLE, + cppu::UnoType::get(), + PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType::get(), + PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType::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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 + { + 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(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 +#include + +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 &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 +#include +#include +#include + +namespace connectivity::macab +{ + /* + ** MacabResultSetMetaData + */ + class MacabResultSetMetaData : public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> + { + MacabConnection* m_pConnection; + OUString m_sTableName; + std::vector 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 &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 +#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 +#include +#include +#include +#include +#include + +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 xColumns; // selected columns + rtl::Reference 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(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::get(), + cppu::UnoType::get(), + cppu::UnoType::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 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(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::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, + cppu::UnoType::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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 + + { + 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 + +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 + +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 +#include + +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(m_rParent).getConnection(), + aName, + xRow->getString(4), + xRow->getString(5), + ""); + } + } + ::comphelper::disposeComponent(xResult); + + return xRet; +} + +void MacabTables::impl_refresh( ) +{ + static_cast(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 +#include + +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 @@ + + + + + + + + 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 + +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 + +#include + +#include "MacabHeader.hxx" +#include "MacabRecord.hxx" + +#include + +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 +#include "MacabHeader.hxx" +#include "MacabRecord.hxx" + +#include +#include +#include + +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> 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 +#include +#include + +#include +#include +#include +#include +#include + +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(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(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 +#include +#include +#include +#include +#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 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 + +#include + +#include +#include +#include + + +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 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 +#endif // End UNIX + +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include +#endif // End _WIN32 +#include +#include +#include + +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(_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 + +#include + +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 +#include +#include +#include +#include + +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(&seq))) + break; + OString line(reinterpret_cast(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 + +#include +#include + +struct ini_NameValue +{ + OUString sName; + OUString sValue; +}; + +typedef std::vector< + ini_NameValue +> NameValueVector; + +struct ini_Section +{ + NameValueVector vVector; +}; +typedef std::mapIniSectionMap; + + +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(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(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(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(product); + ProductStruct &rProduct = m_ProductProfileList[index]; + list.realloc(static_cast(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(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(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 +#include +#include +#include + +#include +#include + +using namespace com::sun::star::mozilla; +namespace connectivity::mozab { class ProfileStruct; } + +typedef std::map 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 @@ + + + + + + + + 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 +#include +#include +#include +#include +#include +#include + +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) + : OCatalog(_xConnection) + , m_xConnection(_xConnection) +{ +} + +void OMySQLCatalog::refreshObjects(const Sequence& _sKindOfObject, + ::std::vector& _rNames) +{ + Reference xResult = m_xMetaData->getTables(Any(), "%", "%", _sKindOfObject); + fillNames(xResult, _rNames); +} + +void OMySQLCatalog::refreshTables() +{ + ::std::vector aVector; + + Sequence 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 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 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 aVector; + Reference xStmt = m_xConnection->createStatement(); + Reference xResult = xStmt->executeQuery( + "SELECT grantee FROM information_schema.user_privileges GROUP BY grantee"); + if (xResult.is()) + { + Reference 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::get()) + return Any(); + + return OCatalog::queryInterface(rType); +} + +Sequence SAL_CALL OMySQLCatalog::getTypes() +{ + Sequence aTypes = OCatalog::getTypes(); + std::vector aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for (; pBegin != pEnd; ++pBegin) + { + if (*pBegin != cppu::UnoType::get()) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence(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 +#include + +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& _rVector) + : OColumnsHelper(_rParent, true /*_bCase*/, _rMutex, _rVector, true /*_bUseHardRef*/) +{ +} + +Reference 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::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 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 const& info) +{ + return comphelper::NamedValueCollection::getOrDefault(info, u"JavaDriverClass", + OUString("com.mysql.jdbc.Driver")); +} +} + +ODriverDelegator::ODriverDelegator(const Reference& _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 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 lcl_loadDriver(const Reference& _rxContext, + const OUString& _sUrl) +{ + Reference xDriverAccess = DriverManager::create(_rxContext); + Reference xDriver = xDriverAccess->getDriverByURL(_sUrl); + return xDriver; +} + +Sequence lcl_convertProperties(T_DRIVERTYPE _eType, + const Sequence& info, + const OUString& _sUrl) +{ + std::vector 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(aProps.data(), aProps.size()); +} +} + +Reference ODriverDelegator::loadDriver(std::u16string_view url, + const Sequence& info) +{ + Reference 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 SAL_CALL ODriverDelegator::connect(const OUString& url, + const Sequence& info) +{ + Reference xConnection; + if (acceptsURL(url)) + { + Reference xDriver = loadDriver(url, info); + if (xDriver.is()) + { + OUString sCuttedUrl = transformUrl(url); + const T_DRIVERTYPE eType = lcl_getDriverType(url); + Sequence 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(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 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 SAL_CALL +ODriverDelegator::getPropertyInfo(const OUString& url, const Sequence& info) +{ + if (!acceptsURL(url)) + return Sequence(); + + Sequence aBoolean{ "0", "1" }; + + std::vector 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())); + } + 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())); + aDriverInfo.push_back(DriverPropertyInfo( + "NamedPipe", "The name of a pipe to connect to a local MySQL server.", false, + OUString(), Sequence())); + } + + return Sequence(aDriverInfo.data(), aDriverInfo.size()); +} + +sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion() { return 1; } + +sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion() { return 0; } + +Reference SAL_CALL +ODriverDelegator::getDataDefinitionByConnection(const Reference& connection) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed); + + Reference xTab; + auto pConnection = comphelper::getFromUnoTunnel(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 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 SAL_CALL +ODriverDelegator::getDataDefinitionByURL(const OUString& url, const Sequence& 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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& _rVector) + : OKeysHelper(_pTable, _rMutex, _rVector) + { + } +}; +} +} + +OMySQLTable::OMySQLTable(sdbcx::OCollection* _pTables, const Reference& _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, + 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::get()); +} + +::cppu::IPropertyArrayHelper* OMySQLTable::createArrayHelper(sal_Int32 /*_nId*/) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& OMySQLTable::getInfoHelper() +{ + return *static_cast(this)->getArrayHelper(isNew() ? 1 : 0); +} + +sdbcx::OCollection* OMySQLTable::createColumns(const ::std::vector& _rNames) +{ + OMySQLColumns* pColumns = new OMySQLColumns(*this, m_aMutex, _rNames); + pColumns->setParent(this); + return pColumns; +} + +sdbcx::OCollection* OMySQLTable::createKeys(const ::std::vector& _rNames) +{ + return new OMySQLKeysHelper(this, m_aMutex, _rNames); +} + +sdbcx::OCollection* OMySQLTable::createIndexes(const ::std::vector& _rNames) +{ + return new OIndexesHelper(this, m_aMutex, _rNames); +} + +const Sequence& OMySQLTable::getUnoTunnelId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OMySQLTable::getSomething(const Sequence& rId) +{ + return comphelper::getSomethingImpl(rId, this, + comphelper::FallbackToGetSomethingOf{}); +} + +// XAlterTable +void SAL_CALL OMySQLTable::alterColumnByName(const OUString& colName, + const Reference& 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 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(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& _xDescriptor) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql + = getAlterTableColumnPart() + " CHANGE " + ::dbtools::quoteName(sQuote, _rColName) + " "; + + rtl::Reference 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(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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 sTableTypes{ + "VIEW", "TABLE", "%" + }; // this last one just to be sure to include anything else... + + Any aCatalog; + if (!sCatalog.isEmpty()) + aCatalog <<= sCatalog; + Reference xResult = m_xMetaData->getTables(aCatalog, sSchema, sTable, sTableTypes); + + sdbcx::ObjectType xRet; + if (xResult.is()) + { + Reference 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(m_rParent).getConnection(), + sTable, xRow->getString(4), xRow->getString(5), sSchema, + sCatalog, nPrivileges); + } + ::comphelper::disposeComponent(xResult); + } + + return xRet; +} + +void OTables::impl_refresh() { static_cast(m_rParent).refreshTables(); } + +void OTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference OTables::createDescriptor() +{ + return new OMySQLTable(this, static_cast(m_rParent).getConnection()); +} + +// XAppend +sdbcx::ObjectType OTables::appendObject(const OUString& _rForName, + const Reference& descriptor) +{ + createTable(descriptor); + return createObject(_rForName); +} + +// XDrop +void OTables::dropObject(sal_Int32 _nPos, const OUString& _sElementName) +{ + Reference xObject(getObject(_nPos)); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject); + if (bIsNew) + return; + + Reference xConnection = static_cast(m_rParent).getConnection(); + + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, _sElementName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + + OUString aSql("DROP "); + + Reference 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 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(static_cast(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& descriptor) +{ + const Reference xConnection + = static_cast(m_rParent).getConnection(); + const OUString aSql + = adjustSQL(::dbtools::createSqlCreateTableStatement(descriptor, xConnection)); + Reference 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(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& 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& _xConnection) + : connectivity::sdbcx::OUser(true) + , m_xConnection(_xConnection) +{ + construct(); +} + +OMySQLUser::OMySQLUser(const css::uno::Reference& _xConnection, + const OUString& Name) + : connectivity::sdbcx::OUser(Name, true) + , m_xConnection(_xConnection) +{ + construct(); +} + +void OMySQLUser::refreshGroups() {} + +OUserExtend::OUserExtend(const css::uno::Reference& _xConnection) + : OMySQLUser(_xConnection) +{ + construct(); +} + +void OUserExtend::construct() +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), + PROPERTY_ID_PASSWORD, 0, &m_Password, ::cppu::UnoType::get()); +} + +cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const +{ + Sequence 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 xMeta = m_xConnection->getMetaData(); + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(xMeta, objName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + Reference 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 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 xMeta = m_xConnection->getMetaData(); + OUString sGrant + = "GRANT " + sPrivs + " ON " + + ::dbtools::quoteTableName(xMeta, objName, ::dbtools::EComposeRule::InDataManipulation) + + " TO " + m_Name; + + Reference 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 xMeta = m_xConnection->getMetaData(); + OUString sGrant + = "REVOKE " + sPrivs + " ON " + + ::dbtools::quoteTableName(xMeta, objName, ::dbtools::EComposeRule::InDataManipulation) + + " FROM " + m_Name; + + Reference 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 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 +#include +#include +#include +#include +#include + +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& _rVector, + const css::uno::Reference& _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 OUsers::createDescriptor() { return new OUserExtend(m_xConnection); } + +// XAppend +sdbcx::ObjectType OUsers::appendObject(const OUString& _rForName, + const Reference& 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 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 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 +#include +#include +#include +#include +#include +#include + +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(m_rParent).refreshTables(); } + +void OViews::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference OViews::createDescriptor() +{ + Reference xConnection = static_cast(m_rParent).getConnection(); + rtl::Reference pNew + = new connectivity::sdbcx::OView(true, xConnection->getMetaData()); + return pNew; +} + +// XAppend +sdbcx::ObjectType OViews::appendObject(const OUString& _rForName, + const Reference& descriptor) +{ + createView(descriptor); + return createObject(_rForName); +} + +// XDrop +void OViews::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/) +{ + if (m_bInDrop) + return; + + Reference xObject(getObject(_nPos)); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject); + if (bIsNew) + return; + + OUString aSql("DROP VIEW"); + + Reference xProp(xObject, UNO_QUERY); + aSql += ::dbtools::composeTableName(m_xMetaData, xProp, + ::dbtools::EComposeRule::InTableDefinitions, true); + + Reference xConnection = static_cast(m_rParent).getConnection(); + Reference 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& descriptor) +{ + Reference xConnection = static_cast(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 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(static_cast(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 @@ + + + + + + + + + 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 @@ + + + + + + + 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& rConnection) + : OCatalog(rConnection) + , m_xConnection(rConnection) +{ +} + +//----- OCatalog ------------------------------------------------------------- +void connectivity::mysqlc::Catalog::refreshTables() +{ + css::uno::Reference xTables + = m_xMetaData->getTables(css::uno::Any(), "%", "%", {}); + + if (!xTables.is()) + return; + + ::std::vector 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 xViews + = m_xMetaData->getTables(css::uno::Any(), "%", "%", { "VIEW" }); + + if (!xViews.is()) + return; + + ::std::vector 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 + +namespace connectivity::mysqlc +{ +class Catalog : public ::connectivity::sdbcx::OCatalog +{ + css::uno::Reference m_xConnection; + +public: + explicit Catalog(const css::uno::Reference& 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 + +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::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 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 + +namespace connectivity::mysqlc +{ +class Column; +typedef ::comphelper::OIdPropertyArrayUsageHelper 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 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& rVector) + : OColumnsHelper(rTable, + true, // case sensitivity + rMutex, rVector, + /*bUseHardRef*/ true) +{ + OColumnsHelper::setParent(&rTable); +} + +css::uno::Reference 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 + +namespace connectivity::mysqlc +{ +class Columns : public ::connectivity::OColumnsHelper +{ +protected: + virtual css::uno::Reference createDescriptor() override; + +public: + Columns(Table& rTable, ::osl::Mutex& rMutex, const ::std::vector& _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 + +#include "mysqlc_driver.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_general.hxx" + +#include + +#include + +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& 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 OConnection::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.Connection" }; +} + +sal_Bool OConnection::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Reference SAL_CALL OConnection::createStatement() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // create a statement + // the statement can only be executed once + Reference xReturn = new OStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + + return xReturn; +} + +Reference 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 xStatement = new OPreparedStatement(this, pStmt); + m_aStatements.push_back(WeakReferenceHelper(xStatement)); + return xStatement; +} + +Reference 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(); +} + +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 SAL_CALL OConnection::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference 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 SAL_CALL OConnection::getTypeMap() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference t = m_typeMap; + return t; +} + +void SAL_CALL OConnection::setTypeMap(const Reference& 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 xComp(statement.get(), UNO_QUERY); + if (xComp.is()) + { + xComp->dispose(); + } + } + m_aStatements.clear(); + + m_xMetaData = WeakReference(); + + 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(version); +} + +OUString OConnection::transFormPreparedStatement(const OUString& _sSQL) +{ + OUString sSqlStatement = _sSQL; + if (!m_xParameterSubstitution.is()) + { + try + { + Reference xCon = this; + Sequence 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& rId) +{ + return comphelper::getSomethingImpl(rId, this); +} + +// static +const Sequence& OConnection::getUnoTunnelId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + +Reference OConnection::createCatalog() +{ + MutexGuard aGuard(m_aMutex); + + // m_xCatalog is a weak reference. Reuse it if it still exists. + Reference 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 +#include "mysqlc_subcomponent.hxx" +#include "mysqlc_types.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +namespace sql +{ +class SQLException; +} + +namespace connectivity +{ +class OMetaConnection; +class ODatabaseMetaData; + +namespace mysqlc +{ +typedef ::cppu::WeakComponentImplHelper + 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 OWeakRefArray; + +class OConnection final : public cppu::BaseMutex, public OConnection_BASE +{ +private: + MYSQL m_mysql; + ConnectionSettings m_settings; + css::uno::Reference m_typeMap; + css::uno::Reference m_xParameterSubstitution; + + // Data attributes + + css::uno::WeakReference m_xCatalog; + css::uno::WeakReference m_xMetaData; + + OWeakRefArray m_aStatements; // vector containing a list + // of all the Statement objects + // for this Connection + + rtl::Reference 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& 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 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 SAL_CALL getSupportedServiceNames() override; + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence& rId) override; + static const css::uno::Sequence& getUnoTunnelId(); + + // XConnection + css::uno::Reference SAL_CALL createStatement() override; + + css::uno::Reference + SAL_CALL prepareStatement(const OUString& sql) override; + + css::uno::Reference + 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 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 SAL_CALL getTypeMap() override; + + void SAL_CALL + setTypeMap(const css::uno::Reference& 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 +#include +#include +#include +#include +#include + +#include +#include +#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, sal_Int32 _nType, + const std::vector>& _rRows) +{ + Reference xIni(_xResultSet, UNO_QUERY); + + Sequence> aRows(_rRows.size()); + + Sequence* pRowsIter = aRows.getArray(); + for (const auto& rRow : _rRows) + { + if (!rRow.empty()) + { + (*pRowsIter) = comphelper::containerToSequence(rRow); + } + ++pRowsIter; + } + Sequence 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 statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery("select user()"); + Reference 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 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 SAL_CALL ODatabaseMetaData::getTableTypes() +{ + const char* const table_types[] = { "TABLE", "VIEW" }; + sal_Int32 const requiredVersion[] = { 0, 50000 }; + + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> 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 SAL_CALL ODatabaseMetaData::getTypeInfo() +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + + std::vector> 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 SAL_CALL ODatabaseMetaData::getCatalogs() +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getSchemas() +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + + Reference statement = m_rConnection.createStatement(); + Reference 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 rs(executed, UNO_QUERY_THROW); + Reference supp(executed, UNO_QUERY_THROW); + Reference rs_meta = supp->getMetaData(); + + Reference xRow(rs, UNO_QUERY_THROW); + sal_uInt32 columns = rs_meta->getColumnCount(); + while (rs->next()) + { + std::vector 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 + 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 statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query); + return rs; +} + +Reference 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 statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query); + Reference xRow(rs, UNO_QUERY_THROW); + + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> aRows; + while (rs->next()) + { + std::vector 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 SAL_CALL ODatabaseMetaData::getTables(const Any& /*catalog*/, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const Sequence& 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 statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query); + return rs; +} + +Reference 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 + SAL_CALL ODatabaseMetaData::getProcedures(const Any& /*catalog*/, + const OUString& /*schemaPattern*/, + const OUString& /*procedureNamePattern*/) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO IMPL + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 7, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getVersionColumns(const Any& /* catalog */, + const OUString& /* schema */, + const OUString& /* table */) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + lcl_setRows_throw(xResultSet, 16, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getExportedKeys(const Any& /*catalog */, + const OUString& /*schema */, + const OUString& /*table */) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO implement + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 8, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getImportedKeys(const Any& /*catalog*/, + const OUString& schema, + const OUString& table) +{ + Reference 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> aRows; + Reference statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query); + Reference xRow(rs, UNO_QUERY_THROW); + + while (rs->next()) + { + std::vector 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 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 statement = m_rConnection.createStatement(); + Reference rs = statement->executeQuery(query); + return rs; +} + +Reference SAL_CALL ODatabaseMetaData::getIndexInfo(const Any& /*catalog*/, + const OUString& /*schema*/, + const OUString& /*table*/, + sal_Bool /*unique*/, + sal_Bool /*approximate*/) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 11, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getBestRowIdentifier(const Any& /*catalog*/, + const OUString& /*schema*/, + const OUString& /*table*/, + sal_Int32 /*scope*/, + sal_Bool /*nullable*/) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 15, rRows); + return xResultSet; +} + +Reference 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 SAL_CALL ODatabaseMetaData::getCrossReference( + const Any& /*primaryCatalog*/, const OUString& /*primarySchema_*/, + const OUString& /*primaryTable_*/, const Any& /*foreignCatalog*/, + const OUString& /*foreignSchema*/, const OUString& /*foreignTable*/) +{ + Reference xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 13, rRows); + return xResultSet; +} + +Reference SAL_CALL ODatabaseMetaData::getUDTs(const Any& /* catalog */, + const OUString& /* schemaPattern */, + const OUString& /* typeNamePattern */, + const Sequence& /* 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 +#include + +namespace connectivity::mysqlc +{ +using ::com::sun::star::uno::Any; + +//************ Class: ODatabaseMetaData + +typedef ::cppu::WeakImplHelper1 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 + SAL_CALL getProcedures(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern) override; + css::uno::Reference + SAL_CALL getProcedureColumns(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern, + const OUString& columnNamePattern) override; + css::uno::Reference + SAL_CALL getTables(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence& types) override; + css::uno::Reference SAL_CALL getSchemas() override; + css::uno::Reference SAL_CALL getCatalogs() override; + css::uno::Reference SAL_CALL getTableTypes() override; + virtual css::uno::Reference + SAL_CALL getColumns(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern) override; + css::uno::Reference + SAL_CALL getColumnPrivileges(const Any& catalog, const OUString& schema, + const OUString& table, + const OUString& columnNamePattern) override; + css::uno::Reference + SAL_CALL getTablePrivileges(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern) override; + css::uno::Reference + SAL_CALL getBestRowIdentifier(const Any& catalog, const OUString& schema, + const OUString& table, sal_Int32 scope, + sal_Bool nullable) override; + css::uno::Reference SAL_CALL + getVersionColumns(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference SAL_CALL + getPrimaryKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference SAL_CALL + getImportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference SAL_CALL + getExportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference + 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 SAL_CALL getTypeInfo() override; + css::uno::Reference + 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 + SAL_CALL getUDTs(const Any& catalog, const OUString& schemaPattern, + const OUString& typeNamePattern, + const css::uno::Sequence& types) override; + css::uno::Reference 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 +#include + +MysqlCDriver::MysqlCDriver(const Reference& _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 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 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 SAL_CALL MysqlCDriver::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference SAL_CALL MysqlCDriver::connect(const OUString& url, + const Sequence& 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 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 SAL_CALL +MysqlCDriver::getPropertyInfo(const OUString& url, const Sequence& /* info */) +{ + if (acceptsURL(url)) + { + return { { "Hostname", "Name of host", true, "localhost", {} }, + { "Port", "Port", true, "3306", {} } }; + } + + return Sequence(); +} + +sal_Int32 SAL_CALL MysqlCDriver::getMajorVersion() { return MARIADBC_VERSION_MAJOR; } + +sal_Int32 SAL_CALL MysqlCDriver::getMinorVersion() { return MARIADBC_VERSION_MINOR; } + +Reference + SAL_CALL MysqlCDriver::getDataDefinitionByConnection(const Reference& rConnection) +{ + if (OConnection* pConnection = comphelper::getFromUnoTunnel(rConnection)) + return pConnection->createCatalog(); + return {}; +} + +Reference SAL_CALL +MysqlCDriver::getDataDefinitionByURL(const OUString& rURL, const Sequence& rInfo) +{ + Reference xConnection = connect(rURL, rInfo); + return getDataDefinitionByConnection(xConnection); +} + +namespace connectivity::mysqlc +{ +Reference MysqlCDriver_CreateInstance(const Reference& _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 +#include +#include +#include + +namespace connectivity::mysqlc +{ +using css::uno::Reference; +using css::uno::Sequence; + +Reference +MysqlCDriver_CreateInstance(const Reference& _rxFactory); + +typedef ::cppu::WeakComponentImplHelper + ODriver_BASE; + +typedef void* (*OMysqlCConnection_CreateInstanceFunction)(void* _pDriver); + +class MysqlCDriver : public ODriver_BASE +{ +protected: + Reference 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& _rxFactory); + + // OComponentHelper + void SAL_CALL disposing() override; + // XInterface + static OUString getImplementationName_Static(); + static Sequence getSupportedServiceNames_Static(); + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence SAL_CALL getSupportedServiceNames() override; + + // XDriver + Reference SAL_CALL + connect(const OUString& url, const Sequence& info) override; + + sal_Bool SAL_CALL acceptsURL(const OUString& url) override; + Sequence SAL_CALL + getPropertyInfo(const OUString& url, const Sequence& info) override; + + sal_Int32 SAL_CALL getMajorVersion() override; + sal_Int32 SAL_CALL getMinorVersion() override; + + const Reference& getFactory() const { return m_xFactory; } + + static rtl_TextEncoding getDefaultEncoding() { return RTL_TEXTENCODING_UTF8; } + + // XDataDefinitionSupplier + virtual css::uno::Reference SAL_CALL getDataDefinitionByConnection( + const css::uno::Reference& rxConnection) override; + virtual css::uno::Reference SAL_CALL getDataDefinitionByURL( + const OUString& rsURL, const css::uno::Sequence& 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 +#include +#include + +#include + +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& _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& _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& _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& _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 + +#include +#include + +#include +#include + +#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 +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& _rxContext); + +void throwInvalidArgumentException(const char* _pAsciiFeatureName, + const css::uno::Reference& _rxContext); + +void throwSQLExceptionWithMsg(const char* msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference& _context, + const rtl_TextEncoding encoding); + +void throwSQLExceptionWithMsg(const OUString& msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference& _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& 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 + +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& 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& 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 + +namespace connectivity::mysqlc +{ +class Table; + +class Keys : public ::connectivity::OKeysHelper +{ +public: + Keys(Table* pTable, ::osl::Mutex& rMutex, const ::std::vector& 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace rtl; + +#include + +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 + +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 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(static_cast(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 SAL_CALL OPreparedResultSet::getTypes() +{ + OTypeCollection aTypes(cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::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 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(nColumnIndex); +} + +template T OPreparedResultSet::retrieveValue(sal_Int32 nColumnIndex) +{ + if (getTypeFromMysqlType(m_aFields[nColumnIndex - 1].type) == std::type_index(typeid(T))) + return *static_cast(m_aData[nColumnIndex - 1].buffer); + else + { + auto const& row = getRowSetValue(nColumnIndex); + if constexpr (std::is_same_v) + return row.getLong(); + else if constexpr (std::is_same_v) + return row.getInt32(); + else if constexpr (std::is_same_v) + return row.getInt16(); + else if constexpr (std::is_same_v) + return row.getInt8(); + else if constexpr (std::is_same_v) + return row.getDouble(); + else if constexpr (std::is_same_v) + return row.getFloat(); + else if constexpr (std::is_same_v) + return row.getBool(); + else + return row; + } +} + +template <> uno::Sequence OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + // TODO make conversion possible + return uno::Sequence(static_cast(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(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(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(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(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 SAL_CALL OPreparedResultSet::getBinaryStream(sal_Int32 /*column*/) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBinaryStream", + *this); + return nullptr; +} + +uno::Reference 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(column); +} + +sal_Int8 SAL_CALL OPreparedResultSet::getByte(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +uno::Sequence SAL_CALL OPreparedResultSet::getBytes(sal_Int32 column) +{ + return safelyRetrieveValue>(column); +} + +Date SAL_CALL OPreparedResultSet::getDate(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +double SAL_CALL OPreparedResultSet::getDouble(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +float SAL_CALL OPreparedResultSet::getFloat(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +sal_Int32 SAL_CALL OPreparedResultSet::getInt(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +sal_Int32 SAL_CALL OPreparedResultSet::getRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return static_cast(mysql_field_tell(m_pResult)); +} + +sal_Int64 SAL_CALL OPreparedResultSet::getLong(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +uno::Reference 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 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 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 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 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& /* 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(column); +} + +OUString SAL_CALL OPreparedResultSet::getString(sal_Int32 column) +{ + return safelyRetrieveValue(column); +} + +Time SAL_CALL OPreparedResultSet::getTime(sal_Int32 column) +{ + return safelyRetrieveValue