001: /*
002:
003: Derby - Class org.apache.derby.client.am.ColumnMetaData
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.client.am;
023:
024: import java.sql.SQLException;
025:
026: import org.apache.derby.iapi.reference.DRDAConstants;
027: import org.apache.derby.iapi.reference.JDBC30Translation;
028: import org.apache.derby.shared.common.reference.SQLState;
029:
030: // Under JDBC 2, we must new up our parameter meta data as column meta data instances
031: // Once we move to JDK 1.4 pre-req, create a ResultSetMetaData class and make this class abstract
032:
033: public class ColumnMetaData implements java.sql.ResultSetMetaData {
034:
035: public int columns_;
036:
037: public boolean[] nullable_;
038:
039: // Although this is describe information, it is tagged transient for now becuase it is not currently used.
040: transient public int[] singleMixedByteOrDouble_; // 1 means single, 2 means double, 3 means mixed-byte, 0 not applicable
041:
042: // All of the following state data comes from the SQLDA reply.
043:
044: //Data from SQLDHGRP
045: public short sqldHold_;
046: public short sqldReturn_;
047: public short sqldScroll_;
048: public short sqldSensitive_;
049: public short sqldFcode_;
050: public short sqldKeytype_;
051: public String sqldRdbnam_; // catalog name, not used by driver, placeholder only
052: public String sqldSchema_; // schema name, not used by driver, placeholder only
053:
054: //data comes from SQLDAGRP
055: public int[] sqlPrecision_; // adjusted sqllen;
056: public int[] sqlScale_;
057: public long[] sqlLength_; // This is maximum length for varchar fields
058: // These are the derby sql types, for use only by ResultSetMetaData, other code should use jdbcTypes_.
059: // sqlTypes_ is currently not set for input column meta data.
060: public int[] sqlType_;
061: public int[] sqlCcsid_;
062:
063: // With the exception of sqlNames_ and sqlxParmmode_, the following members are only allocated when needed
064:
065: //Data from SQLDOPTGRP
066: public String[] sqlName_; // column name, pre-allocated
067: public String[] sqlLabel_; // column label
068: public short[] sqlUnnamed_;
069: public String[] sqlComment_;
070:
071: //Data from SQLDXGRP
072: public short[] sqlxKeymem_;
073: public short[] sqlxGenerated_;
074: public short[] sqlxParmmode_; // pre-allocated
075: public String[] sqlxCorname_;
076: public String[] sqlxName_;
077: public String[] sqlxBasename_; // table name
078: public int[] sqlxUpdatable_;
079: public String[] sqlxSchema_; // schema name
080: public String[] sqlxRdbnam_; // catalog name
081:
082: //-----------------------------transient state--------------------------------
083:
084: // For performance only, not part of logical model.
085: public transient int[][] protocolTypesCache_ = null;
086: public transient java.util.Hashtable protocolTypeToOverrideLidMapping_ = null;
087: public transient java.util.ArrayList mddOverrideArray_ = null;
088:
089: public transient int[] types_;
090: public transient int[] clientParamtertype_;
091:
092: public transient LogWriter logWriter_;
093:
094: // only set on execute replies, this is not describe information.
095: // only used for result set meta data.
096:
097: public transient int resultSetConcurrency_;
098:
099: transient private java.util.Hashtable columnNameToIndexCache_ = null;
100:
101: transient private boolean statementClosed_ = false;
102:
103: void markClosed() {
104: statementClosed_ = true;
105: nullDataForGC();
106: }
107:
108: void checkForClosedStatement() throws SqlException {
109: // agent_.checkForDeferredExceptions();
110: if (statementClosed_) {
111: throw new SqlException(logWriter_, new ClientMessageId(
112: SQLState.LANG_STATEMENT_CLOSED_NO_REASON));
113: }
114: }
115:
116: //---------------------navigational members-----------------------------------
117:
118: //---------------------constructors/finalizer---------------------------------
119:
120: // Called by NETColumnMetaData constructor before #columns is parsed out yet.
121: public ColumnMetaData(LogWriter logWriter) {
122: logWriter_ = logWriter;
123: }
124:
125: // For creating column meta data when describe input is not available.
126: // The upper bound that is passed in is determined by counting the number of parameter markers.
127: // Called by PreparedStatement.flowPrepareStatement() and flowDescribeInputOutput()
128: // only when describe input is not available.
129: public ColumnMetaData(LogWriter logWriter, int upperBound) {
130: logWriter_ = logWriter;
131: initializeCache(upperBound);
132: }
133:
134: public void initializeCache(int upperBound) {
135: columns_ = upperBound;
136: nullable_ = new boolean[upperBound];
137: types_ = new int[upperBound];
138: clientParamtertype_ = new int[upperBound];
139: singleMixedByteOrDouble_ = new int[upperBound]; // 1 means single, 2 means double, 3 means mixed-byte, 0 not applicable
140:
141: sqlPrecision_ = new int[upperBound];
142: sqlScale_ = new int[upperBound];
143: sqlLength_ = new long[upperBound];
144: sqlType_ = new int[upperBound];
145: sqlCcsid_ = new int[upperBound];
146:
147: sqlName_ = new String[upperBound];
148: sqlxParmmode_ = new short[upperBound];
149: }
150:
151: protected void finalize() throws java.lang.Throwable {
152: super .finalize();
153: }
154:
155: //--------------------Abstract material layer call-down methods-----------------
156:
157: //------------------material layer event callback methods-----------------------
158:
159: // ---------------------------jdbc 1------------------------------------------
160:
161: public int getColumnCount() throws SQLException {
162: try {
163: checkForClosedStatement();
164: return columns_;
165: } catch (SqlException e) {
166: throw e.getSQLException();
167: }
168: }
169:
170: public boolean isAutoIncrement(int column) throws SQLException {
171: try {
172: checkForClosedStatement();
173: checkForValidColumnIndex(column);
174: return false;
175: } catch (SqlException e) {
176: throw e.getSQLException();
177: }
178: }
179:
180: public boolean isCaseSensitive(int column) throws SQLException {
181: try {
182: checkForClosedStatement();
183: checkForValidColumnIndex(column);
184: //return true if the SQLTYPE is CHAR, VARCHAR, LOGVARCHAR or CLOB
185: int type = types_[column - 1];
186: return type == Types.CHAR || type == Types.VARCHAR
187: || type == Types.LONGVARCHAR || type == Types.CLOB;
188: } catch (SqlException e) {
189: throw e.getSQLException();
190: }
191: }
192:
193: // all searchable except distinct
194: public boolean isSearchable(int column) throws SQLException {
195: try {
196: checkForClosedStatement();
197: checkForValidColumnIndex(column);
198: return true;
199: } catch (SqlException e) {
200: throw e.getSQLException();
201: }
202: }
203:
204: public boolean isCurrency(int column) throws SQLException {
205: try {
206: checkForClosedStatement();
207: checkForValidColumnIndex(column);
208: return false;
209: } catch (SqlException e) {
210: throw e.getSQLException();
211: }
212: }
213:
214: public int isNullable(int column) throws SQLException {
215: try {
216: checkForClosedStatement();
217: checkForValidColumnIndex(column);
218: if (nullable_[column - 1]) {
219: return java.sql.ResultSetMetaData.columnNullable;
220: } else {
221: return java.sql.ResultSetMetaData.columnNoNulls;
222: }
223: } catch (SqlException e) {
224: throw e.getSQLException();
225: }
226: }
227:
228: public boolean isSigned(int column) throws SQLException {
229: try {
230: checkForClosedStatement();
231: checkForValidColumnIndex(column);
232: //return true only if the SQLType is SMALLINT, INT, BIGINT, FLOAT, REAL, DOUBLE, NUMERIC OR DECIMAL
233: int type = types_[column - 1];
234: return type == Types.SMALLINT || type == Types.INTEGER
235: || type == Types.BIGINT
236: || type == java.sql.Types.FLOAT
237: || type == Types.REAL || type == Types.DOUBLE
238: || type == java.sql.Types.NUMERIC
239: || type == Types.DECIMAL;
240: } catch (SqlException e) {
241: throw e.getSQLException();
242: }
243: }
244:
245: public int getColumnDisplaySize(int column) throws SQLException {
246: try {
247: checkForClosedStatement();
248: checkForValidColumnIndex(column);
249: int jdbcType = types_[column - 1];
250: switch (jdbcType) {
251: case Types.INTEGER:
252: return 11;
253: case Types.SMALLINT:
254: return 6;
255: case Types.BIGINT:
256: return 20;
257: case Types.REAL:
258: return 13;
259: case Types.DOUBLE:
260: case java.sql.Types.FLOAT:
261: return 22;
262: case Types.DECIMAL:
263: case java.sql.Types.NUMERIC:
264: // There are 3 possible cases with respect to finding the correct max width for DECIMAL type.
265: // 1. If scale = 0, only sign should be added to precision.
266: // 2. scale = precision, 3 should be added to precision for sign, decimal and an additional char '0'.
267: // 3. precision > scale > 0, 2 should be added to precision for sign and decimal.
268: int scale = getScale(column);
269: int precision = getPrecision(column);
270: return (scale == 0) ? (precision + 1)
271: : ((scale == precision) ? (precision + 3)
272: : (precision + 2));
273: case Types.CHAR:
274: case Types.VARCHAR:
275: case Types.LONGVARCHAR:
276: case Types.CLOB:
277: return (int) sqlLength_[column - 1];
278: case Types.DATE:
279: return 10;
280: case Types.TIME:
281: return 8;
282: case Types.TIMESTAMP:
283: return 26;
284: case Types.BINARY:
285: case Types.VARBINARY:
286: case Types.LONGVARBINARY:
287: case Types.BLOB:
288: return (int) (2 * sqlLength_[column - 1]); // eg. "FF" represents just one byte
289: default:
290: throw new SqlException(logWriter_, new ClientMessageId(
291: SQLState.UNSUPPORTED_TYPE));
292: }
293: } catch (SqlException e) {
294: throw e.getSQLException();
295: }
296: }
297:
298: public String getColumnLabel(int column) throws SQLException {
299: try {
300: checkForClosedStatement();
301: checkForValidColumnIndex(column);
302: // return labels if label is turned on, otherwise, return column name
303: if (sqlLabel_ != null && sqlLabel_[column - 1] != null) {
304: return sqlLabel_[column - 1];
305: }
306: if (sqlName_ == null || sqlName_[column - 1] == null) {
307: assignColumnName(column);
308: }
309: return sqlName_[column - 1];
310: } catch (SqlException e) {
311: throw e.getSQLException();
312: }
313: }
314:
315: public String getColumnName(int column) throws SQLException {
316: try {
317: checkForClosedStatement();
318: checkForValidColumnIndex(column);
319: // The Javadoc and Jdbc book explicitly state that the empty string ("") is returned if "not applicable"
320: // for the following methods:
321: // getSchemaName()
322: // getTableName()
323: // getCatalogName()
324: // Since the empty string is a valid string and is not really a proper table name, schema name, or catalog name,
325: // we're not sure why the empty string was chosen over null, except possibly to be friendly to lazy jdbc apps
326: // that may not be checking for nulls, thereby minimizing potential NPE's.
327: // By induction, it would make sense to return the empty string when column name is not available/applicable.
328: //
329: // The JDBC specification contains blanket statements about SQL compliance levels,
330: // so elaboration within the JDBC specification is often bypassed.
331: // Personally, I would prefer to return Java null for all the not-applicable cases,
332: // but it appears that we have precedent for the empty ("") string.
333: //
334: // We assume a straightforward induction from jdbc spec that the column name be "" (empty)
335: // in preference to null or NULL for the not applicable case.
336: //
337: if (sqlName_ == null || sqlName_[column - 1] == null) {
338: assignColumnName(column);
339: }
340: return sqlName_[column - 1];
341: } catch (SqlException e) {
342: throw e.getSQLException();
343: }
344: }
345:
346: public String getSchemaName(int column) throws SQLException {
347: try {
348: checkForClosedStatement();
349: checkForValidColumnIndex(column);
350: if (sqlxSchema_ == null || sqlxSchema_[column - 1] == null) {
351: return ""; // Per jdbc spec
352: }
353: return sqlxSchema_[column - 1];
354: } catch (SqlException e) {
355: throw e.getSQLException();
356: }
357: }
358:
359: public int getPrecision(int column) throws SQLException {
360: try {
361: checkForClosedStatement();
362: checkForValidColumnIndex(column);
363: int jdbcType = types_[column - 1];
364:
365: switch (jdbcType) {
366: case java.sql.Types.NUMERIC:
367: case Types.DECIMAL:
368: return sqlPrecision_[column - 1];
369: case Types.SMALLINT:
370: return 5;
371: case Types.INTEGER:
372: return 10;
373: case Types.BIGINT:
374: return 19;
375: case java.sql.Types.FLOAT:
376: return 15;
377: case Types.REAL:
378: return 7; // This is the number of signed digits for IEEE float with mantissa 24, ie. 2^24
379: case Types.DOUBLE:
380: return 15; // This is the number of signed digits for IEEE float with mantissa 24, ie. 2^24
381: case Types.CHAR:
382: case Types.VARCHAR:
383: case Types.LONGVARCHAR:
384: case Types.BINARY:
385: case Types.VARBINARY:
386: case Types.LONGVARBINARY:
387: case Types.CLOB:
388: case Types.BLOB:
389: return (int) sqlLength_[column - 1];
390: case Types.DATE:
391: return 10;
392: case Types.TIME:
393: return 8;
394: case Types.TIMESTAMP:
395: return 26;
396: default:
397: throw new SqlException(logWriter_, new ClientMessageId(
398: SQLState.UNSUPPORTED_TYPE));
399: }
400: } catch (SqlException e) {
401: throw e.getSQLException();
402: }
403: }
404:
405: public int getScale(int column) throws SQLException {
406: try {
407: checkForClosedStatement();
408: checkForValidColumnIndex(column);
409:
410: // We get the scale from the SQLDA as returned by DERBY, but DERBY does not return the ANSI-defined
411: // value of scale 6 for TIMESTAMP.
412: //
413: // The JDBC drivers should hardcode this info as a short/near term solution.
414: //
415: if (types_[column - 1] == Types.TIMESTAMP) {
416: return 6;
417: }
418:
419: return sqlScale_[column - 1];
420: } catch (SqlException e) {
421: throw e.getSQLException();
422: }
423: }
424:
425: public String getTableName(int column) throws SQLException {
426: try {
427: checkForClosedStatement();
428: checkForValidColumnIndex(column);
429: if (sqlxBasename_ == null
430: || sqlxBasename_[column - 1] == null) {
431: return ""; // Per jdbc spec
432: }
433: return sqlxBasename_[column - 1];
434: } catch (SqlException e) {
435: throw e.getSQLException();
436: }
437: }
438:
439: /**
440: * What's a column's table's catalog name?
441: *
442: * @param column the first column is 1, the second is 2, ...
443: *
444: * @return column name or "" if not applicable.
445: *
446: * @throws SQLException thrown on failure
447: */
448: public String getCatalogName(int column) throws SQLException {
449: try {
450: checkForClosedStatement();
451: checkForValidColumnIndex(column);
452: return "";
453: } catch (SqlException e) {
454: throw e.getSQLException();
455: }
456: }
457:
458: public int getColumnType(int column) throws SQLException {
459: try {
460: checkForClosedStatement();
461: checkForValidColumnIndex(column);
462:
463: return types_[column - 1];
464: } catch (SqlException e) {
465: throw e.getSQLException();
466: }
467: }
468:
469: public String getColumnTypeName(int column) throws SQLException {
470: try {
471: checkForClosedStatement();
472: checkForValidColumnIndex(column);
473:
474: int jdbcType = types_[column - 1];
475: // So these all come back zero for downlevel servers in PROTOCOL.
476: // John is going to write some code to construct the sqlType_ array
477: // based on the protocol types from the query descriptor.
478: int sqlType = sqlType_[column - 1];
479:
480: switch (sqlType) {
481: case DRDAConstants.DB2_SQLTYPE_DATE:
482: case DRDAConstants.DB2_SQLTYPE_NDATE:
483: return "DATE";
484: case DRDAConstants.DB2_SQLTYPE_TIME:
485: case DRDAConstants.DB2_SQLTYPE_NTIME:
486: return "TIME";
487: case DRDAConstants.DB2_SQLTYPE_TIMESTAMP:
488: case DRDAConstants.DB2_SQLTYPE_NTIMESTAMP:
489: return "TIMESTAMP";
490: case DRDAConstants.DB2_SQLTYPE_BLOB:
491: case DRDAConstants.DB2_SQLTYPE_NBLOB:
492: return "BLOB";
493: case DRDAConstants.DB2_SQLTYPE_CLOB:
494: case DRDAConstants.DB2_SQLTYPE_NCLOB:
495: return "CLOB";
496: case DRDAConstants.DB2_SQLTYPE_VARCHAR:
497: case DRDAConstants.DB2_SQLTYPE_NVARCHAR:
498: if (jdbcType == Types.VARBINARY) {
499: return "VARCHAR FOR BIT DATA";
500: } else {
501: return "VARCHAR";
502: }
503: case DRDAConstants.DB2_SQLTYPE_CHAR:
504: case DRDAConstants.DB2_SQLTYPE_NCHAR:
505: if (jdbcType == Types.BINARY) {
506: return "CHAR FOR BIT DATA";
507: } else {
508: return "CHAR";
509: }
510: case DRDAConstants.DB2_SQLTYPE_LONG:
511: case DRDAConstants.DB2_SQLTYPE_NLONG:
512: if (jdbcType == Types.LONGVARBINARY) {
513: return "LONG VARCHAR FOR BIT DATA";
514: } else {
515: return "LONG VARCHAR";
516: }
517: case DRDAConstants.DB2_SQLTYPE_CSTR:
518: case DRDAConstants.DB2_SQLTYPE_NCSTR:
519: return "SBCS";
520: case DRDAConstants.DB2_SQLTYPE_FLOAT:
521: case DRDAConstants.DB2_SQLTYPE_NFLOAT:
522: if (jdbcType == Types.DOUBLE) {
523: return "DOUBLE";
524: }
525: if (jdbcType == Types.REAL) {
526: return "REAL";
527: }
528: case DRDAConstants.DB2_SQLTYPE_DECIMAL:
529: case DRDAConstants.DB2_SQLTYPE_NDECIMAL:
530: return "DECIMAL";
531: case DRDAConstants.DB2_SQLTYPE_BIGINT:
532: case DRDAConstants.DB2_SQLTYPE_NBIGINT:
533: return "BIGINT";
534: case DRDAConstants.DB2_SQLTYPE_INTEGER:
535: case DRDAConstants.DB2_SQLTYPE_NINTEGER:
536: return "INTEGER";
537: case DRDAConstants.DB2_SQLTYPE_SMALL:
538: case DRDAConstants.DB2_SQLTYPE_NSMALL:
539: return "SMALLINT";
540: case DRDAConstants.DB2_SQLTYPE_NUMERIC:
541: case DRDAConstants.DB2_SQLTYPE_NNUMERIC:
542: return "NUMERIC";
543: default:
544: throw new SqlException(logWriter_, new ClientMessageId(
545: SQLState.UNSUPPORTED_TYPE));
546: }
547: } catch (SqlException e) {
548: throw e.getSQLException();
549: }
550: }
551:
552: public boolean isReadOnly(int column) throws SQLException {
553: try {
554: checkForClosedStatement();
555: checkForValidColumnIndex(column);
556: if (sqlxUpdatable_ == null) {
557: return (resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY); // If no extended describe, return resultSet's concurrecnty
558: }
559: return sqlxUpdatable_[column - 1] == 0; // PROTOCOL 0 means not updatable, 1 means updatable
560: } catch (SqlException e) {
561: throw e.getSQLException();
562: }
563: }
564:
565: public boolean isWritable(int column) throws SQLException {
566: try {
567: checkForClosedStatement();
568: checkForValidColumnIndex(column);
569: if (sqlxUpdatable_ == null) {
570: return (resultSetConcurrency_ == java.sql.ResultSet.CONCUR_UPDATABLE); // If no extended describe, return resultSet's concurrency
571: }
572: return sqlxUpdatable_[column - 1] == 1; // PROTOCOL 0 means not updatable, 1 means updatable
573: } catch (SqlException e) {
574: throw e.getSQLException();
575: }
576: }
577:
578: public boolean isDefinitelyWritable(int column) throws SQLException {
579: try {
580: checkForClosedStatement();
581: checkForValidColumnIndex(column);
582: if (sqlxUpdatable_ == null) {
583: return false;
584: }
585: return sqlxUpdatable_[column - 1] == 1; // PROTOCOL 0 means not updatable, 1 means updatable
586: } catch (SqlException e) {
587: throw e.getSQLException();
588: }
589: }
590:
591: //--------------------------jdbc 2.0-----------------------------------
592:
593: public String getColumnClassName(int column) throws SQLException {
594: try {
595: checkForClosedStatement();
596: checkForValidColumnIndex(column);
597:
598: int jdbcType = types_[column - 1];
599: switch (jdbcType) {
600: case java.sql.Types.BIT:
601: return "java.lang.Boolean";
602: case java.sql.Types.TINYINT:
603: return "java.lang.Integer";
604: case Types.SMALLINT:
605: return "java.lang.Integer";
606: case Types.INTEGER:
607: return "java.lang.Integer";
608: case Types.BIGINT:
609: return "java.lang.Long";
610: case java.sql.Types.FLOAT:
611: return "java.lang.Double";
612: case Types.REAL:
613: return "java.lang.Float";
614: case Types.DOUBLE:
615: return "java.lang.Double";
616: case java.sql.Types.NUMERIC:
617: case Types.DECIMAL:
618: return "java.math.BigDecimal";
619: case Types.CHAR:
620: case Types.VARCHAR:
621: case Types.LONGVARCHAR:
622: return "java.lang.String";
623: case Types.DATE:
624: return "java.sql.Date";
625: case Types.TIME:
626: return "java.sql.Time";
627: case Types.TIMESTAMP:
628: return "java.sql.Timestamp";
629: case Types.BINARY:
630: case Types.VARBINARY:
631: case Types.LONGVARBINARY:
632: return "byte[]";
633: case java.sql.Types.STRUCT:
634: return "java.sql.Struct";
635: case java.sql.Types.ARRAY:
636: return "java.sql.Array";
637: case Types.BLOB:
638: return "java.sql.Blob";
639: case Types.CLOB:
640: return "java.sql.Clob";
641: case java.sql.Types.REF:
642: return "java.sql.Ref";
643: default:
644: throw new SqlException(logWriter_, new ClientMessageId(
645: SQLState.UNSUPPORTED_TYPE));
646: }
647: } catch (SqlException e) {
648: throw e.getSQLException();
649: }
650: }
651:
652: //----------------------------helper methods----------------------------------
653:
654: void checkForValidColumnIndex(int column) throws SqlException {
655: if (column < 1 || column > columns_) {
656: throw new SqlException(logWriter_, new ClientMessageId(
657: SQLState.LANG_INVALID_COLUMN_POSITION),
658: new Integer(column), new Integer(columns_));
659: }
660: }
661:
662: // If the input parameter has been set, return true, else return false.
663: private boolean isParameterModeGuessedAsAnInput(int parameterIndex) {
664: if (sqlxParmmode_[parameterIndex - 1] == java.sql.ParameterMetaData.parameterModeIn
665: || sqlxParmmode_[parameterIndex - 1] == java.sql.ParameterMetaData.parameterModeInOut) {
666: return true;
667: }
668: return false;
669: }
670:
671: // Does OUT parm registration rely on extended describe?
672: // If the output parameter has been registered, return true, else return false.
673: public boolean isParameterModeGuessedAsOutput(int parameterIndex) {
674: return sqlxParmmode_[parameterIndex - 1] >= java.sql.ParameterMetaData.parameterModeInOut;
675: }
676:
677: /** This method does not appear to be in use -- davidvc@apache.org
678: // Only called when column meta data is not described. Called by setXXX methods.
679: public void guessInputParameterMetaData(int parameterIndex,
680: int jdbcType) throws SqlException {
681: guessInputParameterMetaData(parameterIndex, jdbcType, 0);
682: }
683: */
684:
685: private void setParmModeForInputParameter(int parameterIndex) {
686: if (sqlxParmmode_[parameterIndex - 1] == java.sql.ParameterMetaData.parameterModeOut) {
687: sqlxParmmode_[parameterIndex - 1] = java.sql.ParameterMetaData.parameterModeInOut;
688: } else if (sqlxParmmode_[parameterIndex - 1] == java.sql.ParameterMetaData.parameterModeUnknown) {
689: sqlxParmmode_[parameterIndex - 1] = java.sql.ParameterMetaData.parameterModeIn;
690: }
691: }
692:
693: private void setParmModeForOutputParameter(int parameterIndex) {
694: if (sqlxParmmode_[parameterIndex - 1] == java.sql.ParameterMetaData.parameterModeIn) {
695: sqlxParmmode_[parameterIndex - 1] = java.sql.ParameterMetaData.parameterModeInOut;
696: } else if (sqlxParmmode_[parameterIndex - 1] == java.sql.ParameterMetaData.parameterModeUnknown) {
697: sqlxParmmode_[parameterIndex - 1] = java.sql.ParameterMetaData.parameterModeOut;
698: }
699: }
700:
701: private boolean isCompatibleDriverTypes(int registeredType,
702: int guessedInputType) {
703: switch (registeredType) {
704: case Types.CHAR:
705: case Types.VARCHAR:
706: case Types.LONGVARCHAR:
707: return guessedInputType == Types.CHAR
708: || guessedInputType == Types.VARCHAR
709: || guessedInputType == Types.LONGVARCHAR;
710: case Types.BINARY:
711: case Types.VARBINARY:
712: case Types.LONGVARBINARY:
713: return guessedInputType == Types.BINARY
714: || guessedInputType == Types.VARBINARY
715: || guessedInputType == Types.LONGVARBINARY;
716: default:
717: return registeredType == guessedInputType;
718: }
719: }
720:
721: // Only used when describe information is not available.
722: private int getInternalTypeForGuessedOrRegisteredJdbcType(
723: int guessedOrRegisteredJdbcType) throws SqlException {
724: switch (guessedOrRegisteredJdbcType) {
725: case java.sql.Types.BIT:
726: case java.sql.Types.TINYINT:
727: case java.sql.Types.SMALLINT:
728: return Types.SMALLINT;
729: case java.sql.Types.INTEGER:
730: return Types.INTEGER;
731: case java.sql.Types.BIGINT:
732: return Types.BIGINT;
733: case java.sql.Types.REAL:
734: return Types.REAL;
735: case java.sql.Types.DOUBLE:
736: case java.sql.Types.FLOAT:
737: return Types.DOUBLE;
738: case java.sql.Types.DECIMAL:
739: case java.sql.Types.NUMERIC:
740: return Types.DECIMAL;
741: case java.sql.Types.DATE:
742: return Types.DATE;
743: case java.sql.Types.TIME:
744: return Types.TIME;
745: case java.sql.Types.TIMESTAMP:
746: return Types.TIMESTAMP;
747: case java.sql.Types.CHAR:
748: return Types.CHAR;
749: case java.sql.Types.VARCHAR:
750: return Types.VARCHAR;
751: case java.sql.Types.LONGVARCHAR:
752: return Types.LONGVARCHAR;
753: case java.sql.Types.BINARY:
754: return Types.BINARY;
755: case java.sql.Types.VARBINARY:
756: return Types.VARBINARY;
757: case java.sql.Types.LONGVARBINARY:
758: return Types.LONGVARBINARY;
759: case java.sql.Types.BLOB:
760: return Types.BLOB;
761: case java.sql.Types.CLOB:
762: return Types.CLOB;
763: case java.sql.Types.NULL:
764: case java.sql.Types.OTHER:
765: throw new SqlException(logWriter_, new ClientMessageId(
766: SQLState.UNSUPPORTED_TYPE));
767: default:
768: throw new SqlException(logWriter_, new ClientMessageId(
769: SQLState.UNSUPPORTED_TYPE));
770: }
771: }
772:
773: public void setLogWriter(LogWriter logWriter) {
774: logWriter_ = logWriter;
775: }
776:
777: private void nullDataForGC() {
778: columns_ = 0;
779: nullable_ = null;
780: types_ = null;
781: singleMixedByteOrDouble_ = null;
782: sqldRdbnam_ = null;
783: sqldSchema_ = null;
784: sqlPrecision_ = null;
785: sqlScale_ = null;
786: sqlLength_ = null;
787: sqlType_ = null;
788: sqlCcsid_ = null;
789: sqlName_ = null;
790: sqlLabel_ = null;
791: sqlUnnamed_ = null;
792: sqlComment_ = null;
793: sqlxKeymem_ = null;
794: sqlxGenerated_ = null;
795: sqlxParmmode_ = null;
796: sqlxCorname_ = null;
797: sqlxName_ = null;
798: sqlxBasename_ = null;
799: sqlxUpdatable_ = null;
800: sqlxSchema_ = null;
801: sqlxRdbnam_ = null;
802: clientParamtertype_ = null;
803: types_ = null;
804: }
805:
806: public boolean hasLobColumns() {
807: for (int i = 0; i < columns_; i++) {
808: switch (org.apache.derby.client.am.Utils
809: .getNonNullableSqlType(sqlType_[i])) {
810: case DRDAConstants.DB2_SQLTYPE_BLOB:
811: case DRDAConstants.DB2_SQLTYPE_CLOB:
812: return true;
813: default:
814: break;
815: }
816: }
817: return false;
818: }
819:
820: // Cache the hashtable in ColumnMetaData.
821: int findColumnX(String columnName) throws SqlException {
822: // Create cache if it doesn't exist
823: if (columnNameToIndexCache_ == null) {
824: columnNameToIndexCache_ = new java.util.Hashtable();
825: } else { // Check cache for mapping
826: Integer index = (Integer) columnNameToIndexCache_
827: .get(columnName);
828: if (index != null) {
829: return index.intValue();
830: }
831: }
832:
833: // Ok, we'll have to search the metadata
834: for (int col = 0; col < this .columns_; col++) {
835: if (this .sqlName_ != null
836: && // sqlName comes from an optional group
837: this .sqlName_[col] != null
838: && this .sqlName_[col].equalsIgnoreCase(columnName)) {
839: // Found it, add it to the cache
840: columnNameToIndexCache_.put(columnName, new Integer(
841: col + 1));
842: return col + 1;
843: }
844: }
845: throw new SqlException(logWriter_, new ClientMessageId(
846: SQLState.INVALID_COLUMN_NAME), columnName);
847: }
848:
849: // assign ordinal position as the column name if null.
850: void assignColumnName(int column) {
851: if (columnNameToIndexCache_ == null) {
852: columnNameToIndexCache_ = new java.util.Hashtable();
853: }
854: String columnName = (new Integer(column)).toString();
855: columnNameToIndexCache_.put(columnName, new Integer(column));
856: sqlName_[column - 1] = columnName;
857: }
858:
859: public boolean columnIsNotInUnicode(int index) {
860: return (sqlCcsid_[index] != 1208);
861: }
862:
863: }
|