001: /*
002: Copyright (C) 2002-2004 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022:
023:
024: */
025: package com.mysql.jdbc;
026:
027: /**
028: * EscapeTokenizer breaks up an SQL statement into SQL and escape code parts.
029: *
030: * @author Mark Matthews
031: */
032: public class EscapeTokenizer {
033: // ~ Instance fields
034: // --------------------------------------------------------
035:
036: private int bracesLevel = 0;
037:
038: private boolean emittingEscapeCode = false;
039:
040: private boolean inComment = false;
041:
042: private boolean inQuotes = false;
043:
044: private char lastChar = 0;
045:
046: private char lastLastChar = 0;
047:
048: private int pos = 0;
049:
050: private char quoteChar = 0;
051:
052: private boolean sawVariableUse = false;
053:
054: private String source = null;
055:
056: private int sourceLength = 0;
057:
058: // ~ Constructors
059: // -----------------------------------------------------------
060:
061: /**
062: * Creates a new EscapeTokenizer object.
063: *
064: * @param s
065: * the string to tokenize
066: */
067: public EscapeTokenizer(String s) {
068: this .source = s;
069: this .sourceLength = s.length();
070: this .pos = 0;
071: }
072:
073: // ~ Methods
074: // ----------------------------------------------------------------
075:
076: /**
077: * Does this tokenizer have more tokens available?
078: *
079: * @return if this tokenizer has more tokens available
080: */
081: public synchronized boolean hasMoreTokens() {
082: return (this .pos < this .sourceLength);
083: }
084:
085: /**
086: * Returns the next token
087: *
088: * @return the next token.
089: */
090: public synchronized String nextToken() {
091: StringBuffer tokenBuf = new StringBuffer();
092:
093: if (this .emittingEscapeCode) {
094: tokenBuf.append("{"); //$NON-NLS-1$
095: this .emittingEscapeCode = false;
096: }
097:
098: for (; this .pos < this .sourceLength; this .pos++) {
099: char c = this .source.charAt(this .pos);
100:
101: // Detect variable usage
102:
103: if (!this .inQuotes && c == '@') {
104: this .sawVariableUse = true;
105: }
106:
107: if (c == '\'' || c == '"') {
108: if (this .inQuotes && c == quoteChar) {
109: if (this .pos + 1 < this .sourceLength) {
110: if (this .source.charAt(this .pos + 1) == quoteChar) {
111: // Doubled-up quote escape
112: tokenBuf.append(quoteChar);
113: tokenBuf.append(quoteChar);
114: this .pos++;
115: continue;
116: }
117: }
118: }
119: if (this .lastChar != '\\') {
120: if (this .inQuotes) {
121: if (this .quoteChar == c) {
122: this .inQuotes = false;
123: }
124: } else {
125: this .inQuotes = true;
126: this .quoteChar = c;
127: }
128: } else if (this .lastLastChar == '\\') {
129: if (this .inQuotes) {
130: if (this .quoteChar == c) {
131: this .inQuotes = false;
132: }
133: } else {
134: this .inQuotes = true;
135: this .quoteChar = c;
136: }
137: }
138:
139: tokenBuf.append(c);
140: } else if (c == '-') {
141: if ((this .lastChar == '-')
142: && ((this .lastLastChar != '\\') && !this .inQuotes)) {
143: this .inComment = true;
144: }
145:
146: tokenBuf.append(c);
147: } else if ((c == '\n') || (c == '\r')) {
148: this .inComment = false;
149:
150: tokenBuf.append(c);
151: } else if (c == '{') {
152: if (this .inQuotes || this .inComment) {
153: tokenBuf.append(c);
154: } else {
155: this .bracesLevel++;
156:
157: if (this .bracesLevel == 1) {
158: this .pos++;
159: this .emittingEscapeCode = true;
160:
161: return tokenBuf.toString();
162: }
163:
164: tokenBuf.append(c);
165: }
166: } else if (c == '}') {
167: tokenBuf.append(c);
168:
169: if (!this .inQuotes && !this .inComment) {
170: this .lastChar = c;
171:
172: this .bracesLevel--;
173:
174: if (this .bracesLevel == 0) {
175: this .pos++;
176:
177: return tokenBuf.toString();
178: }
179: }
180: } else {
181: tokenBuf.append(c);
182: }
183:
184: this .lastLastChar = this .lastChar;
185: this .lastChar = c;
186: }
187:
188: return tokenBuf.toString();
189: }
190:
191: boolean sawVariableUse() {
192: return this.sawVariableUse;
193: }
194: }
|