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.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 
29 import org.apache.openoffice.comp.sdbc.dbtools.comphelper.CompHelper;
30 import org.apache.openoffice.comp.sdbc.dbtools.sdbcx.SqlTableHelper.ColumnDescription;
31 import org.apache.openoffice.comp.sdbc.dbtools.sdbcx.descriptors.SdbcxColumnDescriptor;
32 import org.apache.openoffice.comp.sdbc.dbtools.util.ComposeRule;
33 import org.apache.openoffice.comp.sdbc.dbtools.util.DbTools;
34 import org.apache.openoffice.comp.sdbc.dbtools.util.Osl;
35 
36 import com.sun.star.beans.XPropertySet;
37 import com.sun.star.container.ElementExistException;
38 import com.sun.star.container.XNameAccess;
39 import com.sun.star.sdbc.ColumnValue;
40 import com.sun.star.sdbc.DataType;
41 import com.sun.star.sdbc.SQLException;
42 import com.sun.star.sdbc.XDatabaseMetaData;
43 import com.sun.star.sdbc.XStatement;
44 import com.sun.star.uno.UnoRuntime;
45 
46 public class OColumnContainer extends OContainer {
47     private OTable table;
48     private XDatabaseMetaData metadata;
49     private Map<String,ColumnDescription> columnDescriptions = new HashMap<>();
50     private Map<String,ExtraColumnInfo> extraColumnInfo = new HashMap<>();
51 
52     /// The XDatabaseMetaData.getColumns() data stored in columnDescriptions doesn't provide everything we need, so this class stores the rest.
53     public static class ExtraColumnInfo {
54         public boolean isAutoIncrement;
55         public boolean isCurrency;
56         public int dataType;
57     }
58 
OColumnContainer(Object lock, boolean isCaseSensitive, List<ColumnDescription> columnDescriptions, OTable table, XDatabaseMetaData metadata)59     public OColumnContainer(Object lock, boolean isCaseSensitive, List<ColumnDescription> columnDescriptions, OTable table, XDatabaseMetaData metadata)
60             throws ElementExistException {
61         super(lock, isCaseSensitive, toColumnNames(columnDescriptions));
62         this.table = table;
63         this.metadata = metadata;
64         for (ColumnDescription columnDescription : columnDescriptions) {
65             this.columnDescriptions.put(columnDescription.columnName, columnDescription);
66         }
67     }
68 
toColumnNames(List<ColumnDescription> columns)69     private static List<String> toColumnNames(List<ColumnDescription> columns) {
70         List<String> columnNames = new ArrayList<>(columns.size());
71         for (ColumnDescription columnDescription : columns) {
72             columnNames.add(columnDescription.columnName);
73         }
74         return columnNames;
75     }
76 
77     @Override
createObject(String name)78     protected XPropertySet createObject(String name) throws SQLException {
79         boolean queryInfo = true;
80         boolean isAutoIncrement = false;
81         boolean isCurrency = false;
82         int dataType = DataType.OTHER;
83 
84         ColumnDescription columnDescription = columnDescriptions.get(name);
85         if (columnDescription == null) {
86             // could be a recently added column. Refresh:
87             List<ColumnDescription> newColumns = new SqlTableHelper().readColumns(metadata, table.catalogName, table.schemaName, table.getName());
88             for (ColumnDescription newColumnDescription : newColumns) {
89                 if (newColumnDescription.columnName.equals(name)) {
90                     columnDescriptions.put(name, newColumnDescription);
91                     break;
92                 }
93             }
94             columnDescription = columnDescriptions.get(name);
95         }
96         if (columnDescription == null) {
97             throw new SQLException("No column " + name + " found");
98         }
99 
100         ExtraColumnInfo columnInfo = extraColumnInfo.get(name);
101         if (columnInfo == null) {
102             String composedName = DbTools.composeTableNameForSelect(metadata.getConnection(), table);
103             extraColumnInfo = DbTools.collectColumnInformation(metadata.getConnection(), composedName, "*");
104             columnInfo = extraColumnInfo.get(name);
105         }
106         if (columnInfo != null) {
107             queryInfo = false;
108             isAutoIncrement = columnInfo.isAutoIncrement;
109             isCurrency = columnInfo.isCurrency;
110             dataType = columnInfo.dataType;
111         }
112 
113         XNameAccess primaryKeyColumns = DbTools.getPrimaryKeyColumns(UnoRuntime.queryInterface(XPropertySet.class, table));
114         int nullable = columnDescription.nullable;
115         if (nullable != ColumnValue.NO_NULLS && primaryKeyColumns != null && primaryKeyColumns.hasByName(name)) {
116             nullable = ColumnValue.NO_NULLS;
117         }
118         return new OColumn(name, columnDescription.typeName, columnDescription.defaultValue, columnDescription.remarks,
119                 nullable, columnDescription.columnSize, columnDescription.decimalDigits, columnDescription.type,
120                 isAutoIncrement, false, isCurrency, isCaseSensitive());
121     }
122 
123     @Override
createDescriptor()124     protected XPropertySet createDescriptor() {
125         return new SdbcxColumnDescriptor(isCaseSensitive());
126     }
127 
128     @Override
impl_refresh()129     protected void impl_refresh() {
130         extraColumnInfo.clear();
131         // FIXME: won't help
132         table.refreshColumns();
133     }
134 
135     @Override
appendObject(String _rForName, XPropertySet descriptor)136     protected XPropertySet appendObject(String _rForName, XPropertySet descriptor) throws SQLException {
137         if (table == null) {
138             return cloneDescriptor(descriptor);
139         }
140         String sql = String.format("ALTER TABLE %s ADD %s",
141                 DbTools.composeTableName(metadata, table, ComposeRule.InTableDefinitions, false, false, true),
142                 DbTools.createStandardColumnPart(descriptor, table.getConnection(), null, table.getTypeCreatePattern()));
143         XStatement statement = null;
144         try {
145             statement = table.getConnection().createStatement();
146             statement.execute(sql);
147         } finally {
148             CompHelper.disposeComponent(statement);
149         }
150         return createObject(_rForName);
151     }
152 
153     @Override
dropObject(int index, String name)154     protected void dropObject(int index, String name) throws SQLException {
155         Osl.ensure(table, "Table is null!");
156         if (table == null) {
157             return;
158         }
159         String quote = metadata.getIdentifierQuoteString();
160         String sql = String.format("ALTER TABLE %s DROP %s",
161                 DbTools.composeTableName(metadata, table, ComposeRule.InTableDefinitions, false, false, true),
162                 DbTools.quoteName(quote, name));
163         XStatement statement = null;
164         try {
165             statement = table.getConnection().createStatement();
166             statement.execute(sql);
167         } finally {
168             CompHelper.disposeComponent(statement);
169         }
170     }
171 }
172