<commit_before>/*
 * Copyright 2007 - 2018 the original author or authors.
 *
 * 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 net.sf.jailer.ui.databrowser.sqlconsole;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

/**
 * Supports some Oracle SQL+ statements.
 *
 * @author <NAME>
 */
public class SQLPlusSupport {

	/**
	 * The logger.
	 */
	private static final Logger logger = Logger.getLogger(SQLPlusSupport.class);
	
	/**
	 * The variables.
	 */
	private Map<String, String> variables = new HashMap<String, String>();
	
	/**
	 * Column substitutions.
	 */
	private Map<String, String[]> columnSubstitutions = new HashMap<String, String[]>();
	
	private Pattern DEFINE_PATTERN = Pattern.compile("\\s*DEFINE\\s+(\\w+)\\s*=\\s*(.*)\\s*", Pattern.CASE_INSENSITIVE);
	private Pattern UNDEFINE_PATTERN = Pattern.compile("\\s*UNDEFINE\\s+((?:\\w+\\s*)+)", Pattern.CASE_INSENSITIVE);
	private Pattern COLUMN_PATTERN = Pattern.compile("\\s*COLUMN\\s+(\\w+)\\s*((?:(?:new_value|old_value)\\s+\\w+\\s*)+)", Pattern.CASE_INSENSITIVE);
	
	/**
	 * Executes a SQLPlus statement.
	 * 
	 * @param statement the statement
	 * @return <code>true</code> if statement is a valid SQLPlus statement
	 */
	public boolean executeSQLPLusStatement(String statement) {
		Matcher matcher = DEFINE_PATTERN.matcher(statement);
		if (matcher.matches()) {
			String var = matcher.group(1);
			String val = matcher.group(2).trim();
			if (val.length() > 1 && val.startsWith("\"") && val.endsWith("\"")) {
				val = val.substring(1, val.length() - 1);
			}
			variables.put(var.toUpperCase(), val);
			logger.info("DEFINE " + var + " = " + val);
			return true;
		}
		matcher = UNDEFINE_PATTERN.matcher(statement);
		if (matcher.matches()) {
			for (String var: matcher.group(1).split("\\s+")) {
				variables.remove(var.toUpperCase());
			}
			return true;
		}
		matcher = COLUMN_PATTERN.matcher(statement);
		if (matcher.matches()) {
			String column = matcher.group(1);
			String[] variables = matcher.group(2).split("(?i:\\s*(new_value|old_value)\\s*)");
			columnSubstitutions.put(column.toUpperCase(), variables);
			return true;
		}
		return false;
	}

	/**
	 * Replaces all occurrences of "&amp;&lt;var&gt;[.]" with variable values.
	 * 
	 * @param statement the statement
	 * @param positionOffsets map to put position offsets into
	 * @return statement with variable replacements
	 */
	public String replaceVariables(String statement, SortedMap<Integer, Integer> positionOffsets) {
		if (!variables.isEmpty()) {
			Matcher matcher = Pattern.compile("&(\\w+)(\\.|\\b)").matcher(statement);
			matcher.reset();
			int offset = 0;
			boolean result = matcher.find();
			if (result) {
				StringBuffer sb = new StringBuffer();
				do {
					String var = matcher.group(1);
					String replacement = variables.get(var.toUpperCase());
					if (replacement != null) {
						matcher.appendReplacement(sb, replacement);<commit_msg>SQL-Console: added support for substitution variables<commit_after>/*
 * Copyright 2007 - 2018 the original author or authors.
 *
 * 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 net.sf.jailer.ui.databrowser.sqlconsole;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

/**
 * Supports some Oracle SQL+ statements.
 *
 * @author <NAME>
 */
public class SQLPlusSupport {

	/**
	 * The logger.
	 */
	private static final Logger logger = Logger.getLogger(SQLPlusSupport.class);
	
	/**
	 * The variables.
	 */
	private Map<String, String> variables = new HashMap<String, String>();
	
	/**
	 * Column substitutions.
	 */
	private Map<String, String[]> columnSubstitutions = new HashMap<String, String[]>();
	
	private Pattern DEFINE_PATTERN = Pattern.compile("\\s*DEFINE\\s+(\\w+)\\s*=\\s*(.*)\\s*", Pattern.CASE_INSENSITIVE);
	private Pattern UNDEFINE_PATTERN = Pattern.compile("\\s*UNDEFINE\\s+((?:\\w+\\s*)+)", Pattern.CASE_INSENSITIVE);
	private Pattern COLUMN_PATTERN = Pattern.compile("\\s*COLUMN\\s+(\\w+)\\s*((?:(?:new_value|old_value)\\s+\\w+\\s*)+)", Pattern.CASE_INSENSITIVE);
	
	/**
	 * Executes a SQLPlus statement.
	 * 
	 * @param statement the statement
	 * @return <code>true</code> if statement is a valid SQLPlus statement
	 */
	public boolean executeSQLPLusStatement(String statement) {
		Matcher matcher = DEFINE_PATTERN.matcher(statement);
		if (matcher.matches()) {
			String var = matcher.group(1);
			String val = matcher.group(2).trim();
			if (val.length() > 1 && val.startsWith("\"") && val.endsWith("\"")) {
				val = val.substring(1, val.length() - 1);
			}
			variables.put(var.toUpperCase(), val);
			logger.info("DEFINE " + var + " = " + val);
			return true;
		}
		matcher = UNDEFINE_PATTERN.matcher(statement);
		if (matcher.matches()) {
			for (String var: matcher.group(1).split("\\s+")) {
				variables.remove(var.toUpperCase());
			}
			return true;
		}
		matcher = COLUMN_PATTERN.matcher(statement);
		if (matcher.matches()) {
			String column = matcher.group(1);
			String[] variables = matcher.group(2).split("(?i:\\s*(new_value|old_value)\\s*)");
			columnSubstitutions.put(column.toUpperCase(), variables);
			return true;
		}
		return false;
	}

	/**
	 * Replaces all occurrences of "&amp;&lt;var&gt;[.]" with variable values.
	 * 
	 * @param statement the statement
	 * @param positionOffsets map to put position offsets into
	 * @return statement with variable replacements
	 */
	public String replaceVariables(String statement, SortedMap<Integer, Integer> positionOffsets) {
		if (!variables.isEmpty()) {
			Matcher matcher = Pattern.compile("&(\\w+)(\\.|\\b)").matcher(statement);
			matcher.reset();
			int offset = 0;
			boolean result = matcher.find();
			if (result) {
				StringBuffer sb = new StringBuffer();
				do {
					String var = matcher.group(1);
					String replacement = variables.get(var.toUpperCase());
					if (replacement != null) {
						matcher.appendReplacement(sb,  Matcher.quoteReplacement(replacement));
{'fraction_non_alphanumeric': 0.150074294205052, 'fraction_numerical': 0.006213697149804133, 'mean_word_length': 3.9130723291307232, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '5397777', 'n_tokens_mistral': 2545, 'n_tokens_neox': 2264, 'n_words': 598}