/* Copyright (c) 2001-2008, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb;
import org.hsqldb.lib.StringConverter;
/**
* Provides Name Management for SQL objects. <p>
*
* This class now includes the HsqlName class introduced in 1.7.1 and improves
* auto-naming with multiple databases in the engine.<p>
*
* Methods check user defined names and issue system generated names
* for SQL objects.<p>
*
* This class does not deal with the type of the SQL object for which it
* is used.<p>
*
* Some names beginning with SYS_ are reserved for system generated names.
* These are defined in isReserveName(String name) and created by the
* makeAutoName(String type) factory method<p>
*
* sysNumber is used to generate system-generated names. It is
* set to the largest integer encountered in names that use the
* SYS_xxxxxxx_INTEGER format. As the DDL is processed before any ALTER
* command, any new system generated name will have a larger integer suffix
* than all the existing names.
*
* @author fredt@users
* @version 1.8.0
* @since 1.7.2
*/
public class HsqlNameManager {
private static HsqlNameManager staticManager = new HsqlNameManager();
static {
staticManager.serialNumber = Integer.MIN_VALUE;
}
private int serialNumber = 1; // 0 is reserved in lookups
private int sysNumber = 0;
static HsqlName newHsqlSystemObjectName(String name) {
return new HsqlName(staticManager, name);
}
public HsqlName newHsqlName(String name, boolean isquoted) {
return new HsqlName(this, name, isquoted);
}
HsqlName newHsqlName(String prefix, String name, boolean isquoted) {
return new HsqlName(this, prefix, name, isquoted);
}
HsqlName newHsqlName(String name) {
return new HsqlName(this, name);
}
/**
* Auto names are used for autogenerated indexes or anonymous constraints.
* Also the name of a pseudo-column is the autoname ""
*/
public HsqlName newAutoName(String type) {
return newAutoName(type, null);
}
/**
* Auto names are used for autogenerated indexes or anonymous constraints.
*/
HsqlName newAutoName(String type, String namepart) {
StringBuffer sbname = new StringBuffer();
if (type != null) {
if (type.length() != 0) {
sbname.append("SYS_");
sbname.append(type);
sbname.append('_');
if (namepart != null) {
sbname.append(namepart);
sbname.append('_');
}
sbname.append(++sysNumber);
}
} else {
sbname.append(namepart);
}
return new HsqlName(this, sbname.toString());
}
void resetNumbering() {
sysNumber = 0;
serialNumber = 0;
}
public static class HsqlName {
HsqlNameManager manager;
public String name;
boolean isNameQuoted;
public String statementName;
public HsqlName schema;
private final int hashCode;
private HsqlName(HsqlNameManager man) {
manager = man;
hashCode = manager.serialNumber++;
}
private HsqlName(HsqlNameManager man, String name, boolean isquoted) {
this(man);
rename(name, isquoted);
}
private HsqlName(HsqlNameManager man, String prefix, String name,
boolean isquoted) {
this(man);
rename(prefix, name, isquoted);
}
private HsqlName(HsqlNameManager man, String name) {
this(man);
this.name = this.statementName = name;
}
public void rename(String name, boolean isquoted) {
this.name = name;
this.statementName = name;
this.isNameQuoted = isquoted;
if (isNameQuoted) {
statementName = StringConverter.toQuotedString(name, '"',
true);
}
if (name.startsWith("SYS_")) {
int length = sysPrefixLength(name);
if (length > 0) {
try {
int temp = Integer.parseInt(name.substring(length));
if (temp > manager.sysNumber) {
manager.sysNumber = temp;
}
} catch (NumberFormatException e) {}
}
}
}
void rename(String prefix, String name, boolean isquoted) {
StringBuffer sbname = new StringBuffer(prefix);
sbname.append('_');
sbname.append(name);
rename(sbname.toString(), isquoted);
}
public boolean equals(Object other) {
if (other instanceof HsqlName) {
return hashCode == ((HsqlName) other).hashCode;
}
return false;
}
/**
* hash code for this object is its unique serial number.
*/
public int hashCode() {
return hashCode;
}
/**
* "SYS_IDX_" is used for auto-indexes on referring FK columns or
* unique constraints.
* "SYS_PK_" is for the primary key constraints
* "SYS_CT_" is for unique and check constraints
* "SYS_REF_" is for FK constraints in referenced tables
* "SYS_FK_" is for FK constraints in referencing tables
*
*/
static final String[] sysPrefixes = new String[] {
"SYS_IDX_", "SYS_PK_", "SYS_REF_", "SYS_CT_", "SYS_FK_",
};
static int sysPrefixLength(String name) {
for (int i = 0; i < sysPrefixes.length; i++) {
if (name.startsWith(sysPrefixes[i])) {
return sysPrefixes[i].length();
}
}
return 0;
}
static boolean isReservedName(String name) {
return sysPrefixLength(name) > 0;
}
boolean isReservedName() {
return isReservedName(name);
}
public String toString() {
return getClass().getName() + super.hashCode()
+ "[this.hashCode()=" + this.hashCode + ", name=" + name
+ ", name.hashCode()=" + name.hashCode()
+ ", isNameQuoted=" + isNameQuoted + "]";
}
public int compareTo(Object o) {
return hashCode - o.hashCode();
}
/**
* Returns true if the identifier consists of all uppercase letters
* digits and underscore, beginning with a letter and is not in the
* keyword list.
*/
static boolean isRegularIdentifier(String name) {
for (int i = 0, length = name.length(); i < length; i++) {
int c = name.charAt(i);
if (c >= 'A' && c <= 'Z') {
continue;
} else if (c == '_' && i > 0) {
continue;
} else if (c >= '0' && c <= '9') {
continue;
}
return false;
}
return !Token.isKeyword(name);
}
}
}