001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb;
032:
033: import org.hsqldb.lib.StringConverter;
034:
035: /**
036: * Provides Name Management for SQL objects. <p>
037: *
038: * This class now includes the HsqlName class introduced in 1.7.1 and improves
039: * auto-naming with multiple databases in the engine.<p>
040: *
041: * Methods check user defined names and issue system generated names
042: * for SQL objects.<p>
043: *
044: * This class does not deal with the type of the SQL object for which it
045: * is used.<p>
046: *
047: * Some names beginning with SYS_ are reserved for system generated names.
048: * These are defined in isReserveName(String name) and created by the
049: * makeAutoName(String type) factory method<p>
050: *
051: * sysNumber is used to generate system-generated names. It is
052: * set to the largest integer encountered in names that use the
053: * SYS_xxxxxxx_INTEGER format. As the DDL is processed before any ALTER
054: * command, any new system generated name will have a larger integer suffix
055: * than all the existing names.
056: *
057: * @author fredt@users
058: * @version 1.8.0
059: * @since 1.7.2
060: */
061: public class HsqlNameManager {
062:
063: private static HsqlNameManager staticManager = new HsqlNameManager();
064:
065: static {
066: staticManager.serialNumber = Integer.MIN_VALUE;
067: }
068:
069: private int serialNumber = 1; // 0 is reserved in lookups
070: private int sysNumber = 0;
071:
072: static HsqlName newHsqlSystemObjectName(String name) {
073: return new HsqlName(staticManager, name);
074: }
075:
076: public HsqlName newHsqlName(String name, boolean isquoted) {
077: return new HsqlName(this , name, isquoted);
078: }
079:
080: HsqlName newHsqlName(String prefix, String name, boolean isquoted) {
081: return new HsqlName(this , prefix, name, isquoted);
082: }
083:
084: HsqlName newHsqlName(String name) {
085: return new HsqlName(this , name);
086: }
087:
088: /**
089: * Auto names are used for autogenerated indexes or anonymous constraints.
090: * Also the name of a pseudo-column is the autoname ""
091: */
092: public HsqlName newAutoName(String type) {
093: return newAutoName(type, null);
094: }
095:
096: /**
097: * Auto names are used for autogenerated indexes or anonymous constraints.
098: */
099: HsqlName newAutoName(String type, String namepart) {
100:
101: StringBuffer sbname = new StringBuffer();
102:
103: if (type != null) {
104: if (type.length() != 0) {
105: sbname.append("SYS_");
106: sbname.append(type);
107: sbname.append('_');
108:
109: if (namepart != null) {
110: sbname.append(namepart);
111: sbname.append('_');
112: }
113:
114: sbname.append(++sysNumber);
115: }
116: } else {
117: sbname.append(namepart);
118: }
119:
120: return new HsqlName(this , sbname.toString());
121: }
122:
123: void resetNumbering() {
124: sysNumber = 0;
125: serialNumber = 0;
126: }
127:
128: public static class HsqlName {
129:
130: HsqlNameManager manager;
131: public String name;
132: boolean isNameQuoted;
133: public String statementName;
134: public HsqlName schema;
135: private final int hashCode;
136:
137: private HsqlName(HsqlNameManager man) {
138: manager = man;
139: hashCode = manager.serialNumber++;
140: }
141:
142: private HsqlName(HsqlNameManager man, String name,
143: boolean isquoted) {
144:
145: this (man);
146:
147: rename(name, isquoted);
148: }
149:
150: private HsqlName(HsqlNameManager man, String prefix,
151: String name, boolean isquoted) {
152:
153: this (man);
154:
155: rename(prefix, name, isquoted);
156: }
157:
158: private HsqlName(HsqlNameManager man, String name) {
159:
160: this (man);
161:
162: this .name = this .statementName = name;
163: }
164:
165: public void rename(String name, boolean isquoted) {
166:
167: this .name = name;
168: this .statementName = name;
169: this .isNameQuoted = isquoted;
170:
171: if (isNameQuoted) {
172: statementName = StringConverter.toQuotedString(name,
173: '"', true);
174: }
175:
176: if (name.startsWith("SYS_")) {
177: int length = sysPrefixLength(name);
178:
179: if (length > 0) {
180: try {
181: int temp = Integer.parseInt(name
182: .substring(length));
183:
184: if (temp > manager.sysNumber) {
185: manager.sysNumber = temp;
186: }
187: } catch (NumberFormatException e) {
188: }
189: }
190: }
191: }
192:
193: void rename(String prefix, String name, boolean isquoted) {
194:
195: StringBuffer sbname = new StringBuffer(prefix);
196:
197: sbname.append('_');
198: sbname.append(name);
199: rename(sbname.toString(), isquoted);
200: }
201:
202: public boolean equals(Object other) {
203:
204: if (other instanceof HsqlName) {
205: return hashCode == ((HsqlName) other).hashCode;
206: }
207:
208: return false;
209: }
210:
211: /**
212: * hash code for this object is its unique serial number.
213: */
214: public int hashCode() {
215: return hashCode;
216: }
217:
218: /**
219: * "SYS_IDX_" is used for auto-indexes on referring FK columns or
220: * unique constraints.
221: * "SYS_PK_" is for the primary key constraints
222: * "SYS_CT_" is for unique and check constraints
223: * "SYS_REF_" is for FK constraints in referenced tables
224: * "SYS_FK_" is for FK constraints in referencing tables
225: *
226: */
227: static final String[] sysPrefixes = new String[] { "SYS_IDX_",
228: "SYS_PK_", "SYS_REF_", "SYS_CT_", "SYS_FK_", };
229:
230: static int sysPrefixLength(String name) {
231:
232: for (int i = 0; i < sysPrefixes.length; i++) {
233: if (name.startsWith(sysPrefixes[i])) {
234: return sysPrefixes[i].length();
235: }
236: }
237:
238: return 0;
239: }
240:
241: static boolean isReservedName(String name) {
242: return sysPrefixLength(name) > 0;
243: }
244:
245: boolean isReservedName() {
246: return isReservedName(name);
247: }
248:
249: public String toString() {
250:
251: return getClass().getName() + super .hashCode()
252: + "[this.hashCode()=" + this .hashCode + ", name="
253: + name + ", name.hashCode()=" + name.hashCode()
254: + ", isNameQuoted=" + isNameQuoted + "]";
255: }
256:
257: public int compareTo(Object o) {
258: return hashCode - o.hashCode();
259: }
260:
261: /**
262: * Returns true if the identifier consists of all uppercase letters
263: * digits and underscore, beginning with a letter and is not in the
264: * keyword list.
265: */
266: static boolean isRegularIdentifier(String name) {
267:
268: for (int i = 0, length = name.length(); i < length; i++) {
269: int c = name.charAt(i);
270:
271: if (c >= 'A' && c <= 'Z') {
272: continue;
273: } else if (c == '_' && i > 0) {
274: continue;
275: } else if (c >= '0' && c <= '9') {
276: continue;
277: }
278:
279: return false;
280: }
281:
282: return !Token.isKeyword(name);
283: }
284: }
285: }
|