| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.internal.shapefile.jdbc.resultset; |
| |
| import java.math.BigDecimal; |
| import java.math.MathContext; |
| import java.math.RoundingMode; |
| import java.nio.charset.Charset; |
| import java.sql.Date; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLFeatureNotSupportedException; |
| import java.util.Calendar; |
| import java.util.GregorianCalendar; |
| import java.util.Map; |
| import java.util.function.Function; |
| import java.util.logging.Level; |
| |
| import org.apache.sis.internal.shapefile.jdbc.SQLConnectionClosedException; |
| import org.apache.sis.internal.shapefile.jdbc.connection.DBFConnection; |
| import org.apache.sis.internal.shapefile.jdbc.metadata.DBFResultSetMataData; |
| import org.apache.sis.internal.shapefile.jdbc.sql.*; |
| import org.apache.sis.internal.shapefile.jdbc.statement.DBFStatement; |
| |
| /** |
| * A ResultSet based on a record. |
| * @author Marc LE BIHAN |
| */ |
| public class DBFRecordBasedResultSet extends DBFResultSet { |
| /** The current record. */ |
| private Map<String, byte[]> record; |
| |
| /** Condition of where clause (currently, only one is handled). */ |
| private ConditionalClauseResolver singleConditionOfWhereClause; |
| |
| /** Indicates that the last result set record matching conditions has already been returned, and a further call of next() shall throw a "no more record" exception. */ |
| private boolean lastResultSetRecordAlreadyReturned; |
| |
| /** The record number of this record. */ |
| private int recordNumber; |
| |
| /** |
| * Constructs a result set. |
| * @param stmt Parent statement. |
| * @param sqlQuery SQL Statment that produced this ResultSet. |
| * @throws SQLInvalidStatementException if the SQL Statement is invalid. |
| */ |
| public DBFRecordBasedResultSet(final DBFStatement stmt, String sqlQuery) throws SQLInvalidStatementException { |
| super(stmt, sqlQuery); |
| this.singleConditionOfWhereClause = new CrudeSQLParser(this).parse(); |
| } |
| |
| /** |
| * @see org.apache.sis.internal.shapefile.jdbc.resultset.AbstractResultSet#getBigDecimal(java.lang.String) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| */ |
| @Override |
| public BigDecimal getBigDecimal(String columnLabel) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException { |
| logStep("getBigDecimal", columnLabel); |
| |
| assertNotClosed(); |
| |
| // Act as if we were a double, but store the result in a pre-created BigDecimal at the end. |
| try(DBFBuiltInMemoryResultSetForColumnsListing field = (DBFBuiltInMemoryResultSetForColumnsListing)getFieldDesc(columnLabel, sql)) { |
| MathContext mc = new MathContext(field.getInt("DECIMAL_DIGITS"), RoundingMode.HALF_EVEN); |
| Double doubleValue = getDouble(columnLabel); |
| |
| if (doubleValue != null) { |
| BigDecimal number = new BigDecimal(doubleValue, mc); |
| this.wasNull = false; |
| return number; |
| } |
| else { |
| this.wasNull = true; |
| return null; |
| } |
| } |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getBigDecimal(int) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| * @throws SQLIllegalColumnIndexException if the column index has an illegal value. |
| */ |
| @Override |
| public BigDecimal getBigDecimal(int columnIndex) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException, SQLIllegalColumnIndexException { |
| logStep("getBigDecimal", columnIndex); |
| return getBigDecimal(getFieldName(columnIndex, this.sql)); |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getBigDecimal(java.lang.String, int) |
| * @deprecated Deprecated API (from ResultSet Interface) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| */ |
| @Deprecated @Override |
| public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException { |
| logStep("getBigDecimal", columnLabel, scale); |
| assertNotClosed(); |
| |
| // Act as if we were a double, but store the result in a pre-created BigDecimal at the end. |
| MathContext mc = new MathContext(scale, RoundingMode.HALF_EVEN); |
| Double doubleValue = getDouble(columnLabel); |
| |
| if (doubleValue != null) { |
| BigDecimal number = new BigDecimal(getDouble(columnLabel), mc); |
| this.wasNull = false; |
| return number; |
| } |
| else { |
| this.wasNull = true; |
| return null; |
| } |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getDate(java.lang.String) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotDateException if the field is not a date. |
| */ |
| @Override |
| public Date getDate(String columnLabel) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotDateException { |
| logStep("getDate", columnLabel); |
| assertNotClosed(); |
| |
| String value = getString(columnLabel); |
| |
| if (value == null || value.equals("00000000")) { // "00000000" is stored in Database to represent a null value too. |
| this.wasNull = true; |
| return null; // The ResultSet:getDate() contract is to return null when a null date is encountered. |
| } |
| else { |
| this.wasNull = false; |
| } |
| |
| // The DBase 3 date format is "YYYYMMDD". |
| // if the length of the string isn't eight characters, the field format is incorrect. |
| if (value.length() != 8) { |
| String message = format(Level.WARNING, "excp.field_is_not_a_date", columnLabel, this.sql, value); |
| throw new SQLNotDateException(message, this.sql, getFile(), columnLabel, value); |
| } |
| |
| // Extract the date parts. |
| int year, month, dayOfMonth; |
| |
| try { |
| year = Integer.parseInt(value.substring(0, 4)); |
| month = Integer.parseInt(value.substring(5, 7)); |
| dayOfMonth = Integer.parseInt(value.substring(7)); |
| } |
| catch(NumberFormatException e) { |
| String message = format(Level.WARNING, "excp.field_is_not_a_date", columnLabel, this.sql, value); |
| throw new SQLNotDateException(message, this.sql, getFile(), columnLabel, value); |
| } |
| |
| // Create a date. |
| Calendar calendar = new GregorianCalendar(year, month-1, dayOfMonth, 0, 0, 0); |
| Date sqlDate = new Date(calendar.getTimeInMillis()); |
| return sqlDate; |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getDate(int) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotDateException if the field is not a date. |
| * @throws SQLIllegalColumnIndexException if the column index has an illegal value. |
| */ |
| @Override |
| public Date getDate(int columnIndex) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotDateException, SQLIllegalColumnIndexException { |
| logStep("getDate", columnIndex); |
| return getDate(getFieldName(columnIndex, this.sql)); |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getDouble(java.lang.String) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| */ |
| @Override |
| public double getDouble(String columnLabel) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException { |
| logStep("getDouble", columnLabel); |
| |
| Double value = getNumeric(columnLabel, Double::parseDouble); |
| this.wasNull = (value == null); |
| return value != null ? value : 0.0; // The ResultSet contract for numbers is to return 0 when a null value is encountered. |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getDouble(int) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| * @throws SQLIllegalColumnIndexException if the column index has an illegal value. |
| */ |
| @Override |
| public double getDouble(int columnIndex) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException, SQLIllegalColumnIndexException { |
| logStep("getDouble", columnIndex); |
| return getDouble(getFieldName(columnIndex, this.sql)); |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getFloat(java.lang.String) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| */ |
| @Override |
| public float getFloat(String columnLabel) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException { |
| logStep("getFloat", columnLabel); |
| |
| Float value = getNumeric(columnLabel, Float::parseFloat); |
| this.wasNull = (value == null); |
| return value != null ? value : 0; // The ResultSet contract for numbers is to return 0 when a null value is encountered. |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getFloat(int) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| * @throws SQLIllegalColumnIndexException if the column index has an illegal value. |
| */ |
| @Override |
| public float getFloat(int columnIndex) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException, SQLIllegalColumnIndexException { |
| logStep("getFloat", columnIndex); |
| return getFloat(getFieldName(columnIndex, this.sql)); |
| } |
| |
| /** |
| * @see org.apache.sis.internal.shapefile.jdbc.resultset.AbstractResultSet#getInt(java.lang.String) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| */ |
| @Override |
| public int getInt(String columnLabel) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException { |
| logStep("getInt", columnLabel); |
| |
| Integer value = getNumeric(columnLabel, Integer::parseInt); |
| this.wasNull = (value == null); |
| return value != null ? value : 0; // The ResultSet contract for numbers is to return 0 when a null value is encountered. |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getInt(int) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| * @throws SQLIllegalColumnIndexException if the column index has an illegal value. |
| */ |
| @Override |
| public int getInt(int columnIndex) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException, SQLIllegalColumnIndexException { |
| logStep("getInt", columnIndex); |
| return getInt(getFieldName(columnIndex, this.sql)); |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getLong(java.lang.String) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| */ |
| @Override |
| public long getLong(String columnLabel) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException { |
| logStep("getLong", columnLabel); |
| |
| Long value = getNumeric(columnLabel, Long::parseLong); |
| this.wasNull = (value == null); |
| return value != null ? value : 0; // The ResultSet contract for numbers is to return 0 when a null value is encountered. |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getLong(int) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric. |
| * @throws SQLIllegalColumnIndexException if the column index has an illegal value. |
| */ |
| @Override public long getLong(int columnIndex) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException, SQLIllegalColumnIndexException { |
| logStep("getLong", columnIndex); |
| return getLong(getFieldName(columnIndex, this.sql)); |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getMetaData() |
| */ |
| @Override |
| public ResultSetMetaData getMetaData() { |
| logStep("getMetaData"); |
| |
| DBFResultSetMataData meta = new DBFResultSetMataData(this); |
| return meta; |
| } |
| |
| /** |
| * @see org.apache.sis.internal.shapefile.jdbc.resultset.AbstractResultSet#getObject(int) |
| */ |
| @Override |
| public Object getObject(int column) throws SQLConnectionClosedException, SQLIllegalColumnIndexException, SQLFeatureNotSupportedException, SQLNoSuchFieldException, SQLNotNumericException, SQLNotDateException { |
| try(DBFBuiltInMemoryResultSetForColumnsListing field = (DBFBuiltInMemoryResultSetForColumnsListing)getFieldDesc(column, this.sql)) { |
| String fieldType; |
| |
| try { |
| fieldType = field.getString("TYPE_NAME"); |
| } |
| catch(SQLNoSuchFieldException e) { |
| // This is an internal trouble because the field type must be found. |
| throw new RuntimeException(e.getMessage(), e); |
| } |
| |
| switch(fieldType) { |
| case "AUTO_INCREMENT": |
| case "INTEGER": |
| return getInt(column); |
| |
| case "CHAR": |
| return getString(column); |
| |
| case "DATE": |
| return getDate(column); |
| |
| case "DECIMAL": { |
| // Choose Integer or Long type, if no decimal and that the field is not to big. |
| if (field.getInt("DECIMAL_DIGITS") == 0 && field.getInt("COLUMN_SIZE") <= 18) { |
| if (field.getInt("COLUMN_SIZE") <= 9) |
| return getInt(column); |
| else |
| return getLong(column); |
| } |
| |
| return getDouble(column); |
| } |
| |
| case "DOUBLE": |
| case "CURRENCY": |
| return getDouble(column); |
| |
| case "FLOAT": |
| return getFloat(column); |
| |
| case "BOOLEAN": |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on Boolean"); |
| |
| case "DATETIME": |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on DateTime"); |
| |
| case "TIMESTAMP": |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on TimeStamp"); |
| |
| case "MEMO": |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on Memo"); |
| |
| case "PICTURE": |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on Picture"); |
| |
| case "VARIFIELD": |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on VariField"); |
| |
| case "VARIANT": |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on Variant"); |
| |
| case "UNKNOWN": |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on " + fieldType); |
| |
| default: |
| throw unsupportedOperation("ResultSetMetaData.getColumnClassName(..) on " + fieldType); |
| } |
| } |
| } |
| |
| /** |
| * @see org.apache.sis.internal.shapefile.jdbc.resultset.DBFResultSet#getObject(java.lang.String) |
| */ |
| @Override |
| public Object getObject(String columnLabel) throws SQLConnectionClosedException, SQLFeatureNotSupportedException, SQLNoSuchFieldException, SQLNotNumericException, SQLNotDateException { |
| int index = -1; |
| |
| try { |
| index = findColumn(columnLabel); |
| return getObject(index); |
| } |
| catch(SQLIllegalColumnIndexException e) { |
| String message = format(Level.SEVERE, "assert.wrong_index_for_column_name", index, columnLabel); |
| throw new RuntimeException(message, e); |
| } |
| } |
| |
| /** |
| * Return the record number of this record. |
| * @return Record number of this record. |
| */ |
| public int getRowNum() { |
| return this.recordNumber; |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getShort(java.lang.String) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric or has a NULL value. |
| */ |
| @Override |
| public short getShort(String columnLabel) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException { |
| logStep("getShort", columnLabel); |
| |
| Short value = getNumeric(columnLabel, Short::parseShort); |
| this.wasNull = (value == null); |
| return value != null ? value : 0; // The ResultSet contract for numbers is to return 0 when a null value is encountered. |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getShort(int) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric or has a NULL value. |
| * @throws SQLIllegalColumnIndexException if the column index has an illegal value. |
| */ |
| @Override |
| public short getShort(int columnIndex) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException, SQLIllegalColumnIndexException { |
| logStep("getShort", columnIndex); |
| return getShort(getFieldName(columnIndex, this.sql)); |
| } |
| |
| /** |
| * Returns the value in the current row for the given column. |
| * @param columnLabel Column name. |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field does not exist. |
| */ |
| @Override |
| @SuppressWarnings("resource") // Only read the current connection to get the Charset. |
| public String getString(String columnLabel) throws SQLConnectionClosedException, SQLNoSuchFieldException { |
| logStep("getString", columnLabel); |
| assertNotClosed(); |
| |
| getFieldDesc(columnLabel, this.sql); // Ensure that the field queried exists, else a null value here can be interpreted as "not existing" or "has a null value". |
| byte[] bytes = this.record.get(columnLabel); |
| |
| if (bytes == null) { |
| this.wasNull = true; |
| return null; |
| } |
| else { |
| this.wasNull = false; |
| } |
| |
| // If a non null value has been readed, convert it to the wished Charset (provided one has been given). |
| DBFConnection cnt = (DBFConnection)((DBFStatement)getStatement()).getConnection(); |
| Charset charset = cnt.getCharset(); |
| |
| if (charset == null) { |
| return new String(bytes); |
| } |
| else { |
| String withDatabaseCharset = new String(bytes, charset); |
| log(Level.FINER, "log.string_field_charset", columnLabel, withDatabaseCharset, charset); |
| return withDatabaseCharset; |
| } |
| } |
| |
| /** |
| * @see java.sql.ResultSet#getString(int) |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLIllegalColumnIndexException if the column index has an illegal value. |
| */ |
| @Override |
| public String getString(int columnIndex) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLIllegalColumnIndexException { |
| logStep("getString", columnIndex); |
| return(getString(getFieldName(columnIndex, this.sql))); |
| } |
| |
| /** |
| * Moves the cursor forward one row from its current position. |
| * @throws SQLInvalidStatementException if the SQL statement is invalid. |
| * @throws SQLIllegalParameterException if the value of one parameter of a condition is invalid. |
| * @throws SQLNoSuchFieldException if a field mentionned in the condition doesn't exist. |
| * @throws SQLUnsupportedParsingFeatureException if the caller asked for a not yet supported feature of the driver. |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNotNumericException if a value or data expected to be numeric isn't. |
| * @throws SQLNotDateException if a value or data expected to be a date isn't. |
| */ |
| @Override |
| @SuppressWarnings("resource") // Only read the current connection to find if a next row is available and read it. |
| public boolean next() throws SQLNoResultException, SQLConnectionClosedException, SQLInvalidStatementException, SQLIllegalParameterException, SQLNoSuchFieldException, SQLUnsupportedParsingFeatureException, SQLNotNumericException, SQLNotDateException { |
| logStep("next"); |
| assertNotClosed(); |
| |
| DBFConnection cnt = (DBFConnection)((DBFStatement)getStatement()).getConnection(); |
| |
| // Check that we aren't at the end of the Database file. |
| if (cnt.nextRowAvailable() == false) { |
| if (this.lastResultSetRecordAlreadyReturned) { |
| throw new SQLNoResultException(format(Level.WARNING, "excp.no_more_results", this.sql, getFile().getName()), this.sql, getFile()); |
| } |
| else { |
| this.lastResultSetRecordAlreadyReturned = true; |
| return false; |
| } |
| } |
| |
| return nextRecordMatchingConditions(); |
| } |
| |
| /** |
| * Find the next record that match the where condition. |
| * @return true if a record has been found. |
| * @throws SQLInvalidStatementException if the SQL statement is invalid. |
| * @throws SQLIllegalParameterException if the value of one parameter of a condition is invalid. |
| * @throws SQLNoSuchFieldException if a field mentionned in the condition doesn't exist. |
| * @throws SQLUnsupportedParsingFeatureException if the caller asked for a not yet supported feature of the driver. |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNotNumericException if a value or data expected to be numeric isn't. |
| * @throws SQLNotDateException if a value or data expected to be a date isn't. |
| */ |
| @SuppressWarnings("resource") // Only read the current connection to find if a next row is available and read it. |
| private boolean nextRecordMatchingConditions() throws SQLInvalidStatementException, SQLIllegalParameterException, SQLNoSuchFieldException, SQLUnsupportedParsingFeatureException, SQLConnectionClosedException, SQLNotNumericException, SQLNotDateException { |
| boolean recordMatchesConditions = false; |
| DBFConnection cnt = (DBFConnection)((DBFStatement)getStatement()).getConnection(); |
| |
| while(cnt.nextRowAvailable() && recordMatchesConditions == false) { |
| this.record = cnt.readNextRowAsObjects(); |
| this.recordNumber = cnt.getRowNum(); |
| recordMatchesConditions = this.singleConditionOfWhereClause == null || this.singleConditionOfWhereClause.isVerified(this); |
| } |
| |
| return recordMatchesConditions; |
| } |
| |
| /** |
| * @see java.sql.Wrapper#isWrapperFor(java.lang.Class) |
| */ |
| @Override |
| public boolean isWrapperFor(Class<?> iface) { |
| logStep("isWrapperFor", iface); |
| return iface.isAssignableFrom(getInterface()); |
| } |
| |
| /** |
| * @see java.sql.ResultSet#wasNull() |
| */ |
| @Override |
| public boolean wasNull() { |
| logStep("wasNull"); |
| return this.wasNull; |
| } |
| |
| /** |
| * Get a numeric value. |
| * @param <T> Type of the number. |
| * @param columnLabel Column Label. |
| * @param parse Parsing function : Integer.parseInt, Float.parseFloat, Long.parseLong, ... |
| * @return The expected value or null if null was encountered. |
| * @throws SQLConnectionClosedException if the connection is closed. |
| * @throws SQLNoSuchFieldException if the field looked for doesn't exist. |
| * @throws SQLNotNumericException if the field value is not numeric or has a NULL value. |
| */ |
| private <T extends Number> T getNumeric(String columnLabel, Function<String, T> parse) throws SQLConnectionClosedException, SQLNoSuchFieldException, SQLNotNumericException { |
| assertNotClosed(); |
| |
| try(DBFBuiltInMemoryResultSetForColumnsListing rs = (DBFBuiltInMemoryResultSetForColumnsListing)getFieldDesc(columnLabel, this.sql)) { |
| String textValue = getString(columnLabel); |
| |
| if (textValue == null) { |
| return null; |
| } |
| |
| try { |
| textValue = textValue.trim(); // Field must be trimed before being converted. |
| T value = parse.apply(textValue); |
| return(value); |
| } |
| catch(NumberFormatException e) { |
| String message = format(Level.WARNING, "excp.field_is_not_numeric", columnLabel, rs.getString("TYPE_NAME"), this.sql, textValue); |
| throw new SQLNotNumericException(message, this.sql, getFile(), columnLabel, textValue); |
| } |
| } |
| } |
| |
| /** |
| * @see java.lang.Object#toString() |
| */ |
| @Override |
| public String toString() { |
| return format("toString", this.statement != null ? this.statement.toString() : null, this.sql, isClosed() == false); |
| } |
| } |