<commit_before>/*
 * Copyright (C) 2010-2014 <NAME>
 * <EMAIL>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.jkiss.dbeaver.model.sql.parser;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.data.DBDAttributeConstraint;
import org.jkiss.dbeaver.model.data.DBDDataFilter;
import org.jkiss.dbeaver.model.sql.SQLDataSource;
import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.utils.CommonUtils;

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

/**
 * Semantic SQL processor
 */
public class SQLSemanticProcessor {

    private static final String NESTED_QUERY_AlIAS = "z_q";

    static final Log log = LogFactory.getLog(SQLUtils.class);

    public static boolean isSelectQuery(String query)
    {
        try {
            Statement statement = CCJSqlParserUtil.parse(query);
            return statement instanceof Select &&
                ((Select) statement).getSelectBody() instanceof PlainSelect &&
                ((PlainSelect) ((Select) statement).getSelectBody()).getInto() == null;
        } catch (Exception e) {
            //log.debug(e);
            return false;
        }
    }

    public static String addFiltersToQuery(final DBPDataSource dataSource, String sqlQuery, final DBDDataFilter dataFilter) throws DBException {
        boolean supportSubqueries = dataSource instanceof SQLDataSource && ((SQLDataSource) dataSource).getSQLDialect().supportsSubqueries();
        try {
            Statement statement = CCJSqlParserUtil.parse(sqlQuery);
            if (statement instanceof Select && ((Select) statement).getSelectBody() instanceof PlainSelect) {
                PlainSelect select = (PlainSelect) ((Select) statement).getSelectBody();
                if (!supportSubqueries || CommonUtils.isEmpty(select.getJoins())) {
                    patchSelectQuery(dataSource, select, dataFilter);
                    return statement.toString();
                }
            }
            return wrapQuery(dataSource, sqlQuery, dataFilter);
        } catch (Exception e) {
            throw new DBException("SQL parse error", e);
        }
    }

    public static String wrapQuery(final DBPDataSource dataSource, String sqlQuery, final DBDDataFilter dataFilter) throws DBException {
        // Append filter conditions to query
        StringBuilder modifiedQuery = new StringBuilder(sqlQuery.length() + 100);
        modifiedQuery.append("SELECT * FROM (\n");
        modifiedQuery.append(sqlQuery);
        modifiedQuery.append("\n) ").append(NESTED_QUERY_AlIAS);
        if (dataFilter.hasConditions()) {
            modifiedQuery.append(" WHERE ");
            SQLUtils.appendConditionString(dataFilter, dataSource, NESTED_QUERY_AlIAS, modifiedQuery, true);
        }
        if (dataFilter.hasOrdering()) {
            modifiedQuery.append(" ORDER BY "); //$NON-NLS-1$
            SQLUtils.appendOrderString(dataFilter, dataSource, NESTED_QUERY_AlIAS, modifiedQuery);
        }
        return modifiedQuery.toString();
    }

    private static void patchSelectQuery(DBPDataSource dataSource, PlainSelect select, DBDDataFilter filter) throws JSQLParserException {
        // WHERE
        FromItem fromItem = select.getFromItem();
        String tableAlias = fromItem.getAlias() == null ? null : fromItem.getAlias().getName();
        if (filter.hasConditions()) {
            StringBuilder whereString = new StringBuilder();
            SQLUtils.appendConditionString(filter, dataSource, tableAlias, whereString, true);
            Expression filterWhere = CCJSqlParserUtil.parseCondExpression(whereString.toString());
            Expression sourceWhere = select.getWhere();
            if (sourceWhere == null) {
                select.setWhere(filterWhere);
            } else {
                select.setWhere(new AndExpression(new Parenthesis(sourceWhere), filterWhere));
            }
        }
        // ORDER
        if (filter.hasOrdering()) {
            List<OrderByElement> orderByElements = select.getOrderByElements();
            if (orderByElements == null) {
                orderByElements = new ArrayList<OrderByElement>();
                select.setOrderByElements(orderByElements);
            }
            Table orderTable = tableAlias == null ? null : new Table(tableAlias);
            for (DBDAttributeConstraint co : filter.getOrderConstraints()) {
                Expression orderExpr = new Column(orderTable, co.getAttribute().getName());
                OrderByElement element = new OrderByElement();
                element.setExpression(orderExpr);
                if (co.isOrderDescending()) {
                    element.setAsc(false);
                    element.setAscDescPresent(true);
                }
                orderByElements.add(element);
            }

        }

    }

}
<commit_msg>Struct types in custom SQL queries order<commit_after>/*
 * Copyright (C) 2010-2014 <NAME>
 * <EMAIL>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.jkiss.dbeaver.model.sql.parser;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.data.DBDAttributeConstraint;
import org.jkiss.dbeaver.model.data.DBDDataFilter;
import org.jkiss.dbeaver.model.sql.SQLDataSource;
import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.utils.CommonUtils;

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

/**
 * Semantic SQL processor
 */
public class SQLSemanticProcessor {

    private static final String NESTED_QUERY_AlIAS = "z_q";

    static final Log log = LogFactory.getLog(SQLUtils.class);

    public static boolean isSelectQuery(String query)
    {
        try {
            Statement statement = CCJSqlParserUtil.parse(query);
            return statement instanceof Select &&
                ((Select) statement).getSelectBody() instanceof PlainSelect &&
                ((PlainSelect) ((Select) statement).getSelectBody()).getInto() == null;
        } catch (Exception e) {
            //log.debug(e);
            return false;
        }
    }

    public static String addFiltersToQuery(final DBPDataSource dataSource, String sqlQuery, final DBDDataFilter dataFilter) throws DBException {
        boolean supportSubqueries = dataSource instanceof SQLDataSource && ((SQLDataSource) dataSource).getSQLDialect().supportsSubqueries();
        try {
            Statement statement = CCJSqlParserUtil.parse(sqlQuery);
            if (statement instanceof Select && ((Select) statement).getSelectBody() instanceof PlainSelect) {
                PlainSelect select = (PlainSelect) ((Select) statement).getSelectBody();
                if (!supportSubqueries || CommonUtils.isEmpty(select.getJoins())) {
                    patchSelectQuery(dataSource, select, dataFilter);
                    return statement.toString();
                }
            }
            return wrapQuery(dataSource, sqlQuery, dataFilter);
        } catch (Exception e) {
            throw new DBException("SQL parse error", e);
        }
    }

    public static String wrapQuery(final DBPDataSource dataSource, String sqlQuery, final DBDDataFilter dataFilter) throws DBException {
        // Append filter conditions to query
        StringBuilder modifiedQuery = new StringBuilder(sqlQuery.length() + 100);
        modifiedQuery.append("SELECT * FROM (\n");
        modifiedQuery.append(sqlQuery);
        modifiedQuery.append("\n) ").append(NESTED_QUERY_AlIAS);
        if (dataFilter.hasConditions()) {
            modifiedQuery.append(" WHERE ");
            SQLUtils.appendConditionString(dataFilter, dataSource, NESTED_QUERY_AlIAS, modifiedQuery, true);
        }
        if (dataFilter.hasOrdering()) {
            modifiedQuery.append(" ORDER BY "); //$NON-NLS-1$
            SQLUtils.appendOrderString(dataFilter, dataSource, NESTED_QUERY_AlIAS, modifiedQuery);
        }
        return modifiedQuery.toString();
    }

    private static void patchSelectQuery(DBPDataSource dataSource, PlainSelect select, DBDDataFilter filter) throws JSQLParserException {
        // WHERE
        FromItem fromItem = select.getFromItem();
        String tableAlias = fromItem.getAlias() == null ? null : fromItem.getAlias().getName();
        if (filter.hasConditions()) {
            StringBuilder whereString = new StringBuilder();
            SQLUtils.appendConditionString(filter, dataSource, tableAlias, whereString, true);
            Expression filterWhere = CCJSqlParserUtil.parseCondExpression(whereString.toString());
            Expression sourceWhere = select.getWhere();
            if (sourceWhere == null) {
                select.setWhere(filterWhere);
            } else {
                select.setWhere(new AndExpression(new Parenthesis(sourceWhere), filterWhere));
            }
        }
        // ORDER
        if (filter.hasOrdering()) {
            List<OrderByElement> orderByElements = select.getOrderByElements();
            if (orderByElements == null) {
                orderByElements = new ArrayList<OrderByElement>();
                select.setOrderByElements(orderByElements);
            }
            Table orderTable = tableAlias == null ? null : new Table(tableAlias);
            for (DBDAttributeConstraint co : filter.getOrderConstraints()) {
                Expression orderExpr = new Column(orderTable, DBUtils.getObjectFullName(co.getAttribute()));
                OrderByElement element = new OrderByElement();
                element.setExpression(orderExpr);
                if (co.isOrderDescending()) {
                    element.setAsc(false);
                    element.setAscDescPresent(true);
                }
                orderByElements.add(element);
            }

        }

    }

}

{'fraction_non_alphanumeric': 0.09227086711450853, 'fraction_numerical': 0.004323990425449772, 'mean_word_length': 2.706926159129937, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '835628', 'n_tokens_mistral': 3440, 'n_tokens_neox': 3324, 'n_words': 828}