@Override public final String formatJSON() { List<Map<String, String>> f = new ArrayList<Map<String, String>>(); List<List<Object>> r = new ArrayList<List<Object>>(); Map<String, String> fieldMap; for (Field<?> field : fields) { fieldMap = new LinkedHashMap<String, String>(); fieldMap.put("name", field.getName()); fieldMap.put("type", field.getDataType().getTypeName().toUpperCase()); f.add(fieldMap); } for (Record record : this) { List<Object> list = new ArrayList<Object>(); for (int index = 0; index < fields.fields.length; index++) { list.add(record.getValue(index)); } r.add(list); } Map<String, List<?>> map = new LinkedHashMap<String, List<?>>(); map.put("fields", f); map.put("records", r); return JSONObject.toJSONString(map); }
/** * Get the returning record in those dialects that do not support fetching arbitrary fields from * JDBC's {@link Statement#getGeneratedKeys()} method. */ @SuppressWarnings("unchecked") private final void selectReturning(Configuration configuration, Object... values) { if (values != null && values.length > 0) { // This shouldn't be null, as relevant dialects should // return empty generated keys ResultSet if (into.getIdentity() != null) { Field<Number> field = (Field<Number>) into.getIdentity().getField(); Number[] ids = new Number[values.length]; for (int i = 0; i < values.length; i++) { ids[i] = field.getDataType().convert(values[i]); } // Only the IDENTITY value was requested. No need for an // additional query if (returning.size() == 1 && new Fields(returning).field(field) != null) { for (Number id : ids) { R typed = Utils.newRecord(into, configuration); ((AbstractRecord) typed).setValue(field, new Value<Number>(id)); getReturnedRecords().add(typed); } } // Other values are requested, too. Run another query else { returned = create(configuration) .select(returning) .from(into) .where(field.in(ids)) .fetchInto(into); } } } }
Expression(ExpressionOperator operator, Field<T> lhs, Field<?>... rhs) { super(operator.toSQL(), lhs.getDataType(), Util.combine(lhs, rhs)); this.operator = operator; this.lhs = lhs; this.rhs = new FieldList(); this.rhs.addAll(Arrays.asList(rhs)); }
@SuppressWarnings({"unchecked"}) ArrayTable(Field<?> array, String alias) { super(alias); Class<?> arrayType; // TODO [#523] Solve this in a more object-oriented way... if (array.getDataType().getType().isArray()) { arrayType = array.getDataType().getType().getComponentType(); } // [#1110] Keep track of element type information of Oracle VARRAY / TABLE types else if (array instanceof ArrayConstant) { arrayType = array.getDataType().getType(); } // [#1111] Keep track of element type information of Oracle // VARRAY / TABLE types returned from functions else if (ArrayRecord.class.isAssignableFrom(array.getDataType().getType())) { // TODO [#523] This information should be available in ARRAY meta-data ArrayRecord<?> dummy = Utils.newArrayRecord( (Class<ArrayRecord<?>>) array.getDataType().getType(), new DefaultConfiguration()); arrayType = dummy.getDataType().getType(); } // Is this case possible? else { arrayType = Object.class; } this.array = array; this.alias = alias; this.field = init(alias, arrayType); init(alias, arrayType); }
@Override public final String formatXML() { final int size = getFields().size(); StringBuilder sb = new StringBuilder(); sb.append("<result xmlns=\"http://www.jooq.org/xsd/jooq-export-2.6.0.xsd\">"); sb.append("<fields>"); for (Field<?> field : getFields()) { sb.append("<field name=\""); sb.append(escapeXML(field.getName())); sb.append("\" "); sb.append("type=\""); sb.append(field.getDataType().getTypeName().toUpperCase()); sb.append("\"/>"); } sb.append("</fields>"); sb.append("<records>"); for (Record record : this) { sb.append("<record>"); for (int index = 0; index < size; index++) { Field<?> field = getField(index); Object value = record.getValue(index); sb.append("<value field=\""); sb.append(escapeXML(field.getName())); sb.append("\""); if (value == null) { sb.append("/>"); } else { sb.append(">"); sb.append(escapeXML(format0(value))); sb.append("</value>"); } } sb.append("</record>"); } sb.append("</records>"); sb.append("</result>"); return sb.toString(); }
@Override public final Document intoXML() { final int size = getFields().size(); try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.newDocument(); Element eResult = document.createElement("result"); eResult.setAttribute("xmlns", "http://www.jooq.org/xsd/jooq-export-2.6.0.xsd"); document.appendChild(eResult); Element eFields = document.createElement("fields"); eResult.appendChild(eFields); for (Field<?> field : getFields()) { Element eField = document.createElement("field"); eField.setAttribute("name", field.getName()); eField.setAttribute("type", field.getDataType().getTypeName().toUpperCase()); eFields.appendChild(eField); } Element eRecords = document.createElement("records"); eResult.appendChild(eRecords); for (Record record : this) { Element eRecord = document.createElement("record"); eRecords.appendChild(eRecord); for (int index = 0; index < size; index++) { Field<?> field = getField(index); Object value = record.getValue(index); Element eValue = document.createElement("value"); eValue.setAttribute("field", field.getName()); eRecord.appendChild(eValue); if (value != null) { eValue.setTextContent(format0(value)); } } } return document; } catch (ParserConfigurationException ignore) { throw new RuntimeException(ignore); } }
private final Table<Record> table(Configuration configuration) { switch (configuration.getDialect()) { case ORACLE: { if (array.getDataType().getType().isArray()) { return simulate().as(alias); } else { return new OracleArrayTable().as(alias); } } case H2: { return new H2ArrayTable().as(alias); } // [#756] These dialects need special care when aliasing unnested // arrays case HSQLDB: case POSTGRES: { return new PostgresHSQLDBTable().as(alias); } // Other dialects can simulate unnested arrays using UNION ALL default: { if (array.getDataType().getType().isArray() && array instanceof Param) { return simulate(); } else { throw new SQLDialectNotSupportedException( "ARRAY TABLE is not supported for " + configuration.getDialect()); } } } }
@Override public R operate(R target) throws MappingException { AbstractRecord source = AbstractRecord.this; try { // [#1522] [#2989] If possible the complete state of this record should be copied onto the // other record if (target instanceof AbstractRecord) { AbstractRecord t = (AbstractRecord) target; // Iterate over target fields, to avoid ambiguities when two source fields share the same // name. for (int targetIndex = 0; targetIndex < t.size(); targetIndex++) { Field<?> targetField = t.field(targetIndex); int sourceIndex = fields.indexOf(targetField); if (sourceIndex >= 0) { DataType<?> targetType = targetField.getDataType(); Value<?> sourceValue = values[sourceIndex]; t.values[targetIndex] = new Value<Object>( targetType.convert(sourceValue.getValue()), targetType.convert(sourceValue.getOriginal()), sourceValue.isChanged()); } } } else { for (Field<?> targetField : target.fields()) { Field<?> sourceField = field(targetField); if (sourceField != null) { Utils.setValue(target, targetField, source, sourceField); } } } return target; } // All reflection exceptions are intercepted catch (Exception e) { throw new MappingException("An error ocurred when mapping record to " + target, e); } }
private static final Fields init(String alias, Class<?> arrayType) { List<Field<?>> result = new ArrayList<Field<?>>(); // [#1114] VARRAY/TABLE of OBJECT have more than one field if (UDTRecord.class.isAssignableFrom(arrayType)) { try { UDTRecord<?> record = (UDTRecord<?>) arrayType.newInstance(); for (Field<?> f : record.fields()) { result.add(fieldByName(f.getDataType(), alias, f.getName())); } } catch (Exception e) { throw new DataTypeException("Bad UDT Type : " + arrayType, e); } } // Simple array types have a synthetic field called "COLUMN_VALUE" else { result.add(fieldByName(Factory.getDataType(arrayType), alias, "COLUMN_VALUE")); } return new Fields(result); }
@Override public final <T> AggregateFilterStep<T> withinGroupOrderBy(Field<T> field) { return new Function<T>("mode", field.getDataType()).withinGroupOrderBy(field); }
public static <T> void writeToSQLOutput(SQLOutput stream, Field<T> field, T value) throws SQLException { Class<? extends T> type = field.getType(); writeToSQLOutput(stream, type, field.getDataType(), value); }
@SuppressWarnings("unchecked") public static <T> T getFromSQLInput(Configuration configuration, SQLInput stream, Field<T> field) throws SQLException { Class<? extends T> type = field.getType(); DataType<T> dataType = field.getDataType(); if (type == Blob.class) { return (T) stream.readBlob(); } else if (type == Boolean.class) { return (T) checkWasNull(stream, Boolean.valueOf(stream.readBoolean())); } else if (type == BigInteger.class) { BigDecimal result = stream.readBigDecimal(); return (T) (result == null ? null : result.toBigInteger()); } else if (type == BigDecimal.class) { return (T) stream.readBigDecimal(); } else if (type == Byte.class) { return (T) checkWasNull(stream, Byte.valueOf(stream.readByte())); } else if (type == byte[].class) { // [#1327] Oracle cannot deserialise BLOBs as byte[] from SQLInput if (dataType.isLob()) { Blob blob = null; try { blob = stream.readBlob(); return (T) (blob == null ? null : blob.getBytes(1, (int) blob.length())); } finally { Util.safeFree(blob); } } else { return (T) stream.readBytes(); } } else if (type == Clob.class) { return (T) stream.readClob(); } else if (type == Date.class) { return (T) stream.readDate(); } else if (type == Double.class) { return (T) checkWasNull(stream, Double.valueOf(stream.readDouble())); } else if (type == Float.class) { return (T) checkWasNull(stream, Float.valueOf(stream.readFloat())); } else if (type == Integer.class) { return (T) checkWasNull(stream, Integer.valueOf(stream.readInt())); } else if (type == Long.class) { return (T) checkWasNull(stream, Long.valueOf(stream.readLong())); } else if (type == Short.class) { return (T) checkWasNull(stream, Short.valueOf(stream.readShort())); } else if (type == String.class) { return (T) stream.readString(); } else if (type == Time.class) { return (T) stream.readTime(); } else if (type == Timestamp.class) { return (T) stream.readTimestamp(); } else if (type == YearToMonth.class) { String string = stream.readString(); return (T) (string == null ? null : YearToMonth.valueOf(string)); } else if (type == DayToSecond.class) { String string = stream.readString(); return (T) (string == null ? null : DayToSecond.valueOf(string)); } else if (type == UByte.class) { String string = stream.readString(); return (T) (string == null ? null : UByte.valueOf(string)); } else if (type == UShort.class) { String string = stream.readString(); return (T) (string == null ? null : UShort.valueOf(string)); } else if (type == UInteger.class) { String string = stream.readString(); return (T) (string == null ? null : UInteger.valueOf(string)); } else if (type == ULong.class) { String string = stream.readString(); return (T) (string == null ? null : ULong.valueOf(string)); } // The type byte[] is handled earlier. byte[][] can be handled here else if (type.isArray()) { Array result = stream.readArray(); return (T) (result == null ? null : result.getArray()); } else if (ArrayRecord.class.isAssignableFrom(type)) { return (T) getArrayRecord(configuration, stream.readArray(), (Class<? extends ArrayRecord<?>>) type); } else if (EnumType.class.isAssignableFrom(type)) { return getEnumType(type, stream.readString()); } else if (MasterDataType.class.isAssignableFrom(type)) { return (T) getMasterDataType(type, stream.readObject()); } else if (UDTRecord.class.isAssignableFrom(type)) { return (T) stream.readObject(); } else { return (T) stream.readObject(); } }
Nvl(Field<T> arg1, Field<T> arg2) { super("nvl", arg1.getDataType(), arg1, arg2); this.arg1 = arg1; this.arg2 = arg2; }
MutablePOJOMapper(Constructor<? extends E> constructor, E instance) { this.constructor = accessible(constructor); this.useAnnotations = hasColumnAnnotations(configuration, type); this.members = new List[fields.length]; this.methods = new List[fields.length]; this.nested = new HashMap<String, List<RecordMapper<R, Object>>>(); this.instance = instance; Map<String, Field<?>[]> nestedFields = new HashMap<String, Field<?>[]>(); for (int i = 0; i < fields.length; i++) { Field<?> field = fields[i]; String name = field.getName(); // Annotations are available and present if (useAnnotations) { members[i] = getAnnotatedMembers(configuration, type, name); methods[i] = getAnnotatedSetters(configuration, type, name); } // No annotations are present else { int dot = name.indexOf('.'); // A nested mapping is applied if (dot > -1) { String prefix = name.substring(0, dot); Field<?>[] f = nestedFields.get(prefix); if (f == null) { f = nCopies(fields.length, field("")).toArray(new Field[fields.length]); nestedFields.put(prefix, f); } f[i] = field(name(name.substring(prefix.length() + 1)), field.getDataType()); members[i] = Collections.emptyList(); methods[i] = Collections.emptyList(); } // A top-level mapping is applied else { members[i] = getMatchingMembers(configuration, type, name); methods[i] = getMatchingSetters(configuration, type, name); } } } for (Entry<String, Field<?>[]> entry : nestedFields.entrySet()) { String prefix = entry.getKey(); List<RecordMapper<R, Object>> list = new ArrayList<RecordMapper<R, Object>>(); for (java.lang.reflect.Field member : getMatchingMembers(configuration, type, prefix)) { list.add( new RemovingPrefixRecordMapper( new DefaultRecordMapper<R, Object>( new Fields<R>(entry.getValue()), member.getType(), null, configuration), fields, prefix)); } for (Method method : getMatchingSetters(configuration, type, prefix)) { list.add( new RemovingPrefixRecordMapper( new DefaultRecordMapper<R, Object>( new Fields<R>(entry.getValue()), method.getParameterTypes()[0], null, configuration), fields, prefix)); } nested.put(prefix, list); } }
@SuppressWarnings("unchecked") @Override final Field<T> getFunction0(Configuration configuration) { SQLDialect dialect = configuration.getDialect(); // --------------------------------------------------------------------- // XXX: Bitwise operators // --------------------------------------------------------------------- // DB2, H2 and HSQLDB know functions, instead of operators if (BIT_AND == operator && asList(DB2, H2, HSQLDB, ORACLE).contains(dialect)) { return function("bitand", getDataType(), getArguments()); } else if (BIT_AND == operator && FIREBIRD == dialect) { return function("bin_and", getDataType(), getArguments()); } else if (BIT_XOR == operator && asList(DB2, H2, HSQLDB).contains(dialect)) { return function("bitxor", getDataType(), getArguments()); } else if (BIT_XOR == operator && FIREBIRD == dialect) { return function("bin_xor", getDataType(), getArguments()); } else if (BIT_OR == operator && asList(DB2, H2, HSQLDB).contains(dialect)) { return function("bitor", getDataType(), getArguments()); } else if (BIT_OR == operator && FIREBIRD == dialect) { return function("bin_or", getDataType(), getArguments()); } // Oracle has to simulate or/xor else if (BIT_OR == operator && ORACLE == dialect) { return lhs.sub(bitAnd(lhsAsNumber(), rhsAsNumber())).add(rhsAsNumber()); } // ~(a & b) & (a | b) else if (BIT_XOR == operator && asList(ORACLE, SQLITE).contains(dialect)) { return (Field<T>) bitAnd(bitNot(bitAnd(lhsAsNumber(), rhsAsNumber())), bitOr(lhsAsNumber(), rhsAsNumber())); } // Many dialects don't support shifts. Use multiplication/division instead else if (SHL == operator && asList(ASE, DB2, H2, HSQLDB, INGRES, ORACLE, SQLSERVER, SYBASE).contains(dialect)) { return lhs.mul(Factory.power(two(), rhsAsNumber())); } else if (SHR == operator && asList(ASE, DB2, H2, HSQLDB, INGRES, ORACLE, SQLSERVER, SYBASE).contains(dialect)) { return lhs.div(Factory.power(two(), rhsAsNumber())); } // Some dialects support shifts as functions else if (SHL == operator && FIREBIRD == dialect) { return function("bin_shl", getDataType(), getArguments()); } else if (SHR == operator && FIREBIRD == dialect) { return function("bin_shr", getDataType(), getArguments()); } // These operators are not supported in any dialect else if (BIT_NAND == operator) { return (Field<T>) bitNot(bitAnd(lhsAsNumber(), rhsAsNumber())); } else if (BIT_NOR == operator) { return (Field<T>) bitNot(bitOr(lhsAsNumber(), rhsAsNumber())); } else if (BIT_XNOR == operator) { return (Field<T>) bitNot(bitXor(lhsAsNumber(), rhsAsNumber())); } // --------------------------------------------------------------------- // XXX: Date time arithmetic operators // --------------------------------------------------------------------- // [#585] Date time arithmetic for numeric or interval RHS else if (asList(ADD, SUBTRACT).contains(operator) && lhs.getDataType().isDateTime() && (rhs.get(0).getDataType().isNumeric() || rhs.get(0).getDataType().isInterval())) { return new DateExpression(); } // --------------------------------------------------------------------- // XXX: Other operators // --------------------------------------------------------------------- // Use the default operator expression for all other cases else { return new DefaultExpression(); } }
FieldAlias(Field<T> field, String alias) { super(alias, field.getDataType()); this.alias = new Alias<Field<T>>(field, alias, false); }
Neg(Field<T> field, ExpressionOperator operator) { super(operator.toSQL() + field.getName(), field.getDataType()); this.operator = operator; this.field = field; }