1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 package org.apache.openoffice.comp.sdbc.dbtools.sdbcx;
23 
24 import java.util.ArrayList;
25 import java.util.List;
26 
27 import org.apache.openoffice.comp.sdbc.dbtools.comphelper.CompHelper;
28 import org.apache.openoffice.comp.sdbc.dbtools.sdbcx.descriptors.SdbcxIndexDescriptor;
29 import org.apache.openoffice.comp.sdbc.dbtools.util.ComposeRule;
30 import org.apache.openoffice.comp.sdbc.dbtools.util.DbTools;
31 import org.apache.openoffice.comp.sdbc.dbtools.util.PropertyIds;
32 import org.apache.openoffice.comp.sdbc.dbtools.util.StandardSQLState;
33 
34 import com.sun.star.beans.UnknownPropertyException;
35 import com.sun.star.beans.XPropertySet;
36 import com.sun.star.container.ElementExistException;
37 import com.sun.star.container.XIndexAccess;
38 import com.sun.star.lang.IllegalArgumentException;
39 import com.sun.star.lang.IndexOutOfBoundsException;
40 import com.sun.star.lang.WrappedTargetException;
41 import com.sun.star.sdbc.IndexType;
42 import com.sun.star.sdbc.SQLException;
43 import com.sun.star.sdbc.XConnection;
44 import com.sun.star.sdbc.XDatabaseMetaData;
45 import com.sun.star.sdbc.XResultSet;
46 import com.sun.star.sdbc.XRow;
47 import com.sun.star.sdbc.XStatement;
48 import com.sun.star.sdbcx.XColumnsSupplier;
49 import com.sun.star.uno.AnyConverter;
50 import com.sun.star.uno.UnoRuntime;
51 
52 public class OIndexContainer extends OContainer {
53     protected OTable table;
54 
OIndexContainer(Object lock, List<String> names, boolean isCaseSensitive, OTable table)55     public OIndexContainer(Object lock, List<String> names, boolean isCaseSensitive, OTable table) throws ElementExistException {
56         super(lock, isCaseSensitive, names);
57         this.table = table;
58     }
59 
60     @Override
createDescriptor()61     protected XPropertySet createDescriptor() {
62         return new SdbcxIndexDescriptor(isCaseSensitive());
63     }
64 
65     @Override
createObject(String name)66     protected XPropertySet createObject(String name) throws SQLException {
67         try {
68             XConnection connection = table.getConnection();
69             if (connection == null) {
70                 return null;
71             }
72 
73             XPropertySet ret = null;
74             String qualifier = "";
75             String subname;
76             int len = name.indexOf('.');
77             if (len >= 0) {
78                 qualifier = name.substring(0, len);
79                 subname = name.substring(len + 1);
80             } else {
81                 subname = name;
82             }
83 
84             Object catalog = table.getPropertyValue(PropertyIds.CATALOGNAME.name);
85             String schemaName = AnyConverter.toString(table.getPropertyValue(PropertyIds.SCHEMANAME.name));
86             String tableName = AnyConverter.toString(table.getPropertyValue(PropertyIds.NAME.name));
87             XResultSet results = null;
88             try {
89                 results = connection.getMetaData().getIndexInfo(catalog, schemaName, tableName, false, false);
90                 if (results != null) {
91                     XRow row = UnoRuntime.queryInterface(XRow.class, results);
92                     boolean found = false;
93                     boolean isUnique = false;
94                     int clustered = -1;
95                     boolean isPrimaryKeyIndex = false;
96                     ArrayList<String> columnNames = new ArrayList<>();
97                     while (results.next()) {
98                         isUnique  = !row.getBoolean(4);
99                         if ((qualifier.isEmpty() || row.getString(5).equals(qualifier)) && row.getString(6).equals(subname)) {
100                             found = true;
101                             clustered = row.getShort(7);
102                             isPrimaryKeyIndex = isPrimaryKeyIndex(connection.getMetaData(), catalog, schemaName, tableName, subname);
103                             String columnName = row.getString(9);
104                             if (!row.wasNull()) {
105                                 columnNames.add(columnName);
106                             }
107                         }
108                     }
109                     if (found) {
110                         ret = new OIndex(subname, isCaseSensitive(), qualifier, isUnique, isPrimaryKeyIndex, clustered == IndexType.CLUSTERED,
111                                 columnNames, table);
112                     }
113                 }
114             } finally {
115                 CompHelper.disposeComponent(results);
116             }
117             return ret;
118         } catch (WrappedTargetException | UnknownPropertyException | IllegalArgumentException | ElementExistException exception) {
119             throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, exception);
120         }
121     }
122 
isPrimaryKeyIndex(XDatabaseMetaData metadata, Object catalog, String schema, String table, String name)123     private static boolean isPrimaryKeyIndex(XDatabaseMetaData metadata, Object catalog, String schema, String table, String name) throws SQLException {
124         XResultSet results = null;
125         try {
126             results = metadata.getPrimaryKeys(catalog, schema, table);
127             if (results != null) {
128                 XRow row = UnoRuntime.queryInterface(XRow.class, results);
129                 if (results.next()) { // there can be only one primary key
130                     return row.getString(6).equals(name);
131                 }
132             }
133             return false;
134         } finally {
135             CompHelper.disposeComponent(results);
136         }
137     }
138 
139     @Override
appendObject(String _rForName, XPropertySet descriptor)140     protected XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException {
141         try {
142             XConnection connection = table.getConnection();
143             if (connection == null) {
144                 return null;
145             }
146             String quote = connection.getMetaData().getIdentifierQuoteString();
147             boolean isUnique = AnyConverter.toBoolean(descriptor.getPropertyValue(PropertyIds.ISUNIQUE.name));
148             String composedName = DbTools.composeTableName(connection.getMetaData(), table, ComposeRule.InIndexDefinitions, false, false, true);
149             StringBuilder columnsText = new StringBuilder();
150             String separator = "";
151             XColumnsSupplier columnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, descriptor);
152             XIndexAccess columns = UnoRuntime.queryInterface(XIndexAccess.class, columnsSupplier.getColumns());
153             for (int i = 0; i < columns.getCount(); i++) {
154                 columnsText.append(separator);
155                 separator = ", ";
156                 XPropertySet column = AnyConverter.toObject(XPropertySet.class, columns.getByIndex(i));
157                 columnsText.append(DbTools.quoteName(quote, AnyConverter.toString(column.getPropertyValue(PropertyIds.NAME.name))));
158                 // FIXME: ::dbtools::getBooleanDataSourceSetting( m_pTable->getConnection(), "AddIndexAppendix" );
159                 boolean isAscending = AnyConverter.toBoolean(column.getPropertyValue(PropertyIds.ISASCENDING.name));
160                 columnsText.append(isAscending ? " ASC" : " DESC");
161             }
162             String sql = String.format("CREATE %s INDEX %s ON %s (%s)",
163                     isUnique ? "UNIQUE" : "",
164                     _rForName.isEmpty() ? "" : DbTools.quoteName(quote, _rForName),
165                     composedName,
166                     columnsText.toString());
167             XStatement statement = null;
168             try {
169                 statement = connection.createStatement();
170                 statement.execute(sql);
171             } finally {
172                 CompHelper.disposeComponent(statement);
173             }
174             return createObject(_rForName);
175         } catch (WrappedTargetException | UnknownPropertyException | IllegalArgumentException | IndexOutOfBoundsException exception) {
176             throw new SQLException("Error", this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, exception);
177         }
178     }
179 
180     @Override
dropObject(int index, String elementName)181     protected void dropObject(int index, String elementName) throws SQLException {
182         XConnection connection = table.getConnection();
183         if (connection == null) {
184             return;
185         }
186         String name;
187         String schema = "";
188         int len = elementName.indexOf('.');
189         if (len >= 0) {
190             schema = elementName.substring(0, len);
191         }
192         name = elementName.substring(len + 1);
193 
194         String composedName = DbTools.composeTableName(connection.getMetaData(), table, ComposeRule.InTableDefinitions, false, false, true);
195         String indexName = DbTools.composeTableName(connection.getMetaData(), "", schema, name, true, ComposeRule.InIndexDefinitions);
196         String sql = String.format("DROP INDEX %s ON %s", indexName, composedName);
197         XStatement statement = null;
198         try {
199             statement = connection.createStatement();
200             statement.execute(sql);
201         } finally {
202             CompHelper.disposeComponent(statement);
203         }
204     }
205 
206     @Override
impl_refresh()207     protected void impl_refresh() {
208         // FIXME
209     }
210 }
211