import java.util.List;
import java.util.Set;
+import com.healthmarketscience.jackcess.impl.DatabaseImpl;
import com.healthmarketscience.jackcess.impl.IndexData;
import com.healthmarketscience.jackcess.impl.IndexImpl;
+import com.healthmarketscience.jackcess.impl.JetFormat;
/**
* Builder style class for constructing an {@link Index}. See {@link
return this;
}
- public void validate(Set<String> tableColNames) {
+ public void validate(Set<String> tableColNames, JetFormat format) {
+
+ DatabaseImpl.validateIdentifierName(
+ getName(), format.MAX_INDEX_NAME_LENGTH, "index");
+
if(getColumns().isEmpty()) {
throw new IllegalArgumentException("index " + getName() +
" has no columns");
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
+import java.util.regex.Pattern;
import com.healthmarketscience.jackcess.ColumnBuilder;
import com.healthmarketscience.jackcess.Cursor;
/** the columns to read when getting object propertyes */
private static Collection<String> SYSTEM_CATALOG_PROPS_COLUMNS =
new HashSet<String>(Arrays.asList(CAT_COL_ID, CAT_COL_PROPS));
-
+
+ /** regex matching characters which are invalid in identifier names */
+ private static final Pattern INVALID_IDENTIFIER_CHARS =
+ Pattern.compile("[\\p{Cntrl}.!`\\]\\[]");
/** the File of the database */
private final File _file;
}
validateIdentifierName(name, getFormat().MAX_TABLE_NAME_LENGTH, "table");
- validateIdentifierName(linkedDbName, DataType.MEMO.getMaxSize(),
- "linked database");
+ validateName(linkedDbName, DataType.MEMO.getMaxSize(),
+ "linked database");
validateIdentifierName(linkedTableName, getFormat().MAX_TABLE_NAME_LENGTH,
"linked table");
/**
* Validates an identifier name.
+ *
+ * Names of fields, controls, and objects in Microsoft Access:
+ * <ul>
+ * <li>Can include any combination of letters, numbers, spaces, and special
+ * characters except a period (.), an exclamation point (!), an accent
+ * grave (`), and brackets ([ ]).</li>
+ * <li>Can't begin with leading spaces.</li>
+ * <li>Can't include control characters (ASCII values 0 through 31).</li>
+ * </ul>
+ *
* @usage _advanced_method_
*/
public static void validateIdentifierName(String name,
int maxLength,
String identifierType)
{
- if((name == null) || (name.trim().length() == 0)) {
+ // basic name validation
+ validateName(name, maxLength, identifierType);
+
+ // additional identifier validation
+ if(INVALID_IDENTIFIER_CHARS.matcher(name).find()) {
throw new IllegalArgumentException(
- identifierType + " must have non-empty name");
+ identifierType + " name contains invalid characters");
+ }
+
+ // cannot start with spaces
+ if(name.charAt(0) == ' ') {
+ throw new IllegalArgumentException(
+ identifierType + " name cannot start with a space character");
+ }
+ }
+
+ /**
+ * Validates a name.
+ */
+ private static void validateName(String name, int maxLength, String nameType)
+ {
+ if(isBlank(name)) {
+ throw new IllegalArgumentException(
+ nameType + " must have non-blank name");
}
if(name.length() > maxLength) {
throw new IllegalArgumentException(
- identifierType + " name is longer than max length of " + maxLength +
+ nameType + " name is longer than max length of " + maxLength +
": " + name);
}
}
+
+ /**
+ * Returns {@code true} if the given string is {@code null} or all blank
+ * space, {@code false} otherwise.
+ */
+ public static boolean isBlank(String name) {
+ return((name == null) || (name.trim().length() == 0));
+ }
@Override
public String toString() {
public final int USAGE_MAP_TABLE_BYTE_LENGTH;
public final int MAX_COLUMNS_PER_TABLE;
+ public final int MAX_INDEXES_PER_TABLE;
public final int MAX_TABLE_NAME_LENGTH;
public final int MAX_COLUMN_NAME_LENGTH;
public final int MAX_INDEX_NAME_LENGTH;
USAGE_MAP_TABLE_BYTE_LENGTH = defineUsageMapTableByteLength();
MAX_COLUMNS_PER_TABLE = defineMaxColumnsPerTable();
+ MAX_INDEXES_PER_TABLE = defineMaxIndexesPerTable();
MAX_TABLE_NAME_LENGTH = defineMaxTableNameLength();
MAX_COLUMN_NAME_LENGTH = defineMaxColumnNameLength();
MAX_INDEX_NAME_LENGTH = defineMaxIndexNameLength();
protected abstract int defineUsageMapTableByteLength();
protected abstract int defineMaxColumnsPerTable();
+ protected abstract int defineMaxIndexesPerTable();
protected abstract int defineMaxTableNameLength();
protected abstract int defineMaxColumnNameLength();
protected abstract int defineMaxIndexNameLength();
@Override
protected int defineMaxColumnsPerTable() { return 255; }
+ @Override
+ protected int defineMaxIndexesPerTable() { return 32; }
+
@Override
protected int defineMaxTableNameLength() { return 64; }
@Override
protected int defineMaxColumnsPerTable() { return 255; }
+
+ @Override
+ protected int defineMaxIndexesPerTable() { return 32; }
@Override
protected int defineMaxTableNameLength() { return 64; }