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.Arrays;
26 import java.util.Map;
27 
28 import org.apache.openoffice.comp.sdbc.dbtools.comphelper.CompHelper;
29 import org.apache.openoffice.comp.sdbc.dbtools.sdbcx.descriptors.SdbcxKeyDescriptor;
30 import org.apache.openoffice.comp.sdbc.dbtools.util.ComposeRule;
31 import org.apache.openoffice.comp.sdbc.dbtools.util.DbTools;
32 import org.apache.openoffice.comp.sdbc.dbtools.util.PropertyIds;
33 
34 import com.sun.star.beans.PropertyVetoException;
35 import com.sun.star.beans.UnknownPropertyException;
36 import com.sun.star.beans.XPropertySet;
37 import com.sun.star.container.ElementExistException;
38 import com.sun.star.container.XIndexAccess;
39 import com.sun.star.container.XNamed;
40 import com.sun.star.lang.IllegalArgumentException;
41 import com.sun.star.lang.IndexOutOfBoundsException;
42 import com.sun.star.lang.WrappedTargetException;
43 import com.sun.star.sdbc.KeyRule;
44 import com.sun.star.sdbc.SQLException;
45 import com.sun.star.sdbc.XConnection;
46 import com.sun.star.sdbc.XResultSet;
47 import com.sun.star.sdbc.XRow;
48 import com.sun.star.sdbc.XStatement;
49 import com.sun.star.sdbcx.KeyType;
50 import com.sun.star.sdbcx.XColumnsSupplier;
51 import com.sun.star.uno.AnyConverter;
52 import com.sun.star.uno.UnoRuntime;
53 
54 public class OKeyContainer extends OContainer {
55     private OTable table;
56     private Map<String,OKey> keys;
57 
OKeyContainer(Object lock, boolean isCaseSensitive, Map<String,OKey> keys, OTable table)58     public OKeyContainer(Object lock, boolean isCaseSensitive, Map<String,OKey> keys, OTable table) throws ElementExistException {
59         super(lock, isCaseSensitive, Arrays.asList(keys.keySet().toArray(new String[keys.size()])));
60         System.out.println("Keys.size()=" + keys.size());
61         for (Map.Entry<String,OKey> entry : keys.entrySet()) {
62             System.out.println(entry.getKey() + " => " + entry.getValue().referencedTable);
63             XIndexAccess cols = UnoRuntime.queryInterface(XIndexAccess.class, entry.getValue().getColumns());
64             try {
65                 System.out.println("" + cols.getCount() + " columns:");
66                 for (int i =0; i < cols.getCount(); i++) {
67                     System.out.println("  " + AnyConverter.toObject(XNamed.class, cols.getByIndex(i)).getName());
68                 }
69             } catch (WrappedTargetException wrappedTargetException) {
70                 wrappedTargetException.printStackTrace();
71             } catch (IndexOutOfBoundsException indexOutOfBoundsException) {
72                 indexOutOfBoundsException.printStackTrace();
73             } catch (IllegalArgumentException argumentException) {
74                 argumentException.printStackTrace();
75             }
76         }
77         this.keys = keys;
78         this.table = table;
79     }
80 
81     @Override
createDescriptor()82     protected XPropertySet createDescriptor() {
83         return new SdbcxKeyDescriptor(isCaseSensitive());
84     }
85 
86     @Override
createObject(String name)87     protected XPropertySet createObject(String name) throws SQLException {
88         OKey ret = null;
89 
90         if (!name.isEmpty()) {
91             ret = keys.get(name);
92         }
93 
94         if (ret == null) { // we have a primary key with a system name
95             // FIXME: so why was this exactly the same?
96             ret = keys.get(name);
97         }
98 
99         return ret;
100     }
101 
102     @Override
impl_refresh()103     protected void impl_refresh() {
104         //throw new NotImplementedException("");
105     }
106 
107     @Override
appendObject(String _rForName, XPropertySet descriptor)108     protected XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException {
109         XConnection connection = table.getConnection();
110         if (connection == null) {
111             return null;
112         }
113         try {
114             int keyType = AnyConverter.toInt(descriptor.getPropertyValue(PropertyIds.TYPE.name));
115             int updateRule = 0;
116             int deleteRule = 0;
117             String referencedName = "";
118             if (keyType == KeyType.FOREIGN) {
119                 referencedName = AnyConverter.toString(descriptor.getPropertyValue(PropertyIds.UPDATERULE.name));
120                 updateRule = AnyConverter.toInt(descriptor.getPropertyValue(PropertyIds.UPDATERULE.name));
121                 deleteRule = AnyConverter.toInt(descriptor.getPropertyValue(PropertyIds.DELETERULE.name));
122             }
123 
124             String quote = connection.getMetaData().getIdentifierQuoteString();
125             String tableName = DbTools.composeTableName(connection.getMetaData(), table, ComposeRule.InTableDefinitions, false, false, true);
126 
127             String keyTypeString;
128             if (keyType == KeyType.PRIMARY) {
129                 keyTypeString = "PRIMARY KEY";
130             } else if (keyType == KeyType.FOREIGN) {
131                 keyTypeString = "FOREIGN KEY";
132             } else {
133                 throw new SQLException();
134             }
135 
136             StringBuilder columnsText = new StringBuilder();
137             XColumnsSupplier columnsSupplier = UnoRuntime.queryInterface(XColumnsSupplier.class, descriptor);
138             XIndexAccess columns = UnoRuntime.queryInterface(XIndexAccess.class, columnsSupplier.getColumns());
139             String separator = "";
140             for (int i = 0; i < columns.getCount(); i++) {
141                 columnsText.append(separator);
142                 separator = ",";
143                 XPropertySet columnProperties = AnyConverter.toObject(XPropertySet.class, columns.getByIndex(i));
144                 columnsText.append(DbTools.quoteName(quote, AnyConverter.toString(columnProperties.getPropertyValue(PropertyIds.NAME.name))));
145             }
146 
147             String sql = String.format("ALTER TABLE %s ADD %s (%s)", tableName, keyTypeString, columnsText.toString());
148 
149             if (keyType == KeyType.FOREIGN) {
150                 String quotedTableName = DbTools.quoteTableName(connection.getMetaData(), referencedName, ComposeRule.InTableDefinitions);
151                 StringBuilder relatedColumns = new StringBuilder();
152                 separator = "";
153                 for (int i = 0; i < columns.getCount(); i++) {
154                     relatedColumns.append(separator);
155                     separator = ",";
156                     XPropertySet columnProperties = AnyConverter.toObject(XPropertySet.class, columns.getByIndex(i));
157                     relatedColumns.append(DbTools.quoteName(quote, AnyConverter.toString(columnProperties.getPropertyValue(PropertyIds.RELATEDCOLUMN.name))));
158                 }
159                 sql += String.format(" REFERENCES %s (%s)%s%s", quotedTableName, relatedColumns.toString(),
160                         getKeyRuleString(true, updateRule), getKeyRuleString(false, deleteRule));
161             }
162             XStatement statement = null;
163             try {
164                 statement = connection.createStatement();
165                 statement.execute(sql);
166             } finally {
167                 CompHelper.disposeComponent(statement);
168             }
169 
170             // find the name which the database gave the new key
171             String newName = _rForName;
172             try {
173                 String schema = AnyConverter.toString(this.table.getPropertyValue(PropertyIds.SCHEMANAME.name));
174                 String table = AnyConverter.toString(this.table.getPropertyValue(PropertyIds.TABLENAME.name));
175                 XResultSet results = null;
176                 try {
177                     final int column;
178                     if (keyType == KeyType.FOREIGN) {
179                         results = connection.getMetaData().getImportedKeys(this.table.getPropertyValue(PropertyIds.CATALOGNAME.name), schema, table);
180                         column = 12;
181                     } else {
182                         results = connection.getMetaData().getPrimaryKeys(this.table.getPropertyValue(PropertyIds.CATALOGNAME.name), schema, table);
183                         column = 6;
184                     }
185                     if (results != null) {
186                         XRow row = UnoRuntime.queryInterface(XRow.class, results);
187                         while (results.next()) {
188                             String name = row.getString(column);
189                             if (!hasByName(name)) { // this name wasn't inserted yet so it must be the new one
190                                 descriptor.setPropertyValue(PropertyIds.NAME.name, name);
191                                 newName = name;
192                                 break;
193                             }
194                         }
195                     }
196                 } finally {
197                     CompHelper.disposeComponent(results);
198                 }
199             } catch (SQLException sqlException) {
200             }
201             keys.put(newName, new OKey(newName, isCaseSensitive(), referencedName, keyType, updateRule, deleteRule, new ArrayList<String>(), table));
202             return createObject(newName);
203         } catch (WrappedTargetException wrappedTargetException) {
204         } catch (UnknownPropertyException unknownPropertyException) {
205         } catch (IllegalArgumentException illegalArgumentException) {
206         } catch (IndexOutOfBoundsException indexOutOfBoundsException) {
207         } catch (PropertyVetoException propertyVetoException) {
208         } catch (ElementExistException elementExistException) {
209         }
210         return null;
211     }
212 
getKeyRuleString(boolean isUpdate, int rule)213     protected String getKeyRuleString(boolean isUpdate, int rule) {
214         String keyRule = "";
215         switch (rule) {
216         case KeyRule.CASCADE:
217             keyRule = isUpdate ? " ON UPDATE CASCADE " : " ON DELETE CASCADE ";
218             break;
219         case KeyRule.RESTRICT:
220             keyRule = isUpdate ? " ON UPDATE RESTRICT " : " ON DELETE RESTRICT ";
221             break;
222         case KeyRule.SET_NULL:
223             keyRule = isUpdate ? " ON UPDATE SET NULL " : " ON DELETE SET NULL ";
224             break;
225         case KeyRule.SET_DEFAULT:
226             keyRule = isUpdate ? " ON UPDATE SET DEFAULT " : " ON DELETE SET DEFAULT ";
227             break;
228         }
229         return keyRule;
230     }
231 
232     @Override
dropObject(int index, String name)233     protected void dropObject(int index, String name) throws SQLException {
234         XConnection connection = table.getConnection();
235         if (connection == null) {
236             return;
237         }
238         try {
239             XPropertySet key = AnyConverter.toObject(XPropertySet.class, getObject(index));
240             String tableName = DbTools.composeTableName(connection.getMetaData(), table,
241                     ComposeRule.InTableDefinitions, false, false, true);
242             final int keyType;
243             if (key != null) {
244                 keyType = AnyConverter.toInt(key.getPropertyValue(PropertyIds.TYPE.name));
245             } else {
246                 keyType = KeyType.PRIMARY;
247             }
248             final String sql;
249             if (keyType == KeyType.PRIMARY) {
250                 sql = String.format("ALTER TABLE %s DROP PRIMARY KEY", tableName);
251             } else {
252                 sql = String.format("ALTER TABLE %s %s %s", tableName, getDropForeignKey(),
253                         DbTools.quoteName(connection.getMetaData().getIdentifierQuoteString(), name));
254             }
255             XStatement statement = null;
256             try {
257                 statement = connection.createStatement();
258                 statement.execute(sql);
259             } finally {
260                 CompHelper.disposeComponent(statement);
261             }
262         } catch (IllegalArgumentException illegalArgumentException) {
263 
264         } catch (WrappedTargetException wrappedTargetException) {
265         } catch (UnknownPropertyException unknownPropertyException) {
266         }
267     }
268 
getDropForeignKey()269     public String getDropForeignKey() {
270         return "DROP CONSTRAINT";
271     }
272 }
273