/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.ais.model;
import com.foundationdb.util.Strings;
public class TableName implements Comparable<TableName>
{
public final static String INFORMATION_SCHEMA = "information_schema";
public final static String SECURITY_SCHEMA = "security_schema";
public final static String SQLJ_SCHEMA = "sqlj";
public final static String SYS_SCHEMA = "sys";
private final String schemaName;
private final String tableName;
public TableName(String schemaName, String tableName)
{
this.schemaName = schemaName;
this.tableName = tableName;
}
public static TableName create(String schemaName, String tableName)
{
return new TableName(schemaName, tableName);
}
/** Parse a qualified string (e.g. test.foo) into a TableName. */
public static TableName parse(String defaultSchema, String s)
{
String[] parts = Strings.parseQualifiedName(s, 2);
return new TableName(parts[0].isEmpty() ? defaultSchema : parts[0], parts[1]);
}
public String getSchemaName()
{
return schemaName;
}
public String getTableName()
{
return tableName;
}
public String getDescription()
{
StringBuilder buffer = new StringBuilder();
buffer.append(getSchemaName());
buffer.append(".");
buffer.append(getTableName());
return buffer.toString();
}
public String toStringEscaped() {
return String.format("%s.%s", Strings.escapeIdentifier(schemaName), Strings.escapeIdentifier(tableName));
}
public boolean inSystemSchema() {
return inSystemSchema(schemaName);
}
public static boolean inSystemSchema(String schemaName) {
return INFORMATION_SCHEMA.equals(schemaName) ||
SECURITY_SCHEMA.equals(schemaName) ||
SQLJ_SCHEMA.equals(schemaName) ||
SYS_SCHEMA.equals(schemaName);
}
@Override
public String toString()
{
return getDescription();
}
@Override
public boolean equals(Object obj)
{
if (! (obj instanceof TableName)) {
return false;
}
TableName o = (TableName) obj;
return equals(o.getSchemaName(), o.getTableName());
}
public boolean equals(String schema, String table)
{
return getSchemaName().equals(schema) &&
getTableName().equals(table);
}
@Override
public int hashCode()
{
return getSchemaName().hashCode() +
getTableName().hashCode();
}
@Override
public int compareTo(TableName that)
{
int c = this.getSchemaName().compareTo(that.getSchemaName());
if (c == 0) {
c = this.getTableName().compareTo(that.getTableName());
}
return c;
}
/**
* Writes this table's escaped name to the builder. If the table's schema matches (case sensitive) the given
* unlessSchema that portion of the name will <em>not</em> be included in the returned String. Otherwise, it will
* be. If unlessSchema is null, this will always print the fully qualified name.
* @param builder the builder to write the escaped name to
* @param unlessSchema if matches this TableName's schema, print only the table's escaped name (not fully qualified)
* @return the builder you passed in
*/
private StringBuilder escape(StringBuilder builder, String unlessSchema) {
if (unlessSchema == null || (!schemaName.equals(unlessSchema))) {
if (needsEscaping(schemaName)) {
escape(schemaName, builder);
}
else {
builder.append(schemaName);
}
builder.append('.');
}
if (needsEscaping(tableName)) {
escape(tableName, builder);
}
else {
builder.append(tableName);
}
return builder;
}
/**
* Prints this table's escaped, fully qualified name.
* @return the escaped, fully qualified name
*/
public String escaped() {
return escaped(null);
}
/**
* Returns this table's escaped name. If the table's schema matches (case sensitive) the given unlessSchema,
* that portion of the name will <em>not</em> be included in the returned String. Otherwise, it will be. If
* unlessSchema is null, this will always print the fully qualified name.
* @param unlessSchema if matches this TableName's schema, print only the table's escaped name (not fully qualified)
* @return the escaped name
*/
public String escaped(String unlessSchema) {
return escape(new StringBuilder(), unlessSchema).toString();
}
private static boolean needsEscaping(String name) {
char[] chars = new char[ name.length() ];
name.getChars(0, name.length(), chars, 0);
for (char c : chars) {
if (! (Character.isLetterOrDigit(c) || c == '_')) {
return true;
}
}
return false;
}
private static StringBuilder escape(String name, StringBuilder out) {
out.append('`').append(name.replace("`", "``")).append('`');
return out;
}
}