mil.nga.geopackage.db.table.ConstraintParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of geopackage-core Show documentation
Show all versions of geopackage-core Show documentation
Core functionality for GeoPackage implementations
The newest version!
package mil.nga.geopackage.db.table;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import mil.nga.geopackage.db.CoreSQLUtils;
/**
* SQL constraint parser from create table statements
*
* @author osbornb
* @since 3.3.0
*/
public class ConstraintParser {
/**
* Regex prefix for ignoring: case insensitive, dotall mode (match line
* terminators), and start of line
*/
private static final String REGEX_PREFIX = "(?i)(?s)^";
/**
* Constraint name regex suffix
*/
private static final String CONSTRAINT_NAME_REGEX_SUFFIX = "CONSTRAINT\\s+(\".+\"|\\S+)\\s";
/**
* Constraint name regex
*/
private static final String CONSTRAINT_NAME_REGEX = REGEX_PREFIX
+ CONSTRAINT_NAME_REGEX_SUFFIX;
/**
* Constraint name and definition regex
*/
private static final String CONSTRAINT_REGEX = REGEX_PREFIX + "("
+ CONSTRAINT_NAME_REGEX_SUFFIX + ")?(.*)";
/**
* Constraint name pattern
*/
private static final Pattern NAME_PATTERN = Pattern
.compile(CONSTRAINT_NAME_REGEX);
/**
* Constraint name pattern name matcher group
*/
private static final int NAME_PATTERN_NAME_GROUP = 1;
/**
* Constraint name and definition pattern
*/
private static final Pattern CONSTRAINT_PATTERN = Pattern
.compile(CONSTRAINT_REGEX);
/**
* Constraint name and definition pattern name matcher group
*/
private static final int CONSTRAINT_PATTERN_NAME_GROUP = 2;
/**
* Constraint name and definition pattern definition matcher group
*/
private static final int CONSTRAINT_PATTERN_DEFINITION_GROUP = 3;
/**
* Get the constraints for the table SQL
*
* @param tableSql
* table SQL
* @return constraints
*/
public static TableConstraints getConstraints(String tableSql) {
TableConstraints constraints = new TableConstraints();
// Find the start and end of the column definitions and table
// constraints
int start = -1;
int end = -1;
if (tableSql != null) {
start = tableSql.indexOf("(");
end = tableSql.lastIndexOf(")");
}
if (start >= 0 && end >= 0) {
String definitions = tableSql.substring(start + 1, end).trim();
// Parse the column definitions and table constraints, divided by
// columns when not within parentheses. Create constraints when
// found.
int openParentheses = 0;
int sqlStart = 0;
for (int i = 0; i < definitions.length(); i++) {
char character = definitions.charAt(i);
if (character == '(') {
openParentheses++;
} else if (character == ')') {
openParentheses--;
} else if (character == ',' && openParentheses == 0) {
String constraintSql = definitions.substring(sqlStart, i);
addConstraints(constraints, constraintSql);
sqlStart = i + 1;
}
}
if (sqlStart < definitions.length()) {
String constraintSql = definitions.substring(sqlStart,
definitions.length());
addConstraints(constraints, constraintSql);
}
}
return constraints;
}
/**
* Add constraints of the optional type or all constraints
*
* @param constraints
* constraints to add to
* @param constraintSQL
* constraint SQL statement
*/
private static void addConstraints(TableConstraints constraints,
String constraintSql) {
Constraint constraint = getTableConstraint(constraintSql);
if (constraint != null) {
constraints.addTableConstraint(constraint);
} else {
ColumnConstraints columnConstraints = getColumnConstraints(
constraintSql);
if (columnConstraints.hasConstraints()) {
constraints.addColumnConstraints(columnConstraints);
}
}
}
/**
* Attempt to get column constraints by parsing the SQL statement
*
* @param constraintSql
* constraint SQL statement
* @return constraints
*/
public static ColumnConstraints getColumnConstraints(String constraintSql) {
String[] parts = constraintSql.trim().split("\\s+");
String columnName = CoreSQLUtils.quoteUnwrap(parts[0]);
ColumnConstraints constraints = new ColumnConstraints(columnName);
int constraintIndex = -1;
ConstraintType constraintType = null;
for (int i = 1; i < parts.length; i++) {
String part = parts[i];
if (Constraint.CONSTRAINT.equalsIgnoreCase(part)) {
if (constraintType != null) {
constraints.addConstraint(createConstraint(parts,
constraintIndex, i, constraintType));
constraintType = null;
}
constraintIndex = i;
} else {
ConstraintType type = ConstraintType.getColumnType(part);
if (type != null) {
if (constraintType != null) {
constraints.addConstraint(createConstraint(parts,
constraintIndex, i, constraintType));
constraintIndex = -1;
}
if (constraintIndex < 0) {
constraintIndex = i;
}
constraintType = type;
}
}
}
if (constraintType != null) {
constraints.addConstraint(createConstraint(parts, constraintIndex,
parts.length, constraintType));
}
return constraints;
}
/**
* Create a constraint from the SQL parts with the range for the type
*
* @param parts
* SQL parts
* @param startIndex
* start index (inclusive)
* @param endIndex
* end index (exclusive)
* @param type
* constraint type
* @return constraint
*/
private static Constraint createConstraint(String[] parts, int startIndex,
int endIndex, ConstraintType type) {
StringBuilder constraintSql = new StringBuilder();
for (int i = startIndex; i < endIndex; i++) {
if (constraintSql.length() > 0) {
constraintSql.append(" ");
}
constraintSql.append(parts[i]);
}
String sql = constraintSql.toString();
String name = getName(sql);
return new RawConstraint(type, name, sql);
}
/**
* Attempt to get the constraint by parsing the SQL statement
*
* @param constraintSql
* constraint SQL statement
* @param table
* true to search for a table constraint, false to search for a
* column constraint
* @return constraint or null
*/
private static Constraint getConstraint(String constraintSql,
boolean table) {
Constraint constraint = null;
String[] nameAndDefinition = getNameAndDefinition(constraintSql);
String definition = nameAndDefinition[1];
if (definition != null) {
String prefix = definition.split("\\s+")[0];
ConstraintType type = null;
if (table) {
type = ConstraintType.getTableType(prefix);
} else {
type = ConstraintType.getColumnType(prefix);
}
if (type != null) {
constraint = new RawConstraint(type, nameAndDefinition[0],
constraintSql.trim());
}
}
return constraint;
}
/**
* Attempt to get a table constraint by parsing the SQL statement
*
* @param constraintSql
* constraint SQL statement
* @return constraint or null
*/
public static Constraint getTableConstraint(String constraintSql) {
return getConstraint(constraintSql, true);
}
/**
* Check if the SQL is a table type constraint
*
* @param constraintSql
* constraint SQL statement
* @return true if a table constraint
*/
public static boolean isTableConstraint(String constraintSql) {
return getTableConstraint(constraintSql) != null;
}
/**
* Get the table constraint type of the constraint SQL
*
* @param constraintSql
* constraint SQL
* @return constraint type or null
*/
public static ConstraintType getTableType(String constraintSql) {
ConstraintType type = null;
Constraint constraint = getTableConstraint(constraintSql);
if (constraint != null) {
type = constraint.getType();
}
return type;
}
/**
* Determine if the table constraint SQL is the constraint type
*
* @param type
* constraint type
* @param constraintSql
* constraint SQL
* @return true if the constraint type
*/
public static boolean isTableType(ConstraintType type,
String constraintSql) {
boolean isType = false;
ConstraintType constraintType = getTableType(constraintSql);
if (constraintType != null) {
isType = type == constraintType;
}
return isType;
}
/**
* Attempt to get a column constraint by parsing the SQL statement
*
* @param constraintSql
* constraint SQL statement
* @return constraint or null
*/
public static Constraint getColumnConstraint(String constraintSql) {
return getConstraint(constraintSql, false);
}
/**
* Check if the SQL is a column type constraint
*
* @param constraintSql
* constraint SQL statement
* @return true if a column constraint
*/
public static boolean isColumnConstraint(String constraintSql) {
return getColumnConstraint(constraintSql) != null;
}
/**
* Get the column constraint type of the constraint SQL
*
* @param constraintSql
* constraint SQL
* @return constraint type or null
*/
public static ConstraintType getColumnType(String constraintSql) {
ConstraintType type = null;
Constraint constraint = getColumnConstraint(constraintSql);
if (constraint != null) {
type = constraint.getType();
}
return type;
}
/**
* Determine if the column constraint SQL is the constraint type
*
* @param type
* constraint type
* @param constraintSql
* constraint SQL
* @return true if the constraint type
*/
public static boolean isColumnType(ConstraintType type,
String constraintSql) {
boolean isType = false;
ConstraintType constraintType = getColumnType(constraintSql);
if (constraintType != null) {
isType = type == constraintType;
}
return isType;
}
/**
* Attempt to get a constraint by parsing the SQL statement
*
* @param constraintSql
* constraint SQL statement
* @return constraint or null
*/
public static Constraint getConstraint(String constraintSql) {
Constraint constraint = getTableConstraint(constraintSql);
if (constraint == null) {
constraint = getColumnConstraint(constraintSql);
}
return constraint;
}
/**
* Check if the SQL is a constraint
*
* @param constraintSql
* constraint SQL statement
* @return true if a constraint
*/
public static boolean isConstraint(String constraintSql) {
return getConstraint(constraintSql) != null;
}
/**
* Get the constraint type of the constraint SQL
*
* @param constraintSql
* constraint SQL
* @return constraint type or null
*/
public static ConstraintType getType(String constraintSql) {
ConstraintType type = null;
Constraint constraint = getConstraint(constraintSql);
if (constraint != null) {
type = constraint.getType();
}
return type;
}
/**
* Determine if the constraint SQL is the constraint type
*
* @param type
* constraint type
* @param constraintSql
* constraint SQL
* @return true if the constraint type
*/
public static boolean isType(ConstraintType type, String constraintSql) {
boolean isType = false;
ConstraintType constraintType = getType(constraintSql);
if (constraintType != null) {
isType = type == constraintType;
}
return isType;
}
/**
* Get the constraint name if it has one
*
* @param constraintSql
* constraint SQL
* @return constraint name or null
*/
public static String getName(String constraintSql) {
String name = null;
Matcher matcher = NAME_PATTERN.matcher(constraintSql);
if (matcher.find()) {
name = CoreSQLUtils
.quoteUnwrap(matcher.group(NAME_PATTERN_NAME_GROUP));
}
return name;
}
/**
* Get the constraint name and remaining definition
*
* @param constraintSql
* constraint SQL
* @return array with name or null at index 0, definition at index 1
*/
public static String[] getNameAndDefinition(String constraintSql) {
String parts[] = null;
Matcher matcher = CONSTRAINT_PATTERN.matcher(constraintSql.trim());
if (matcher.find()) {
String name = CoreSQLUtils
.quoteUnwrap(matcher.group(CONSTRAINT_PATTERN_NAME_GROUP));
if (name != null) {
name = name.trim();
}
String definition = matcher
.group(CONSTRAINT_PATTERN_DEFINITION_GROUP);
if (definition != null) {
definition = definition.trim();
}
parts = new String[] { name, definition };
}
return parts;
}
}