001: /*
002: * Copyright 2002 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: SQLIdentifier.java,v 1.9 2003/03/14 19:29:54 pierreg0 Exp $
009: */
010:
011: package com.triactive.jdo.store;
012:
013: class SQLIdentifier {
014: protected final DatabaseAdapter dba;
015:
016: protected String javaName;
017: protected String sqlIdentifier;
018: protected String identifierQuoteString;
019:
020: public SQLIdentifier(DatabaseAdapter dba) {
021: this .dba = dba;
022: this .javaName = null;
023: this .sqlIdentifier = null;
024: this .identifierQuoteString = dba.getIdentifierQuoteString();
025: }
026:
027: public SQLIdentifier(DatabaseAdapter dba, String sqlIdentifier) {
028: this .dba = dba;
029: this .javaName = null;
030: this .identifierQuoteString = dba.getIdentifierQuoteString();
031: setSQLIdentifier(sqlIdentifier);
032: }
033:
034: protected int getMaxLength() {
035: return SQL92Constants.MAX_IDENTIFIER_LENGTH;
036: }
037:
038: /**
039: * Sets the Java identifier to the given value and computes a corresponding
040: * SQL identifier.
041: *
042: * <p>Conversion consists of breaking the identifier into words, converting
043: * each word to upper-case, and separating each one with an underscore "_".
044: * Words are identified by a leading upper-case character.
045: * Any leading or trailing underscores are removed.
046: *
047: * <p>The resulting SQL identifier is "generic" and not suitable for direct
048: * use in a SQL statement; the toString() method should be used for that.
049: *
050: * <p>The resulting SQL identifier also truncated to getMaxLength().
051: * The excess characters plus the previous two characters are removed and
052: * replaced with the base 36 representation of their hash value mod 1296 (36
053: * * 36).
054: *
055: * @param javaName the Java identifier.
056: */
057:
058: private static final int HASH_RANGE = Character.MAX_RADIX
059: * Character.MAX_RADIX / 2;
060:
061: protected void setJavaName(String javaName) {
062: this .javaName = javaName;
063:
064: StringBuffer s = new StringBuffer();
065: char prev = '\0';
066:
067: for (int i = 0; i < javaName.length(); ++i) {
068: char c = javaName.charAt(i);
069:
070: if (c >= 'A' && c <= 'Z') {
071: if (prev >= 'a' && prev <= 'z')
072: s.append('_');
073:
074: s.append(c);
075: } else if (c >= 'a' && c <= 'z')
076: s.append((char) (c - ('a' - 'A')));
077: else if (c >= '0' && c <= '9' || c == '_')
078: s.append(c);
079: else if (c == '.')
080: s.append('_');
081: else {
082: String cval = "000" + Integer.toHexString((int) c);
083:
084: s.append(cval.substring(cval.length()
085: - (c > 0xff ? 4 : 2)));
086: }
087:
088: prev = c;
089: }
090:
091: /* Remove leading and trailing underscores. */
092: while (s.length() > 0 && s.charAt(0) == '_')
093: s.deleteCharAt(0);
094: while (s.length() > 0 && s.charAt(s.length() - 1) == '_')
095: s.deleteCharAt(s.length() - 1);
096:
097: if (s.length() == 0)
098: throw new IllegalArgumentException(
099: "Illegal Java identifier: " + javaName);
100:
101: setSQLIdentifier(truncate(s.toString(), getMaxLength()));
102: }
103:
104: protected void setSQLIdentifier(String sqlIdentifier) {
105: if (dba.storesLowerCaseIdentifiers())
106: this .sqlIdentifier = sqlIdentifier.toLowerCase();
107: else
108: this .sqlIdentifier = sqlIdentifier.toUpperCase();
109: }
110:
111: protected static String truncate(String sqlIdentifier, int length) {
112: if (sqlIdentifier.length() > length) {
113: int tailIndex = length - 2;
114: int tailHash = sqlIdentifier.substring(tailIndex)
115: .hashCode();
116:
117: /* Scale the hash code down to the range 0 - 1295. */
118: if (tailHash < 0)
119: tailHash = tailHash % HASH_RANGE + (HASH_RANGE - 1);
120: else
121: tailHash = tailHash % HASH_RANGE + HASH_RANGE;
122:
123: String suffix = "0"
124: + Integer.toString(tailHash, Character.MAX_RADIX);
125:
126: return sqlIdentifier.substring(0, tailIndex)
127: + suffix.substring(suffix.length() - 2);
128: } else
129: return sqlIdentifier;
130: }
131:
132: public String getJavaName() {
133: return javaName;
134: }
135:
136: public String getSQLIdentifier() {
137: return sqlIdentifier;
138: }
139:
140: public int hashCode() {
141: return sqlIdentifier.hashCode();
142: }
143:
144: public boolean equals(Object obj) {
145: if (obj == this )
146: return true;
147:
148: if (!(obj instanceof SQLIdentifier))
149: return false;
150:
151: SQLIdentifier id = (SQLIdentifier) obj;
152:
153: return sqlIdentifier.equals(id.sqlIdentifier);
154: }
155:
156: public String toString() {
157: if (dba.isSQLKeyword(sqlIdentifier))
158: return identifierQuoteString + sqlIdentifier
159: + identifierQuoteString;
160: else
161: return sqlIdentifier;
162: }
163: }
|