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

com.blazebit.persistence.impl.util.SqlUtils Maven / Gradle / Ivy

The newest version!
package com.blazebit.persistence.impl.util;

import java.util.ArrayList;
import java.util.List;

public class SqlUtils {

    private static final String SELECT = "select ";
    private static final String FROM = " from ";
    private static final String WITH = "with ";
    private static final String FROM_FINAL_TABLE = " from final table (";
    private static final String NEXT_VALUE_FOR = "next value for ";
    private static final PatternFinder SELECT_FINDER = new BoyerMooreCaseInsensitiveAsciiFirstPatternFinder(SELECT);
    private static final PatternFinder FROM_FINDER = new BoyerMooreCaseInsensitiveAsciiFirstPatternFinder(FROM);
    private static final PatternFinder WITH_FINDER = new BoyerMooreCaseInsensitiveAsciiFirstPatternFinder(WITH);
    private static final PatternFinder FROM_FINAL_TABLE_FINDER = new BoyerMooreCaseInsensitiveAsciiFirstPatternFinder(FROM_FINAL_TABLE);
    private static final PatternFinder NEXT_VALUE_FOR_FINDER = new BoyerMooreCaseInsensitiveAsciiFirstPatternFinder(NEXT_VALUE_FOR);

    public static int countSelectItems(CharSequence sql) {
        int count = 1;
        int parenthesis = 0;
        for (int i = 0; i < sql.length(); i++) {
            final char c = sql.charAt(i);

            if (c == '(') {
                parenthesis++;
            } else if (c == ')') {
                parenthesis--;
            } else if (parenthesis == 0 && c == ',') {
                count++;
            }
        }

        return count;
    }

    public static String[] getSelectItemAliases(CharSequence sql, int start) {
        int selectIndex = SELECT_FINDER.indexIn(sql, start);
        int fromIndex = FROM_FINDER.indexIn(sql, selectIndex);
        // from-less query
        if (fromIndex == -1) {
            fromIndex = sql.length();
        }

        List selectAliases = new ArrayList();
        StringBuilder sb = new StringBuilder();
        int parenthesis = 0;
        boolean text = false;

        int i = selectIndex + SELECT.length();
        int end = fromIndex;
        while (i < end) {
            final char c = sql.charAt(i);

            if (text) {
                if (parenthesis == 0 && c == ',') {
                    selectAliases.add(extractAlias(sb, selectAliases.size()));
                    sb.setLength(0);
                    text = false;
                } else {
                    sb.append(c);
                }
            } else {
                if (Character.isWhitespace(c)) {
                    // skip whitespace
                    i++;
                    continue;
                } else if (c == '(') {
                    // While we are in a subcontext, consider the whole query
                    end = sql.length();

                    parenthesis++;
                } else if (c == ')') {
                    // When we leave the context, reset the end to the from index
                    if (i < fromIndex) {
                        end = fromIndex;
                    } else {
                        // If the found from was in the subcontext, find the next from
                        end = fromIndex = FROM_FINDER.indexIn(sql, i);
                        // from-less query
                        if (fromIndex == -1) {
                            end = fromIndex = sql.length();
                        }
                    }

                    parenthesis--;
                }

                sb.append(c);
                text = true;
            }

            i++;
        }

        if (text) {
            selectAliases.add(extractAlias(sb, selectAliases.size()));
        }

        return selectAliases.toArray(new String[selectAliases.size()]);
    }

    public static int indexOfSelect(CharSequence sql) {
        int selectIndex = SELECT_FINDER.indexIn(sql);
        int withIndex = WITH_FINDER.indexIn(sql, 0, selectIndex);
        if (withIndex == -1) {
            return selectIndex;
        }

        int brackets = 0;
        int i = withIndex + WITH.length() + 1;
        int end = selectIndex;
        while (i < end) {
            final char c = sql.charAt(i);
            if (c == '(') {
                // While we are in a subcontext, consider the whole query
                end = sql.length();

                brackets++;
            } else if (c == ')') {
                brackets--;

                if (brackets == 0) {
                    // When we leave the context, reset the end to the select index
                    if (i < selectIndex) {
                        end = selectIndex;
                    } else {
                        // If the found select was in the subcontext, find the next select
                        end = selectIndex = SELECT_FINDER.indexIn(sql, i);
                    }
                }
            }
            i++;
        }

        return selectIndex;
    }

    public static int[] indexOfFinalTableSubquery(CharSequence sql, int selectIndex) {
        int fromFinalTableIndex = FROM_FINAL_TABLE_FINDER.indexIn(sql, selectIndex);
        if (fromFinalTableIndex == -1) {
            return new int[] { 0, sql.length() };
        }
        int brackets = 1;
        int i = fromFinalTableIndex + FROM_FINAL_TABLE.length();
        int end = sql.length();
        while (i < end) {
            final char c = sql.charAt(i);
            if (c == '(') {
                brackets++;
            } else if (c == ')') {
                brackets--;

                if (brackets == 0) {
                    return new int[] { fromFinalTableIndex + FROM_FINAL_TABLE.length(), i };
                }
            }
            i++;
        }

        return new int[] { 0, sql.length() };
    }

    private static String extractAlias(StringBuilder sb, int index) {
        int aliasEndCharIndex = findLastNonWhitespace(sb);
        int aliasBeforeIndex = findLastWhitespace(sb, aliasEndCharIndex);
        if (aliasBeforeIndex < 0) {
            aliasBeforeIndex = sb.lastIndexOf(".");
        }
        if (NEXT_VALUE_FOR_FINDER.indexIn(sb) != -1) {
            // Since sequences in subqueries might not be allowed, we pass the whole expression
            return sb.toString();
        }
        return sb.substring(aliasBeforeIndex + 1, aliasEndCharIndex + 1);
    }

    private static int findLastNonWhitespace(StringBuilder sb) {
        int i = sb.length() - 1;
        while (i >= 0) {
            if (!Character.isWhitespace(sb.charAt(i))) {
                break;
            } else {
                i--;
            }
        }

        return i;
    }

    private static int findLastWhitespace(StringBuilder sb, int end) {
        int i = end;
        while (i >= 0) {
            if (Character.isWhitespace(sb.charAt(i))) {
                break;
            } else {
                i--;
            }
        }

        return i;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy