Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ default E encodeNull(){

D decode(Object data);

default E encodeNull(ColumnMetadata column){
return encodeNull();
}

default E encode(Object value, ColumnMetadata column){
return encode(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public Object decode(Object data) {
public Object encode(Object data) {
if (data == null) {
if (valueCodec != null) {
return valueCodec.encodeNull();
return valueCodec.encodeNull(this);
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import lombok.SneakyThrows;
import org.hswebframework.ezorm.core.ValueCodec;
import org.hswebframework.ezorm.core.meta.ColumnMetadata;
import org.hswebframework.ezorm.rdb.executor.NullValue;
import org.hswebframework.ezorm.rdb.metadata.DataType;
import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata;
import org.hswebframework.ezorm.rdb.supports.oracle.OracleDialect;
import org.hswebframework.ezorm.rdb.utils.FeatureUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
Expand All @@ -21,14 +24,29 @@ public class ClobValueCodec implements ValueCodec {

public static final ClobValueCodec INSTANCE = new ClobValueCodec();

public static boolean isClobType(DataType type) {
return type.getSqlType() == JDBCType.LONGVARCHAR ||
type.getSqlType() == JDBCType.LONGNVARCHAR ||
type.getSqlType() == JDBCType.CLOB;
}

@Override
public Object encodeNull(ColumnMetadata column) {
if (column instanceof RDBColumnMetadata col) {
if (ClobValueCodec.isClobType(col.getType())) {
return NullValue.of(LongCharSequence.class, col.getType());
}
return NullValue.of(col.getType());
}
return null;
}

@Override
public Object encode(Object value, ColumnMetadata column) {
Object val = this.encode(value);
if (val instanceof CharSequence cs && column instanceof RDBColumnMetadata col) {
if (col.getType().getSqlType() == JDBCType.LONGVARCHAR ||
col.getType().getSqlType() == JDBCType.LONGNVARCHAR ||
col.getType().getSqlType() == JDBCType.CLOB) {
return new ClobValue(cs);
if (ClobValueCodec.isClobType(col.getType())) {
return new LongCharSequence(cs);
}
}
return val;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@
import lombok.extern.slf4j.Slf4j;
import org.hswebframework.ezorm.core.ValueCodec;
import org.hswebframework.ezorm.core.meta.ColumnMetadata;
import org.hswebframework.ezorm.rdb.executor.NullValue;
import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata;
import org.hswebframework.ezorm.rdb.utils.FeatureUtils;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.JDBCType;
import java.util.Collection;
import java.util.Map;
import java.util.TimeZone;
Expand Down Expand Up @@ -104,15 +105,25 @@ public JsonValueCodec(Class<?> targetType, JavaType type) {
this.targetType = targetType;
}

@Override
public Object encodeNull(ColumnMetadata column) {
if (column instanceof RDBColumnMetadata col) {
// clob 类型
if (ClobValueCodec.isClobType(col.getType())) {
return NullValue.of(LongCharSequence.class, col.getType());
}
return NullValue.of(col.getType());
}
return ValueCodec.super.encodeNull(column);
}

@Override
public Object encode(Object value, ColumnMetadata column) {
Object data = encode(value);
if (data instanceof CharSequence cs && column instanceof RDBColumnMetadata col) {
// clob 类型
if (col.getType().getSqlType() == JDBCType.LONGVARCHAR ||
col.getType().getSqlType() == JDBCType.LONGNVARCHAR ||
col.getType().getSqlType() == JDBCType.CLOB) {
return new ClobValue(cs);
if (ClobValueCodec.isClobType(col.getType())) {
return new LongCharSequence(cs);
}
}
return data;
Expand Down Expand Up @@ -149,27 +160,29 @@ public Object decode(Object data) {
try {
Object target = data;

if (data instanceof Clob) {
target = mapper.readValue(((Clob) data).getCharacterStream(), jacksonType);
} else if (data instanceof Blob) {
target = mapper.readValue(((Blob) data).getBinaryStream(), jacksonType);
if (data instanceof Clob _clob) {
target = mapper.readValue(_clob.getCharacterStream(), jacksonType);
} else if (data instanceof Blob _blob) {
target = mapper.readValue(_blob.getBinaryStream(), jacksonType);
} else if (data instanceof InputStream) {
target = mapper.readValue((InputStream) data, jacksonType);
} else if (data instanceof byte[]) {
target = mapper.readValue((byte[]) data, jacksonType);
} else if (data instanceof String) {
target = doRead(((String) data));
} else if (data instanceof byte[] bytes) {
target = mapper.readValue(bytes, jacksonType);
} else if (data instanceof CharSequence) {
target = doRead(String.valueOf(data));
} else if (data instanceof Reader reader) {
target = mapper.readValue(reader, jacksonType);
} else if (data instanceof ByteBuffer) {
return doRead(new ByteBufferBackedInputStream(((ByteBuffer) data)));
} else if (FeatureUtils.r2dbcIsAlive()) {
Mono<?> mono = null;
if (data instanceof io.r2dbc.spi.Clob) {
mono = Flux.from(((io.r2dbc.spi.Clob) data).stream())
if (data instanceof io.r2dbc.spi.Clob _clob) {
mono = Flux.from(_clob.stream())
.collect(Collectors.joining())
.map(this::doRead);

} else if (data instanceof io.r2dbc.spi.Blob) {
mono = Mono.from(((io.r2dbc.spi.Blob) data).stream())
} else if (data instanceof io.r2dbc.spi.Blob _blob) {
mono = Mono.from(_blob.stream())
.map(ByteBufferBackedInputStream::new)
.map(this::doRead);
}
Expand All @@ -194,6 +207,9 @@ public Object decode(Object data) {
if (targetType == Flux.class) {
return target == null ? Flux.empty() : Flux.just(target);
}
if (target == null) {
return null;
}
log.warn("unsupported json format:{}", data);
return target;
} catch (Throwable e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package org.hswebframework.ezorm.rdb.codec;

import org.reactivestreams.Publisher;
import reactor.util.annotation.NonNull;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.stream.IntStream;

public class ClobValue implements CharSequence {
public class LongCharSequence implements CharSequence {

private final CharSequence charSequence;

public ClobValue(CharSequence charSequence) {
public LongCharSequence(CharSequence charSequence) {
this.charSequence = charSequence;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@
@Getter
@AllArgsConstructor(staticName = "of")
public class NullValue {
@Deprecated
private Class type;

@NonNull
private Class<?> type;

private DataType dataType;

public static NullValue of(DataType dataType){
return of(dataType.getJavaType(),dataType);
public static NullValue of(DataType dataType) {
return of(dataType.getJavaType(), dataType);
}

public Class<?> getType() {
return type == null ? dataType.getJavaType() : type;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Null Pointers: Inconsistent Null Handling.

The getType() method can throw NullPointerException when type is null and dataType is also null, since it calls dataType.getJavaType() without null-checking dataType. The @NonNull annotation was removed from the dataType field, allowing null values, but the getter doesn't handle this case.

Fix in Cursor Fix in Web

}

@Override
public String toString() {
return "null" + (dataType==null?"": (type != null ? "(" + dataType.getId() + ")" : ""));
return "null" + (type != null ? "("+type.getSimpleName()+")" : (dataType != null ? "(" + dataType.getId() + ")" : ""));
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package org.hswebframework.ezorm.rdb.executor.jdbc;

import lombok.SneakyThrows;
import org.hswebframework.ezorm.rdb.codec.ClobValue;
import org.hswebframework.ezorm.rdb.codec.LongCharSequence;
import org.hswebframework.ezorm.rdb.executor.NullValue;

import javax.sql.rowset.serial.SerialClob;
import java.io.ByteArrayInputStream;
import java.io.CharArrayReader;
import java.io.StringReader;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
Expand Down Expand Up @@ -38,18 +37,17 @@ protected static void preparedStatementParameter(PreparedStatement statement, Ob
for (Object object : parameter) {
if (object == null) {
statement.setNull(index++, Types.NULL);
} else if (object instanceof NullValue) {
statement.setNull(index++, ((NullValue) object).getDataType().getSqlType().getVendorTypeNumber());
} else if (object instanceof NullValue nullValue) {
statement.setNull(index++, nullValue.getDataType().getSqlType().getVendorTypeNumber());
} else if (object instanceof Date) {
statement.setTimestamp(index++, new java.sql.Timestamp(((Date) object).getTime()));
} else if (object instanceof byte[] b) {
statement.setBlob(index++, new ByteArrayInputStream(b));
} else if (object instanceof ClobValue cb) {
} else if (object instanceof LongCharSequence cb) {
statement.setCharacterStream(index++, cb.reader());
} else {
statement.setObject(index++, object);
}

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.hswebframework.ezorm.core.CastUtil;
import org.hswebframework.ezorm.rdb.codec.ClobValue;
import org.hswebframework.ezorm.rdb.codec.LongCharSequence;
import org.hswebframework.ezorm.rdb.executor.BatchSqlRequest;
import org.hswebframework.ezorm.rdb.executor.DefaultColumnWrapperContext;
import org.hswebframework.ezorm.rdb.executor.NullValue;
Expand Down Expand Up @@ -251,11 +251,18 @@ protected Statement prepareStatement(Statement statement, SqlRequest request) {
for (Object parameter : request.getParameters()) {
if (parameter == null) {
bindNull(statement, index, String.class);
} else if (parameter instanceof NullValue) {
bindNull(statement, index, ((NullValue) parameter).getDataType().getJavaType());
} else if (parameter instanceof NullValue nullValue) {
Class<?> javaType = nullValue.getType();
if (javaType == LongCharSequence.class) {
// 空字符,批量保存时,有的数据库不同行不能有的设置null有的不设置.
bindNull(statement, index, Clob.class);
}else {
bindNull(statement, index, javaType);
}

} else {
// convert clob
if (parameter instanceof ClobValue cb) {
if (parameter instanceof LongCharSequence cb) {
parameter = Clob.from(Mono.just(cb.source()));
}
bind(statement, index, parameter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ public RDBColumnMetadata clone() {
public Object encode(Object data) {
if (data == null || data instanceof NullValue) {
if (valueCodec != null) {
Object newVal = valueCodec.encodeNull();
Object newVal = valueCodec.encodeNull(this);
if (newVal != null) {
return newVal;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package org.hswebframework.ezorm.rdb.supports.oracle;

import io.r2dbc.mssql.codec.ClobCodec;
import lombok.AllArgsConstructor;
import org.hswebframework.ezorm.core.RuntimeDefaultValue;
import org.hswebframework.ezorm.core.param.Term;
import org.hswebframework.ezorm.rdb.codec.ClobValueCodec;
import org.hswebframework.ezorm.rdb.codec.LongCharSequence;
import org.hswebframework.ezorm.rdb.executor.NullValue;
import org.hswebframework.ezorm.rdb.executor.SqlRequest;
import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor;
Expand Down Expand Up @@ -188,9 +191,15 @@ public SqlRequest build(InsertOperatorParameter parameter) {
value = NullValue.of(column.getType());
}
}

value = column.encode(value);
// 适配 clob字段 不支持设置null
if (valueSize > 1 && (value == null || value instanceof NullValue)) {
if (ClobValueCodec.isClobType(column.getType())) {
value = new LongCharSequence("");
}
}
fragments.addSql("? as ", column.getQuoteName())
.addParameter(column.encode(value));
.addParameter(value);
valueIndex++;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.hswebframework.ezorm.core.RuntimeDefaultValue;
import org.hswebframework.ezorm.rdb.codec.ClobValueCodec;
import org.hswebframework.ezorm.rdb.codec.LongCharSequence;
import org.hswebframework.ezorm.rdb.executor.NullValue;
import org.hswebframework.ezorm.rdb.executor.SqlRequest;
import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata;
Expand Down Expand Up @@ -126,7 +128,14 @@ public SqlRequest build(InsertOperatorParameter parameter) {
if (value == null) {
value = NullValue.of(column.getType());
}
valuesSql.add(SqlFragments.QUESTION_MARK).addParameter(column.encode(value));
value = column.encode(value);
// 适配 clob字段 不支持设置null
if (valueSize > 1 && (value == null || value instanceof NullValue)) {
if (ClobValueCodec.isClobType(column.getType())) {
value = new LongCharSequence("");
}
}
valuesSql.add(SqlFragments.QUESTION_MARK).addParameter(value);
}
intoSql.add(SqlFragments.RIGHT_BRACKET);
valuesSql.add(SqlFragments.RIGHT_BRACKET);
Expand Down
Loading
Loading