package org.postgresql.core.v3;
import org.postgresql.core.NativeQuery;
import org.postgresql.core.ParameterList;
public class BatchedQuery extends SimpleQuery {
private String sql;
private final int valuesBraceOpenPosition;
private final int valuesBraceClosePosition;
private final int batchSize;
private BatchedQuery[] blocks;
public BatchedQuery(NativeQuery query, TypeTransferModeRegistry transferModeRegistry,
int valuesBraceOpenPosition,
int valuesBraceClosePosition, boolean sanitiserDisabled) {
super(query, transferModeRegistry, sanitiserDisabled);
this.valuesBraceOpenPosition = valuesBraceOpenPosition;
this.valuesBraceClosePosition = valuesBraceClosePosition;
this.batchSize = 1;
}
private BatchedQuery(BatchedQuery src, int batchSize) {
super(src);
this.valuesBraceOpenPosition = src.valuesBraceOpenPosition;
this.valuesBraceClosePosition = src.valuesBraceClosePosition;
this.batchSize = batchSize;
}
public BatchedQuery deriveForMultiBatch(int valueBlock) {
if (getBatchSize() != 1) {
throw new IllegalStateException("Only the original decorator can be derived.");
}
if (valueBlock == 1) {
return this;
}
int index = Integer.numberOfTrailingZeros(valueBlock) - 1;
if (valueBlock > 128 || valueBlock != (1 << (index + 1))) {
throw new IllegalArgumentException(
"Expected value block should be a power of 2 smaller or equal to 128. Actual block is "
+ valueBlock);
}
if (blocks == null) {
blocks = new BatchedQuery[7];
}
BatchedQuery bq = blocks[index];
if (bq == null) {
bq = new BatchedQuery(this, valueBlock);
blocks[index] = bq;
}
return bq;
}
@Override
public int getBatchSize() {
return batchSize;
}
@Override
public String getNativeSql() {
if (sql != null) {
return sql;
}
sql = buildNativeSql(null);
return sql;
}
private String buildNativeSql(ParameterList params) {
String sql = null;
String nativeSql = super.getNativeSql();
int batchSize = getBatchSize();
if (batchSize < 2) {
sql = nativeSql;
return sql;
}
if (nativeSql == null) {
sql = "";
return sql;
}
int valuesBlockCharCount = 0;
int[] bindPositions = getNativeQuery().bindPositions;
int[] chunkStart = new int[1 + bindPositions.length];
int[] chunkEnd = new int[1 + bindPositions.length];
chunkStart[0] = valuesBraceOpenPosition;
if (bindPositions.length == 0) {
valuesBlockCharCount = valuesBraceClosePosition - valuesBraceOpenPosition + 1;
chunkEnd[0] = valuesBraceClosePosition + 1;
} else {
chunkEnd[0] = bindPositions[0];
valuesBlockCharCount += chunkEnd[0] - chunkStart[0];
for (int i = 0; i < bindPositions.length; i++) {
int startIndex = bindPositions[i] + 2;
int endIndex =
i < bindPositions.length - 1 ? bindPositions[i + 1] : valuesBraceClosePosition + 1;
for (; startIndex < endIndex; startIndex++) {
if (!Character.isDigit(nativeSql.charAt(startIndex))) {
break;
}
}
chunkStart[i + 1] = startIndex;
chunkEnd[i + 1] = endIndex;
valuesBlockCharCount += chunkEnd[i + 1] - chunkStart[i + 1];
}
}
int length = nativeSql.length();
length += NativeQuery.calculateBindLength(bindPositions.length * batchSize);
length -= NativeQuery.calculateBindLength(bindPositions.length);
length += (valuesBlockCharCount + 1 ) * (batchSize - 1 );
StringBuilder s = new StringBuilder(length);
int pos;
if (bindPositions.length > 0 && params == null) {
s.append(nativeSql, 0, valuesBraceClosePosition + 1);
pos = bindPositions.length + 1;
} else {
pos = 1;
batchSize++;
s.append(nativeSql, 0, valuesBraceOpenPosition);
}
for (int i = 2; i <= batchSize; i++) {
if (i > 2 || pos != 1) {
s.append(',');
}
s.append(nativeSql, chunkStart[0], chunkEnd[0]);
for (int j = 1; j < chunkStart.length; j++) {
if (params == null) {
NativeQuery.appendBindName(s, pos++);
} else {
s.append(params.toString(pos++, true));
}
s.append(nativeSql, chunkStart[j], chunkEnd[j]);
}
}
s.append(nativeSql, valuesBraceClosePosition + 1, nativeSql.length());
sql = s.toString();
assert params != null || s.length() == length
: "Predicted length != actual: " + length + " !=" + s.length();
return sql;
}
@Override
public String toString(ParameterList params) {
if (getBatchSize() < 2) {
return super.toString(params);
}
return buildNativeSql(params);
}
}