All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jooq.impl.DefaultBindContext Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
 * All rights reserved.
 *
 * This work is dual-licensed
 * - under the Apache Software License 2.0 (the "ASL")
 * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
 * =============================================================================
 * You may choose which license applies to you:
 *
 * - If you're using this work with Open Source databases, you may choose
 *   either ASL or jOOQ License.
 * - If you're using this work with at least one commercial database, you must
 *   choose jOOQ License
 *
 * For more information, please visit http://www.jooq.org/licenses
 *
 * Apache Software License 2.0:
 * -----------------------------------------------------------------------------
 * Licensed 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.
 *
 * jOOQ License and Maintenance Agreement:
 * -----------------------------------------------------------------------------
 * Data Geekery grants the Customer the non-exclusive, timely limited and
 * non-transferable license to install and use the Software under the terms of
 * the jOOQ License and Maintenance Agreement.
 *
 * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
 * and Maintenance Agreement for more details: http://www.jooq.org/licensing
 */
package org.jooq.impl;

import static java.util.Arrays.asList;
// ...
// ...
// ...
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
import static org.jooq.impl.DefaultExecuteContext.localConnection;
import static org.jooq.tools.reflect.Reflect.on;
import static org.jooq.util.postgres.PostgresUtils.toPGArrayString;
import static org.jooq.util.postgres.PostgresUtils.toPGInterval;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Arrays;
import java.util.UUID;

// ...
import org.jooq.BindContext;
import org.jooq.Configuration;
import org.jooq.Converter;
import org.jooq.EnumType;
import org.jooq.SQLDialect;
import org.jooq.UDTRecord;
import org.jooq.exception.SQLDialectNotSupportedException;
import org.jooq.tools.Convert;
import org.jooq.tools.JooqLogger;
import org.jooq.types.DayToSecond;
import org.jooq.types.UByte;
import org.jooq.types.UInteger;
import org.jooq.types.ULong;
import org.jooq.types.UShort;
import org.jooq.types.YearToMonth;

/**
 * @author Lukas Eder
 */
class DefaultBindContext extends AbstractBindContext {

    private static final JooqLogger log              = JooqLogger.getLogger(DefaultBindContext.class);

    private final PreparedStatement stmt;

    DefaultBindContext(Configuration configuration, PreparedStatement stmt) {
        super(configuration);

        this.stmt = stmt;
    }

    @Override
    public final PreparedStatement statement() {
        return stmt;
    }

    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected final BindContext bindValue0(Object value, Class type) throws SQLException {
        SQLDialect dialect = configuration.dialect();

        // [#650] Check first, if we have a converter for the supplied type
        Converter converter = DataTypes.converter(type);
        if (converter != null) {
            value = ((Converter) converter).to(value);
            type = converter.fromType();
        }

        if (log.isTraceEnabled()) {
            if (value != null && value.getClass().isArray() && value.getClass() != byte[].class) {
                log.trace("Binding variable " + peekIndex(), Arrays.asList((Object[]) value) + " (" + type + ")");
            }
            else {
                log.trace("Binding variable " + peekIndex(), value + " (" + type + ")");
            }
        }

        // Setting null onto a prepared statement is subtly different for every
        // SQL dialect. See the following section for details
        if (value == null) {
            int sqlType = DefaultDataType.getDataType(dialect, type).getSQLType();

            /* [pro] xx
            xx xxxxxxxxxxxx xxxxx xxxxx xxxx xx xx xxxxx xxxx xxxxx xxxx xxxx
            xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
                xxxxxx xxxxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxx xxxxxxxxxxxxxxxxxxxxxxxxx
                xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxx xxxxxxxxxx
            x

            xxxx
            xx [/pro] */
            // [#1126] Oracle's UDTs need to be bound with their type name
            if (UDTRecord.class.isAssignableFrom(type)) {
                String typeName = Utils.newRecord((Class>) type)
                                       .operate(null)
                                       .getUDT()
                                       .getName();
                stmt.setNull(nextIndex(), sqlType, typeName);
            }

            // [#1225] [#1227] TODO Put this logic into DataType
            // Some dialects have trouble binding binary data as BLOB
            else if (asList(POSTGRES).contains(configuration.dialect()) && sqlType == Types.BLOB) {
                stmt.setNull(nextIndex(), Types.BINARY);
            }

            /* [pro] xx
            xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxx x

                xx xxxx xxxxxxxxxx xxxx xx xxxx xxxxxx xxxx xxx xxx xxxxxxxxx xxxxxx
                xx xxxxxxxxxxx xxxxx xxxxxxx xxx xxxxxxx
                xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                xxxxxx xxxxxxxxx x
                    xxxx xxxxxxxxxxxxx
                    xxxx xxxxxxxxxxxxxxxx
                    xxxx xxxxxxxxxxxxxxxxxxxx
                    xxxx xxxxxxxxxxx
                        xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
                        xxxxxx

                    xxxxxxxx
                        xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx
                        xxxxxx
                x
            x

            xx xxxxxxx xxxxxxx xxx xxx xxxxxx xxxxxx xxxx xxx xxxx xxxxxxxx xxx xxx xxxx xxxxxx
            xx xxxxxx xxx xxx xxxxxxx xxxxx
            xxxx xx xxxxxxxx xx xxxxxxxxxxxxx xx xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
                xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx
            x

            xx [/pro] */
            // All other types can be set to null if the JDBC type is known
            else if (sqlType != Types.OTHER) {
                stmt.setNull(nextIndex(), sqlType);
            }

            /* [pro] xx
            xx xxxxxx xxx xxx xxxxxxx xxxxxxx xxxxx xxxxxx xx xxx xx xxxx
            xx xxxxxxxxxxx xxx
            xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxxxxx x
                xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx
            x

            xx xxxxxx xxx xxxxxxx xxxxxxx xxxxx xxx xx xxx xx xxxx xxxxx xxxxxxx
            xxxx xx xxxxxxxxxxxxxxxxxxxxxxxx xx xxxxxxx x
                xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
            x

            xx [/pro] */
            // [#729] In the absence of the correct JDBC type, try setObject
            else {
                stmt.setObject(nextIndex(), null);
            }
        }
        else {

            // Try to infer the bind value type from the actual bind value if possible.
            if (type == Object.class) {
                type = value.getClass();
            }

            if (type == Blob.class) {
                stmt.setBlob(nextIndex(), (Blob) value);
            }
            else if (type == Boolean.class) {
                /* [pro] xx
                xx xx xxxxxx xxxxxx xxxxxx xx xxxxx xxxxx xxxxx xx xxxxxxxxx xx xxxxxxxxxx xx xxxxxxx xxxxxxx
                xx xxxxxxxxxxxxxxxxx xx xxxxxxx
                    xxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxx xxxxx x x x xxx
                xxxx
                xx [/pro] */
                    stmt.setBoolean(nextIndex(), (Boolean) value);
            }
            else if (type == BigDecimal.class) {
                if (asList(SQLITE).contains(dialect.family())) {
                    stmt.setString(nextIndex(), value.toString());
                }
                else {
                    stmt.setBigDecimal(nextIndex(), (BigDecimal) value);
                }
            }
            else if (type == BigInteger.class) {
                if (asList(SQLITE).contains(dialect.family())) {
                    stmt.setString(nextIndex(), value.toString());
                }
                else {
                    stmt.setBigDecimal(nextIndex(), new BigDecimal((BigInteger) value));
                }
            }
            else if (type == Byte.class) {
                stmt.setByte(nextIndex(), (Byte) value);
            }
            else if (type == byte[].class) {
                stmt.setBytes(nextIndex(), (byte[]) value);
            }
            else if (type == Clob.class) {
                stmt.setClob(nextIndex(), (Clob) value);
            }
            else if (type == Double.class) {
                stmt.setDouble(nextIndex(), (Double) value);
            }
            else if (type == Float.class) {
                stmt.setFloat(nextIndex(), (Float) value);
            }
            else if (type == Integer.class) {
                stmt.setInt(nextIndex(), (Integer) value);
            }
            else if (type == Long.class) {
                /* [pro] xx
                xx xxxxxxxxxxxxxxxxx xx xxxxxxx
                    xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
                xxxx
                xx [/pro] */
                stmt.setLong(nextIndex(), (Long) value);
            }
            else if (type == Short.class) {
                stmt.setShort(nextIndex(), (Short) value);
            }
            else if (type == String.class) {
                stmt.setString(nextIndex(), (String) value);
            }

            // There is potential for trouble when binding date time as such
            // -------------------------------------------------------------
            else if (type == Date.class) {
                if (dialect == SQLITE) {
                    stmt.setString(nextIndex(), ((Date) value).toString());
                }
                else {
                    stmt.setDate(nextIndex(), (Date) value);
                }
            }
            else if (type == Time.class) {
                if (dialect == SQLITE) {
                    stmt.setString(nextIndex(), ((Time) value).toString());
                }
                else {
                    stmt.setTime(nextIndex(), (Time) value);
                }
            }
            else if (type == Timestamp.class) {
                if (dialect == SQLITE) {
                    stmt.setString(nextIndex(), ((Timestamp) value).toString());
                }
                else {
                    stmt.setTimestamp(nextIndex(), (Timestamp) value);
                }
            }

            // [#566] Interval data types are best bound as Strings
            else if (type == YearToMonth.class) {
                if (dialect == POSTGRES) {
                    stmt.setObject(nextIndex(), toPGInterval((YearToMonth) value));
                }
                else {
                    stmt.setString(nextIndex(), value.toString());
                }
            }
            else if (type == DayToSecond.class) {
                if (dialect == POSTGRES) {
                    stmt.setObject(nextIndex(), toPGInterval((DayToSecond) value));
                }
                else {
                    stmt.setString(nextIndex(), value.toString());
                }
            }
            else if (type == UByte.class) {
                stmt.setShort(nextIndex(), ((UByte) value).shortValue());
            }
            else if (type == UShort.class) {
                stmt.setInt(nextIndex(), ((UShort) value).intValue());
            }
            else if (type == UInteger.class) {
                /* [pro] xx
                xx xxxxxxxxxxxxxxxxx xx xxxxxxx
                    xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
                xxxx
                xx [/pro] */
                stmt.setLong(nextIndex(), ((UInteger) value).longValue());
            }
            else if (type == ULong.class) {
                /* [pro] xx
                xx xxxxxxxxxxxxxxxxx xx xxxxxxx
                    xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxx
                xxxx
                xx [/pro] */
                stmt.setBigDecimal(nextIndex(), new BigDecimal(value.toString()));
            }
            else if (type == UUID.class) {
                switch (dialect.family()) {

                    // [#1624] Some JDBC drivers natively support the
                    // java.util.UUID data type
                    case H2:
                    case POSTGRES: {
                        stmt.setObject(nextIndex(), value);
                        break;
                    }

                    /* [pro] xx
                    xx xxxxx xxx xxxxxxxx xxxx xxxx xxxxx xx xx xxxx xxxx xxxxxxxx
                    xx xxxx xx xxxx xxxxxxxxxx xxxxxxx xxxx xxxxxxxxxxxxxxxxxx
                    xxxx xxxxxxxxxx
                    xxxx xxxxxxx

                    xx [/pro] */
                    // Most databases don't have such a type. In this case, jOOQ
                    // simulates the type
                    default: {
                        stmt.setString(nextIndex(), value.toString());
                        break;
                    }
                }
            }

            // The type byte[] is handled earlier. byte[][] can be handled here
            else if (type.isArray()) {
                switch (dialect) {
                    case POSTGRES: {
                        stmt.setString(nextIndex(), toPGArrayString((Object[]) value));
                        break;
                    }
                    case HSQLDB: {
                        Object[] a = (Object[]) value;
                        Class t = type;

                        // [#2325] Some array types are not natively supported by HSQLDB
                        // More integration tests are probably needed...
                        if (type == UUID[].class) {
                            a = Convert.convertArray(a, String[].class);
                            t = String[].class;
                        }

                        stmt.setArray(nextIndex(), new DefaultArray(dialect, a, t));
                        break;
                    }
                    case H2: {
                        stmt.setObject(nextIndex(), value);
                        break;
                    }
                    default:
                        throw new SQLDialectNotSupportedException("Cannot bind ARRAY types in dialect " + dialect);
                }
            }
            /* [pro] xx
            xxxx xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x
                xxxxxxxxxxxxxx xxxxxxxxxxx x xxxxxxxxxxxxxxxx xxxxxx
                xxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
            x
            xx [/pro] */
            else if (EnumType.class.isAssignableFrom(type)) {
                stmt.setString(nextIndex(), ((EnumType) value).getLiteral());
            }
            else {
                stmt.setObject(nextIndex(), value);
            }
        }

        return this;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy