Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
* All rights reserved.
*
* 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.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import static java.lang.Boolean.TRUE;
import static java.util.Arrays.asList;
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.FIREBIRD;
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
// ...
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
import static org.jooq.conf.ParamType.INLINED;
import static org.jooq.impl.DSL.cast;
import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.name;
import static org.jooq.impl.DSL.using;
import static org.jooq.impl.DefaultExecuteContext.localTargetConnection;
import static org.jooq.impl.Tools.attachRecords;
import static org.jooq.impl.Tools.getMappedUDTName;
import static org.jooq.impl.Tools.needsBackslashEscaping;
import static org.jooq.tools.jdbc.JDBCUtils.safeClose;
import static org.jooq.tools.jdbc.JDBCUtils.safeFree;
import static org.jooq.tools.jdbc.JDBCUtils.wasNull;
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.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// ...
import org.jooq.Attachable;
import org.jooq.Binding;
import org.jooq.BindingGetResultSetContext;
import org.jooq.BindingGetSQLInputContext;
import org.jooq.BindingGetStatementContext;
import org.jooq.BindingRegisterContext;
import org.jooq.BindingSQLContext;
import org.jooq.BindingSetSQLOutputContext;
import org.jooq.BindingSetStatementContext;
import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.Converter;
import org.jooq.Converters;
import org.jooq.DataType;
import org.jooq.EnumType;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Result;
import org.jooq.Row;
import org.jooq.SQLDialect;
import org.jooq.Schema;
import org.jooq.Scope;
import org.jooq.UDTRecord;
import org.jooq.exception.ControlFlowSignal;
import org.jooq.exception.DataTypeException;
import org.jooq.exception.MappingException;
import org.jooq.exception.SQLDialectNotSupportedException;
import org.jooq.tools.Convert;
import org.jooq.tools.JooqLogger;
import org.jooq.tools.jdbc.JDBCUtils;
import org.jooq.tools.jdbc.MockArray;
import org.jooq.types.DayToSecond;
import org.jooq.types.Interval;
import org.jooq.types.UByte;
import org.jooq.types.UInteger;
import org.jooq.types.ULong;
import org.jooq.types.UNumber;
import org.jooq.types.UShort;
import org.jooq.types.YearToMonth;
import org.jooq.util.postgres.PostgresUtils;
/**
* @author Lukas Eder
*/
public class DefaultBinding implements Binding {
static final JooqLogger log = JooqLogger.getLogger(DefaultBinding.class);
private static final char[] HEX = "0123456789abcdef".toCharArray();
/**
* Generated UID
*/
private static final long serialVersionUID = -198499389344950496L;
final Class type;
final Converter converter;
@Deprecated
// TODO: This type boolean should not be passed standalone to the
// constructor. Find a better design
final boolean isLob;
public DefaultBinding(Converter converter) {
this(converter, false);
}
DefaultBinding(Converter converter, boolean isLob) {
this.type = converter.fromType();
this.converter = converter;
this.isLob = isLob;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
static Binding newBinding(final Converter converter, final DataType type, final Binding binding) {
final Binding theBinding;
if (converter == null && binding == null) {
theBinding = (Binding) type.getBinding();
}
else if (converter == null) {
theBinding = (Binding) binding;
}
else if (binding == null) {
theBinding = (Binding) new DefaultBinding(converter, type.isLob());
}
else {
theBinding = new Binding() {
/**
* Generated UID
*/
private static final long serialVersionUID = 8912340791845209886L;
final Converter theConverter = Converters.of(binding.converter(), converter);
@Override
public Converter converter() {
return theConverter;
}
@Override
public void sql(BindingSQLContext ctx) throws SQLException {
binding.sql(ctx.convert(converter));
}
@Override
public void register(BindingRegisterContext ctx) throws SQLException {
binding.register(ctx.convert(converter));
}
@Override
public void set(BindingSetStatementContext ctx) throws SQLException {
binding.set(ctx.convert(converter));
}
@Override
public void set(BindingSetSQLOutputContext ctx) throws SQLException {
binding.set(ctx.convert(converter));
}
@Override
public void get(BindingGetResultSetContext ctx) throws SQLException {
binding.get(ctx.convert(converter));
}
@Override
public void get(BindingGetStatementContext ctx) throws SQLException {
binding.get(ctx.convert(converter));
}
@Override
public void get(BindingGetSQLInputContext ctx) throws SQLException {
binding.get(ctx.convert(converter));
}
};
}
return theBinding;
}
@Override
public Converter converter() {
return converter;
}
@Override
public void sql(BindingSQLContext ctx) {
T converted = converter.to(ctx.value());
// Casting can be enforced or prevented
switch (ctx.render().castMode()) {
case NEVER:
toSQL(ctx, converted);
return;
case ALWAYS:
toSQLCast(ctx, converted);
return;
}
// See if we "should" cast, to stay on the safe side
if (shouldCast(ctx, converted)) {
toSQLCast(ctx, converted);
}
// Most RDBMS can infer types for bind values
else {
toSQL(ctx, converted);
}
}
private final boolean shouldCast(BindingSQLContext ctx, T converted) {
// In default mode, casting is only done when parameters are NOT inlined
if (ctx.render().paramType() != INLINED) {
// Generated enums should not be cast...
if (!(converted instanceof EnumType)) {
switch (ctx.family()) {
// These dialects can hardly detect the type of a bound constant.
case DERBY:
case FIREBIRD:
// These dialects have some trouble, when they mostly get it right.
case H2:
case HSQLDB:
// [#1261] There are only a few corner-cases, where this is
// really needed. Check back on related CUBRID bugs
case CUBRID:
// [#1029] Postgres and [#632] Sybase need explicit casting
// in very rare cases.
case POSTGRES: {
return true;
}
}
}
}
// [#566] JDBC doesn't explicitly support interval data types. To be on
// the safe side, always cast these types in those dialects that support
// them
if (Interval.class.isAssignableFrom(type)) {
switch (ctx.family()) {
case POSTGRES:
return true;
}
}
if (type == OffsetTime.class || type == OffsetDateTime.class) {
switch (ctx.family()) {
case POSTGRES:
return true;
}
}
return false;
}
/**
* Render the bind variable including a cast, if necessary
*/
private final void toSQLCast(BindingSQLContext ctx, T converted) {
DataType dataType = DefaultDataType.getDataType(ctx.dialect(), type);
DataType sqlDataType = dataType.getSQLDataType();
SQLDialect family = ctx.family();
// [#822] Some RDBMS need precision / scale information on BigDecimals
if (converted != null && type == BigDecimal.class && asList(CUBRID, DERBY, FIREBIRD, HSQLDB).contains(family)) {
// Add precision / scale on BigDecimals
int scale = ((BigDecimal) converted).scale();
int precision = ((BigDecimal) converted).precision();
// [#5323] BigDecimal precision is always 1 for BigDecimals smaller than 1.0
if (scale >= precision)
precision = scale + 1;
toSQLCast(ctx, converted, dataType, 0, precision, scale);
}
// [#1028] Most databases don't know an OTHER type (except H2, HSQLDB).
else if (SQLDataType.OTHER == sqlDataType) {
// If the bind value is set, it can be used to derive the cast type
if (converted != null) {
toSQLCast(ctx, converted, DefaultDataType.getDataType(family, converted.getClass()), 0, 0, 0);
}
// [#632] [#722] Current integration tests show that Ingres and
// Sybase can do without casting in most cases.
else if (asList().contains(family)) {
ctx.render().sql(ctx.variable());
}
// Derby and DB2 must have a type associated with NULL. Use VARCHAR
// as a workaround. That's probably not correct in all cases, though
else {
toSQLCast(ctx, converted, DefaultDataType.getDataType(family, String.class), 0, 0, 0);
}
}
// [#1029] Postgres generally doesn't need the casting. Only in the
// above case where the type is OTHER
// [#1125] Also with temporal data types, casting is needed some times
// [#4338] ... specifically when using JSR-310 types
// [#1130] TODO type can be null for ARRAY types, etc.
else if (asList(POSTGRES).contains(family) && (sqlDataType == null || !sqlDataType.isTemporal())) {
toSQL(ctx, converted);
}
// [#1727] VARCHAR types should be cast to their actual lengths in some
// dialects
else if ((sqlDataType == SQLDataType.VARCHAR || sqlDataType == SQLDataType.CHAR) && asList(FIREBIRD).contains(family)) {
toSQLCast(ctx, converted, dataType, getValueLength(converted), 0, 0);
}
// In all other cases, the bind variable can be cast normally
else {
toSQLCast(ctx, converted, dataType, dataType.length(), dataType.precision(), dataType.scale());
}
}
private final int getValueLength(T value) {
String string = (String) value;
if (string == null) {
return 1;
}
else {
int length = string.length();
// If non 7-bit ASCII characters are present, multiply the length by
// 4 to be sure that even UTF-32 collations will fit. But don't use
// larger numbers than Derby's upper limit 32672
for (int i = 0; i < length; i++) {
if (string.charAt(i) > 127) {
return Math.min(32672, 4 * length);
}
}
return Math.min(32672, length);
}
}
private final void toSQLCast(BindingSQLContext ctx, T converted, DataType> dataType, int length, int precision, int scale) {
ctx.render().keyword("cast").sql('(');
toSQL(ctx, converted);
ctx.render().sql(' ').keyword("as").sql(' ')
.sql(dataType.length(length).precision(precision, scale).getCastTypeName(ctx.configuration()))
.sql(')');
}
/**
* Inlining abstraction
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private final void toSQL(BindingSQLContext ctx, Object val) {
SQLDialect family = ctx.family();
RenderContext render = ctx.render();
if (render.paramType() == INLINED) {
// [#2223] Some type-casts in this section may seem unnecessary, e.g.
// ((Boolean) val).toString(). They have been put in place to avoid
// accidental type confusions where type != val.getClass(), and thus
// SQL injection may occur
if (val == null) {
render.keyword("null");
}
else if (type == Boolean.class) {
// [#1153] Some dialects don't support boolean literals TRUE and FALSE
if (asList(FIREBIRD, SQLITE).contains(family)) {
render.sql(((Boolean) val) ? "1" : "0");
}
else {
render.keyword(((Boolean) val).toString());
}
}
// [#1154] Binary data cannot always be inlined
else if (type == byte[].class) {
byte[] binary = (byte[]) val;
if (asList().contains(family)) {
render.sql("0x")
.sql(convertBytesToHex(binary));
}
else if (asList(DERBY, H2, HSQLDB, MARIADB, MYSQL, SQLITE).contains(family)) {
render.sql("X'")
.sql(convertBytesToHex(binary))
.sql('\'');
}
else if (asList().contains(family)) {
render.keyword("hextoraw('")
.sql(convertBytesToHex(binary))
.sql("')");
}
else if (family == POSTGRES) {
render.sql("E'")
.sql(PostgresUtils.toPGString(binary))
.keyword("'::bytea");
}
// This default behaviour is used in debug logging for dialects
// that do not support inlining binary data
else {
render.sql("X'")
.sql(convertBytesToHex(binary))
.sql('\'');
}
}
// Interval extends Number, so let Interval come first!
else if (Interval.class.isAssignableFrom(type)) {
render.sql('\'')
.sql(escape(val, render))
.sql('\'');
}
// [#5249] Special inlining of special floating point values
else if (Double.class.isAssignableFrom(type) && ((Double) val).isNaN()) {
if (POSTGRES == family)
render.visit(inline("NaN")).sql("::").keyword("float8");
else
render.sql(((Number) val).toString());
}
// [#5249] Special inlining of special floating point values
else if (Float.class.isAssignableFrom(type) && ((Float) val).isNaN()) {
if (POSTGRES == family)
render.visit(inline("NaN")).sql("::").keyword("float4");
else
render.sql(((Number) val).toString());
}
else if (Number.class.isAssignableFrom(type)) {
render.sql(((Number) val).toString());
}
// [#1156] Date/Time data types should be inlined using JDBC
// escape syntax
else if (type == Date.class) {
// The SQLite JDBC driver does not implement the escape syntax
// [#1253] SQL Server and Sybase do not implement date literals
if (asList(SQLITE).contains(family)) {
render.sql('\'').sql(escape(val, render)).sql('\'');
}
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
render.keyword("date('").sql(escape(val, render)).sql("')");
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
render.keyword("{d '").sql(escape(val, render)).sql("'}");
}
// Most dialects implement SQL standard date literals
else {
render.keyword("date '").sql(escape(val, render)).sql('\'');
}
}
else if (type == Timestamp.class) {
// The SQLite JDBC driver does not implement the escape syntax
// [#1253] SQL Server and Sybase do not implement timestamp literals
if (asList(SQLITE).contains(family)) {
render.sql('\'').sql(escape(val, render)).sql('\'');
}
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
render.keyword("timestamp('").sql(escape(val, render)).sql("')");
}
// CUBRID timestamps have no fractional seconds
else if (family == CUBRID) {
render.keyword("datetime '").sql(escape(val, render)).sql('\'');
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
render.keyword("{ts '").sql(escape(val, render)).sql("'}");
}
// Most dialects implement SQL standard timestamp literals
else {
render.keyword("timestamp '").sql(escape(val, render)).sql('\'');
}
}
else if (type == Time.class) {
// The SQLite JDBC driver does not implement the escape syntax
// [#1253] SQL Server and Sybase do not implement time literals
if (asList(SQLITE).contains(family)) {
render.sql('\'').sql(new SimpleDateFormat("HH:mm:ss").format((Time) val)).sql('\'');
}
// [#1253] Derby doesn't support the standard literal
else if (family == DERBY) {
render.keyword("time").sql("('").sql(escape(val, render)).sql("')");
}
// [#3648] Circumvent a MySQL bug related to date literals
else if (family == MYSQL) {
render.keyword("{t '").sql(escape(val, render)).sql("'}");
}
// Most dialects implement SQL standard time literals
else {
render.keyword("time").sql(" '").sql(escape(val, render)).sql('\'');
}
}
else if (type.isArray()) {
String separator = "";
// H2 renders arrays as rows
if (family == H2) {
render.sql('(');
for (Object o : ((Object[]) val)) {
render.sql(separator);
new DefaultBinding