All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.housepower.jdbc.misc.SQLLexer Maven / Gradle / Ivy

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.housepower.jdbc.misc;

import java.sql.SQLException;

public class SQLLexer {
    private int pos;
    private final char[] data;

    public SQLLexer(int pos, String data) {
        this.pos = pos;
        this.data = data.toCharArray();
    }

    public char character() {
        return eof() ? 0 : data[pos++];
    }

    // only support dec
    public int intLiteral() {
        skipAnyWhitespace();

        int start = pos;

        if (isCharacter('-') || isCharacter('+'))
            pos++;

        for (; pos < data.length; pos++)
            if (!isNumericASCII(data[pos]))
                break;

        return Integer.parseInt(new StringView(start, pos, data).toString());
    }

    public Number numberLiteral() {
        skipAnyWhitespace();

        int start = pos;
        boolean isHex = false;
        boolean isBinary = false;
        boolean isDouble = false;
        boolean hasExponent = false;
        boolean hasSigned = false;

        if (isCharacter('-') || isCharacter('+')) {
            hasSigned = true;
            pos++;
        }

        if (pos + 2 < data.length) {
            if (data[pos] == '0'
                    && (data[pos + 1] == 'x' || data[pos + 1] == 'X' || data[pos + 1] == 'b' || data[pos + 1] == 'B')) {
                isHex = data[pos + 1] == 'x' || data[pos + 1] == 'X';
                isBinary = data[pos + 1] == 'b' || data[pos + 1] == 'B';
                pos += 2;
            }
        }

        for (; pos < data.length; pos++) {
            if (isHex ? !isHexDigit(data[pos]) : !isNumericASCII(data[pos])) {
                break;
            }
        }

        if (pos < data.length && data[pos] == '.') {
            isDouble = true;
            for (pos++; pos < data.length; pos++) {
                if (isHex ? !isHexDigit(data[pos]) : !isNumericASCII(data[pos]))
                    break;
            }
        }

        if (pos + 1 < data.length
                && (isHex ? (data[pos] == 'p' || data[pos] == 'P') : (data[pos] == 'e' || data[pos] == 'E'))) {
            hasExponent = true;
            pos++;

            if (pos + 1 < data.length && (data[pos] == '-' || data[pos] == '+')) {
                pos++;
            }

            for (; pos < data.length; pos++) {
                char ch = data[pos];
                if (!isNumericASCII(ch)) {
                    break;
                }
            }
        }

        if (isBinary) {
            String signed = hasSigned ? data[start] + "" : "";
            int begin = start + (hasSigned ? 3 : 2);
            return Long.parseLong(signed + new String(data, begin, pos - begin), 2);
        } else if (isDouble || hasExponent) {
            return Double.valueOf(new String(data, start, pos - start));
        } else if (isHex) {
            String signed = hasSigned ? data[start] + "" : "";
            int begin = start + (hasSigned ? 3 : 2);
            return Long.parseLong(signed + new String(data, begin, pos - begin), 16);
        } else {
            return Long.parseLong(new String(data, start, pos - start));
        }
    }

    public String stringLiteral() throws SQLException {
        return stringView().toString();
    }

    public StringView stringView() throws SQLException {
        skipAnyWhitespace();
        Validate.isTrue(isCharacter('\''));
        return stringLiteralWithQuoted('\'');
    }

    public boolean eof() {
        skipAnyWhitespace();
        return pos >= data.length;
    }

    public boolean isCharacter(char ch) {
        return !eof() && data[pos] == ch;
    }

    public StringView bareWord() throws SQLException {
        skipAnyWhitespace();
        if (isCharacter('`')) {
            return stringLiteralWithQuoted('`');
        } else if (isCharacter('"')) {
            return stringLiteralWithQuoted('"');
        } else if ('_' == data[pos] || (data[pos] >= 'a' && data[pos] <= 'z')
                || (data[pos] >= 'A' && data[pos] <= 'Z')) {
            int start = pos;
            for (pos++; pos < data.length; pos++) {
                if (!('_' == data[pos] || (data[pos] >= 'a' && data[pos] <= 'z')
                        || (data[pos] >= 'A' && data[pos] <= 'Z') || (data[pos] >= '0' && data[pos] <= '9')))
                    break;
            }
            return new StringView(start, pos, data);
        }
        throw new SQLException("Expect Bare Token.");
    }

    public boolean isWhitespace() {
        return data[pos++] == ' ';
    }

    private boolean isNumericASCII(char c) {
        return c >= '0' && c <= '9';
    }

    private boolean isHexDigit(char c) {
        return isNumericASCII(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
    }

    private void skipAnyWhitespace() {
        for (; pos < data.length; pos++)
            if (data[pos] != ' ' && data[pos] != '\t' && data[pos] != '\n' && data[pos] != '\r' && data[pos] != '\f')
                return;
    }

    private StringView stringLiteralWithQuoted(char quoted) throws SQLException {
        int start = pos;
        Validate.isTrue(data[pos] == quoted);
        for (pos++; pos < data.length; pos++) {
            if (data[pos] == '\\')
                pos++;
            else if (data[pos] == quoted)
                return new StringView(start + 1, pos++, data);
        }
        throw new SQLException("The String Literal is no Closed.");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy