/
NikolayIvkin
/
sqlancer2
Обзор
Документация
Войти
/
NikolayIvkin
/
sqlancer2
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/sqlancer/sqlite3/ast/SQLite3Constant.java
625 строк
20 KB
Jinsheng Ba
Deterministic Hex and Dec for SQLite3
17 май 2022, 16:02
17 май 2022, 16:02
7080326
Код
Авторство
О чём код?
package sqlancer.sqlite3.ast; import java.math.BigDecimal; import java.util.regex.Matcher; import java.util.regex.Pattern; import sqlancer.Randomly; import sqlancer.sqlite3.SQLite3Visitor; import sqlancer.sqlite3.schema.SQLite3DataType; import sqlancer.sqlite3.schema.SQLite3Schema.SQLite3Column.SQLite3CollateSequence; public abstract class SQLite3Constant extends SQLite3Expression { public static class SQLite3NullConstant extends SQLite3Constant { @Override public boolean isNull() { return true; } @Override public Object getValue() { return null; } @Override public SQLite3DataType getDataType() { return SQLite3DataType.NULL; } @Override public SQLite3Constant applyEquals(SQLite3Constant right, SQLite3CollateSequence collate) { return SQLite3Constant.createNullConstant(); } @Override public SQLite3Constant applyNumericAffinity() { return this; } @Override public SQLite3Constant applyTextAffinity() { return this; } @Override String getStringRepresentation() { return "NULL"; } @Override public SQLite3Constant castToBoolean() { return SQLite3Cast.asBoolean(this); } @Override public SQLite3Constant applyLess(SQLite3Constant right, SQLite3CollateSequence collate) { return SQLite3Constant.createNullConstant(); } } public static class SQLite3IntConstant extends SQLite3Constant { private final long value; private final boolean isHex; public SQLite3IntConstant(long value, boolean isHex) { this.value = value; this.isHex = isHex; } public SQLite3IntConstant(long value) { this.value = value; this.isHex = false; } @Override public boolean isHex() { return isHex; } @Override public boolean isNull() { return false; } @Override public long asInt() { return value; } @Override public Object getValue() { return value; } @Override public SQLite3DataType getDataType() { return SQLite3DataType.INT; } @Override public SQLite3Constant applyEquals(SQLite3Constant right, SQLite3CollateSequence collate) { if (right instanceof SQLite3RealConstant) { if (Double.isInfinite(right.asDouble())) { return SQLite3Constant.createFalse(); } BigDecimal otherColumnValue = BigDecimal.valueOf(right.asDouble()); BigDecimal thisColumnValue = BigDecimal.valueOf(value); return SQLite3Constant.createBoolean(thisColumnValue.compareTo(otherColumnValue) == 0); } else if (right instanceof SQLite3IntConstant) { return SQLite3Constant.createBoolean(value == right.asInt()); } else if (right instanceof SQLite3NullConstant) { return SQLite3Constant.createNullConstant(); } else { return SQLite3Constant.createFalse(); } } @Override public SQLite3Constant applyNumericAffinity() { return this; } @Override public SQLite3Constant applyTextAffinity() { return SQLite3Constant.createTextConstant(String.valueOf(value)); } @Override String getStringRepresentation() { return String.valueOf(value); } @Override public SQLite3Constant castToBoolean() { return SQLite3Cast.asBoolean(this); } @Override public SQLite3Constant applyLess(SQLite3Constant right, SQLite3CollateSequence collate) { if (right.isNull()) { return right; } else if (right.getDataType() == SQLite3DataType.TEXT || right.getDataType() == SQLite3DataType.BINARY) { return SQLite3Constant.createTrue(); } else if (right.getDataType() == SQLite3DataType.INT) { long rightValue = right.asInt(); return SQLite3Constant.createBoolean(value < rightValue); } else { if (Double.POSITIVE_INFINITY == right.asDouble()) { return SQLite3Constant.createTrue(); } else if (Double.NEGATIVE_INFINITY == right.asDouble()) { return SQLite3Constant.createFalse(); } assert right.getDataType() == SQLite3DataType.REAL; BigDecimal otherColumnValue = BigDecimal.valueOf(right.asDouble()); BigDecimal thisColumnValue = BigDecimal.valueOf(value); return SQLite3Constant.createBoolean(thisColumnValue.compareTo(otherColumnValue) < 0); } } } public static class SQLite3RealConstant extends SQLite3Constant { private final double value; public SQLite3RealConstant(double value) { this.value = value; } @Override public boolean isNull() { return false; } @Override public double asDouble() { return value; } @Override public Object getValue() { return value; } @Override public SQLite3DataType getDataType() { return SQLite3DataType.REAL; } @Override public SQLite3Constant applyEquals(SQLite3Constant right, SQLite3CollateSequence collate) { if (right instanceof SQLite3RealConstant) { return SQLite3Constant.createBoolean(value == right.asDouble()); } else if (right instanceof SQLite3IntConstant) { if (Double.isInfinite(value)) { return SQLite3Constant.createFalse(); } BigDecimal thisColumnValue = BigDecimal.valueOf(value); BigDecimal otherColumnValue = BigDecimal.valueOf(right.asInt()); return SQLite3Constant.createBoolean(thisColumnValue.compareTo(otherColumnValue) == 0); } else if (right instanceof SQLite3NullConstant) { return SQLite3Constant.createNullConstant(); } else { return SQLite3Constant.createFalse(); } } @Override public SQLite3Constant applyNumericAffinity() { return this; } @Override public SQLite3Constant applyTextAffinity() { return SQLite3Cast.castToText(this); } @Override String getStringRepresentation() { return String.valueOf(value); } @Override public SQLite3Constant castToBoolean() { return SQLite3Cast.asBoolean(this); } @Override public SQLite3Constant applyLess(SQLite3Constant right, SQLite3CollateSequence collate) { if (right.isNull()) { return right; } else if (right.getDataType() == SQLite3DataType.TEXT || right.getDataType() == SQLite3DataType.BINARY) { return SQLite3Constant.createTrue(); } else if (right.getDataType() == SQLite3DataType.REAL) { double rightValue = right.asDouble(); return SQLite3Constant.createBoolean(value < rightValue); } else { if (Double.POSITIVE_INFINITY == value) { return SQLite3Constant.createFalse(); } else if (Double.NEGATIVE_INFINITY == value) { return SQLite3Constant.createTrue(); } assert right.getDataType() == SQLite3DataType.INT; BigDecimal otherColumnValue = BigDecimal.valueOf(right.asInt()); BigDecimal thisColumnValue = BigDecimal.valueOf(value); return SQLite3Constant.createBoolean(thisColumnValue.compareTo(otherColumnValue) < 0); } } } public static class SQLite3TextConstant extends SQLite3Constant { private final String text; public SQLite3TextConstant(String text) { this.text = text; } @Override public boolean isNull() { return false; } @Override public String asString() { return text; } @Override public Object getValue() { return text; } @Override public SQLite3DataType getDataType() { return SQLite3DataType.TEXT; } @Override public SQLite3Constant applyEquals(SQLite3Constant right, SQLite3CollateSequence collate) { if (right.isNull()) { return SQLite3Constant.createNullConstant(); } else if (right instanceof SQLite3TextConstant) { String other = right.asString(); boolean equals; switch (collate) { case BINARY: equals = text.equals(other); break; case NOCASE: equals = toLower(text).equals(toLower(other)); break; case RTRIM: equals = trimTrailing(text).equals(trimTrailing(other)); break; default: throw new AssertionError(collate); } return SQLite3Constant.createBoolean(equals); } else { return SQLite3Constant.createFalse(); } } public static String toLower(String t) { StringBuilder text = new StringBuilder(t); for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); if (c >= 'A' && c <= 'Z') { text.setCharAt(i, Character.toLowerCase(c)); } } return text.toString(); } public static String toUpper(String t) { StringBuilder text = new StringBuilder(t); for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); if (c >= 'a' && c <= 'z') { text.setCharAt(i, Character.toUpperCase(c)); } } return text.toString(); } public static String trim(String str) { return trimLeading(trimTrailing(str)); } public static String trimLeading(String str) { if (str != null) { for (int i = 0; i < str.length(); i++) { if (str.charAt(i) != ' ') { return str.substring(i); } } } return ""; } public static String trimTrailing(String str) { if (str != null) { for (int i = str.length() - 1; i >= 0; --i) { if (str.charAt(i) != ' ') { return str.substring(0, i + 1); } } } return ""; } @Override public SQLite3Constant applyNumericAffinity() { Pattern leadingDigitPattern = Pattern .compile("[-+]?((\\d(\\d)*(\\.(\\d)*)?)|\\.(\\d)(\\d)*)([Ee][+-]?(\\d)(\\d)*)?"); String trimmedString = text.trim(); if (trimmedString.isEmpty()) { return this; } Matcher matcher = leadingDigitPattern.matcher(trimmedString); if (matcher.matches()) { return SQLite3Cast.castToNumeric(this); } else { return this; } } @Override public SQLite3Constant applyTextAffinity() { return this; } @Override String getStringRepresentation() { return text; } @Override public SQLite3Constant castToBoolean() { return SQLite3Cast.asBoolean(this); } @Override public SQLite3Constant applyLess(SQLite3Constant right, SQLite3CollateSequence collate) { if (right.isNull()) { return right; } else if (right.getDataType() == SQLite3DataType.BINARY) { return SQLite3Constant.createTrue(); } else if (right.getDataType() == SQLite3DataType.TEXT) { String other = right.asString(); boolean lessThan; switch (collate) { case BINARY: lessThan = text.compareTo(other) < 0; break; case NOCASE: lessThan = toLower(text).compareTo(toLower(other)) < 0; break; case RTRIM: lessThan = trimTrailing(text).compareTo(trimTrailing(other)) < 0; break; default: throw new AssertionError(collate); } return SQLite3Constant.createBoolean(lessThan); } else { assert right.getDataType() == SQLite3DataType.REAL || right.getDataType() == SQLite3DataType.INT; return SQLite3Constant.createFalse(); } } } public static class SQLite3BinaryConstant extends SQLite3Constant { private final byte[] bytes; public SQLite3BinaryConstant(byte[] bytes) { this.bytes = bytes.clone(); } @Override public boolean isNull() { return false; } @Override public SQLite3DataType getDataType() { return SQLite3DataType.BINARY; } @Override public Object getValue() { return bytes; } @Override public byte[] asBinary() { return bytes.clone(); } @Override public SQLite3Constant applyNumericAffinity() { return this; } @Override public SQLite3Constant applyTextAffinity() { return this; /* * if (bytes.length == 0) { return this; } else { StringBuilder sb = new StringBuilder(); for (byte b : * bytes) { if (isPrintableChar(b)) { sb.append((char) b); } } return * SQLite3Constant.createTextConstant(sb.toString()); } */ } public boolean isPrintableChar(byte b) { return Math.abs(b) >= 32; } @Override String getStringRepresentation() { String hexRepr = SQLite3Visitor.byteArrayToHex(bytes); return String.format("x'%s'", hexRepr); } @Override public SQLite3Constant applyEquals(SQLite3Constant right, SQLite3CollateSequence collate) { if (right.isNull()) { return SQLite3Constant.createNullConstant(); } else if (right.getDataType() == SQLite3DataType.BINARY) { byte[] otherArr = right.asBinary(); if (bytes.length == otherArr.length) { for (int i = 0; i < bytes.length; i++) { if (bytes[i] != otherArr[i]) { return SQLite3Constant.createFalse(); } } return SQLite3Constant.createTrue(); } else { return SQLite3Constant.createFalse(); } } else { return SQLite3Constant.createFalse(); } } @Override public SQLite3Constant castToBoolean() { return SQLite3Cast.asBoolean(this); } @Override public SQLite3Constant applyLess(SQLite3Constant right, SQLite3CollateSequence collate) { if (right.isNull()) { return right; } else if (right.getDataType() == SQLite3DataType.TEXT || right.getDataType() == SQLite3DataType.INT || right.getDataType() == SQLite3DataType.REAL) { return SQLite3Constant.createFalse(); } else { byte[] otherArr = right.asBinary(); int minLength = Math.min(bytes.length, otherArr.length); for (int i = 0; i < minLength; i++) { if (bytes[i] != otherArr[i]) { return SQLite3Constant.createBoolean((bytes[i] & 0xff) < (otherArr[i] & 0xff)); } else if (bytes[i] > otherArr[i]) { return SQLite3Constant.createFalse(); } } return SQLite3Constant.createBoolean(bytes.length < otherArr.length); } } } abstract String getStringRepresentation(); public abstract boolean isNull(); public abstract Object getValue(); public boolean isHex() { throw new UnsupportedOperationException(this.getDataType().toString()); } public long asInt() { throw new UnsupportedOperationException(this.getDataType().toString()); } public double asDouble() { throw new UnsupportedOperationException(this.getDataType().toString()); } public byte[] asBinary() { throw new UnsupportedOperationException(this.getDataType().toString()); } public String asString() { throw new UnsupportedOperationException(this.getDataType().toString()); } public abstract SQLite3DataType getDataType(); public static SQLite3Constant createIntConstant(long val) { return new SQLite3IntConstant(val); } public static SQLite3Constant createIntConstant(long val, boolean isHex) { return new SQLite3IntConstant(val, isHex); } public static SQLite3Constant createBinaryConstant(byte[] val) { return new SQLite3BinaryConstant(val); } public static SQLite3Constant createBinaryConstant(String val) { return new SQLite3BinaryConstant(SQLite3Visitor.hexStringToByteArray(val)); } public static SQLite3Constant createRealConstant(double real) { return new SQLite3RealConstant(real); } public static SQLite3Constant createTextConstant(String text) { return new SQLite3TextConstant(text); } public static SQLite3Constant createNullConstant() { return new SQLite3NullConstant(); } public static SQLite3Constant getRandomBinaryConstant(Randomly r) { return new SQLite3BinaryConstant(r.getBytes()); } @Override public SQLite3Constant getExpectedValue() { return this; } @Override public SQLite3CollateSequence getExplicitCollateSequence() { return null; } @Override public String toString() { return String.format("(%s) %s", getDataType(), getStringRepresentation()); } public abstract SQLite3Constant applyNumericAffinity(); public abstract SQLite3Constant applyTextAffinity(); public static SQLite3Constant createTrue() { return new SQLite3Constant.SQLite3IntConstant(1); } public static SQLite3Constant createFalse() { return new SQLite3Constant.SQLite3IntConstant(0); } public static SQLite3Constant createBoolean(boolean tr) { return new SQLite3Constant.SQLite3IntConstant(tr ? 1 : 0); } public abstract SQLite3Constant applyEquals(SQLite3Constant right, SQLite3CollateSequence collate); public abstract SQLite3Constant applyLess(SQLite3Constant right, SQLite3CollateSequence collate); public abstract SQLite3Constant castToBoolean(); public SQLite3Constant applyEquals(SQLite3Constant right) { return applyEquals(right, SQLite3CollateSequence.BINARY); } public boolean isReal() { return getDataType() == SQLite3DataType.REAL; } }