1   /*
2    * PRELYTIS.
3    * Copyright 2007, PRELYTIS S.A., and individual contributors
4    * as indicated by the @author tags. See the copyright.txt file in the
5    * distribution for a full listing of individual contributors.
6    *
7    * This is free software; you can redistribute it and/or modify it
8    * under the terms of the GNU Lesser General Public License as
9    * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */
22  package org.jdbc4olap.jdbc;
23  
24  import java.sql.ResultSetMetaData;
25  import java.sql.SQLException;
26  import java.sql.Types;
27  import java.util.ArrayList;
28  import java.util.List;
29  import java.util.HashMap;
30  import java.util.logging.Logger;
31  
32  import org.jdbc4olap.xmla.Jdbc4OlapConstants;
33  
34  /**
35   * @author <a href="mailto:fsiberchicot@jdbc4olap.org">Florian SIBERCHICOT</a>
36   * @author Dan Rollo
37   */
38  class OlapResultSetMetaData implements ResultSetMetaData {
39  
40      /**
41       * Create metadata for the given resultset, all column types are set to Types.VARCHAR.
42       *
43       * @param rs          the resultset to which metadata will be added
44       * @param columnNames the names of columns in the resultset
45       */
46      static void setMetaDataStringCols(final OlapResultSet rs, final String[] columnNames) {
47  
48          final int[] colummTypes = createStringColTypesForNames(columnNames);
49  
50          setMetaData(rs, columnNames, colummTypes);
51      }
52  
53      static int[] createStringColTypesForNames(final String[] columnNames) {
54          final int[] colummTypes;
55          if (columnNames == null) {
56              colummTypes = null;
57          } else {
58              colummTypes = new int[columnNames.length];
59              for (int i = 0; i < columnNames.length; i++) {
60                  colummTypes[i] = Types.VARCHAR;
61              }
62          }
63          return colummTypes;
64      }
65  
66      /**
67       * Create metadata for the given resultset.
68       *
69       * @param rs          the resultset to which metadata will be added
70       * @param columnNames the names of columns in the resultset
71       * @param columnTypes the sql type of each column
72       */
73      static void setMetaData(final OlapResultSet rs, final String[] columnNames, final int[] columnTypes) {
74          setMetaData(rs, columnNames, columnTypes, null);
75      }
76      /**
77       * Create metadata for the given resultset.
78       *
79       * @param rs          the resultset to which metadata will be added
80       * @param columnNames the names of columns in the resultset
81       * @param columnTypes the sql type of each column
82       * @param columnLabels the display name of each column
83       */
84      static void setMetaData(final OlapResultSet rs, final String[] columnNames, final int[] columnTypes,
85                              final String[] columnLabels) {
86          final OlapResultSetMetaData md = new OlapResultSetMetaData(rs);
87  
88          if (columnNames != null) {
89  
90              if (columnTypes == null) {
91                  throw new IllegalStateException("Array mismatch: columnNames.length: "
92                          + columnNames.length + ", columnTypes is null");
93              }
94              if (columnNames.length != columnTypes.length) {
95                  throw new IllegalStateException("Array length mismatch: columnNames.length: "
96                          + columnNames.length + ", columnTypes.length: " + columnTypes.length);
97              }
98              if (columnLabels != null && columnNames.length != columnLabels.length) {
99                  throw new IllegalStateException("Array length mismatch: columnNames.length: "
100                         + columnNames.length + ", columnLabels.length: " + columnTypes.length);
101             }
102 
103             for (int i = 0; i < columnNames.length; i++) {
104                 final OlapColumnMetaData cmd = new OlapColumnMetaData();
105                 cmd.setName(columnNames[i]);
106                 cmd.setType(columnTypes[i]);
107                 if (columnLabels != null) {
108                     cmd.setLabel(columnLabels[i]);
109                 }
110                 md.add(cmd);
111             }
112 
113         } else if (columnTypes != null) {
114             throw new IllegalStateException("Array mismatch: columnNames is null, columnTypes.length: " + columnTypes.length);
115         }
116 
117         rs.setMetaData(md);
118     }
119 
120     private final List<OlapColumnMetaData> list;
121     // only intended for debugging
122     private final OlapResultSet owner;
123 
124     OlapResultSetMetaData(final OlapResultSet ownerRS) {
125         this.list = new ArrayList<OlapColumnMetaData>();
126         this.owner = ownerRS;
127     }
128 
129     // only intended for debugging
130     OlapResultSet getOwner() {
131         return owner;
132     }
133 
134     void add(final OlapColumnMetaData column) {
135         list.add(column);
136     }
137 
138     OlapColumnMetaData getColumn(final int column) {
139         return list.get(column - 1);
140     }
141 
142     public String getCatalogName(final int column) throws SQLException {
143         return getColumn(column).getCatalogName();
144     }
145 
146     public String getColumnClassName(final int column) throws SQLException {
147         return getColumn(column).getClassName();
148     }
149 
150     public int getColumnCount() throws SQLException {
151         return list.size();
152     }
153 
154     static final int COL_DISPLAY_SIZE_PAD = 2;
155 
156     public int getColumnDisplaySize(final int column) throws SQLException {
157         if (getColumn(column).getDisplaySize() != 0) {
158             return getColumn(column).getDisplaySize();
159         }
160 
161         final String label = getColumnLabel(column);
162         if (label != null) {
163             return label.length() + COL_DISPLAY_SIZE_PAD;
164         }
165 
166         return 0;
167     }
168 
169     public String getColumnLabel(final int column) throws SQLException {
170         final OlapColumnMetaData columnMD = getColumn(column);
171 
172         final String colLabel;
173         if (columnMD.getLabel() == null) {
174             colLabel = columnMD.getName();
175         } else {
176             colLabel = columnMD.getLabel();
177         }
178         return colLabel;
179     }
180 
181     public String getColumnName(final int column) throws SQLException {
182         return getColumn(column).getName();
183     }
184 
185     public int getColumnType(final int column) throws SQLException {
186         return getColumn(column).getType();
187     }
188 
189 
190     /**
191      * Mapping of java.sql.Types to TypeNames. We may need a more flexible approach?
192      */
193     static final HashMap<Integer, String> TYPE_NAME_MAP = new HashMap<Integer, String>();
194 
195     static {
196         TYPE_NAME_MAP.put(Types.VARCHAR, "VARCHAR");
197         TYPE_NAME_MAP.put(Types.BOOLEAN, "BOOLEAN");
198         TYPE_NAME_MAP.put(Types.INTEGER, "INTEGER");
199         TYPE_NAME_MAP.put(Types.NUMERIC, "NUMERIC");
200     }
201 
202     public String getColumnTypeName(final int column) throws SQLException {
203         if (getColumn(column).getTypeName() != null) {
204             return getColumn(column).getTypeName();
205         }
206 
207         final String typeName = TYPE_NAME_MAP.get(getColumnType(column));
208         if (typeName == null) {
209             Logger log = Logger.getLogger(Jdbc4OlapConstants.JDBC4OLAP_LOG);
210             log.warning("----WARNING: Missing Name in TypeMap for type: " + getColumnType(column)
211                     + "; Catalog: " + getCatalogName(column) + ", Schema: " + getSchemaName(column) + ", Table: " + getTableName(column)
212                     + ", Column: " + getColumnName(column) + ", Type: " + getColumnType(column));
213         }
214         return typeName;
215     }
216 
217     public int getPrecision(final int column) throws SQLException {
218         return getColumn(column).getPrecision();
219     }
220 
221     public int getScale(final int column) throws SQLException {
222         return getColumn(column).getScale();
223     }
224 
225     public String getSchemaName(final int column) throws SQLException {
226         return getColumn(column).getSchemaName();
227     }
228 
229     public String getTableName(final int column) throws SQLException {
230         return getColumn(column).getTableName();
231     }
232 
233     public boolean isAutoIncrement(final int column) throws SQLException {
234         return getColumn(column).isAutoIncrement();
235     }
236 
237     public boolean isCaseSensitive(final int column) throws SQLException {
238         return getColumn(column).isCaseSensitive();
239     }
240 
241     public boolean isCurrency(final int column) throws SQLException {
242         return getColumn(column).isCurrency();
243     }
244 
245     public boolean isDefinitelyWritable(final int column) throws SQLException {
246         return getColumn(column).isDefinitivelyWritable();
247     }
248 
249     public int isNullable(final int column) throws SQLException {
250         return getColumn(column).isNullable();
251     }
252 
253     public boolean isReadOnly(final int column) throws SQLException {
254         return getColumn(column).isReadOnly();
255     }
256 
257     public boolean isSearchable(final int column) throws SQLException {
258         return getColumn(column).isSearchable();
259     }
260 
261     public boolean isSigned(final int column) throws SQLException {
262         return getColumn(column).isSigned();
263     }
264 
265     public boolean isWritable(final int column) throws SQLException {
266         return getColumn(column).isWritable();
267     }
268 }