package org.shaneking.aspectj.jsqlparser.util;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.arithmetic.*;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.*;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.comment.Comment;
import net.sf.jsqlparser.statement.create.index.CreateIndex;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.create.view.AlterView;
import net.sf.jsqlparser.statement.create.view.CreateView;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.drop.Drop;
import net.sf.jsqlparser.statement.execute.Execute;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.merge.Merge;
import net.sf.jsqlparser.statement.replace.Replace;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.truncate.Truncate;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.statement.upsert.Upsert;
import net.sf.jsqlparser.statement.values.ValuesStatement;
import org.shaneking.aspectj.jsqlparser.annotation.SensitiveItemsFinderAlias;
import org.shaneking.aspectj.jsqlparser.annotation.SensitiveItemsFinderAsterisk;
import org.shaneking.aspectj.jsqlparser.annotation.SensitiveItemsFinderPath;
import org.shaneking.aspectj.jsqlparser.annotation.SensitiveItemsFinderTransformed;
import org.shaneking.skava.lang.String0;
import org.shaneking.skava.persistence.Tuple;
import java.util.*;
import java.util.stream.Collectors;
/**
* Precondition: explain pass
* Order: inter -> outer
* Focus:
* 1.select item (x.y)
* 2.column transformed
*
* https://www.postgresql.org/docs/current/static/sql-select.html
* [ WITH [ RECURSIVE ] with_query [, ...] ]
* SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
* [ * | expression [ [ AS ] output_name ] [, ...] ]
* [ FROM from_item [, ...] ]
* [ WHERE condition ]
* [ GROUP BY grouping_element [, ...] ]
* [ HAVING condition [, ...] ]
* [ WINDOW window_name AS ( window_definition ) [, ...] ]
* [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
* [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
* [ LIMIT { count | ALL } ]
* [ OFFSET start [ ROW | ROWS ] ]
* [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
* [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]
*
* where from_item can be one of:
*
* [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
* [ TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ] ]
* [ LATERAL ] ( select ) [ AS ] alias [ ( column_alias [, ...] ) ]
* with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
* [ LATERAL ] function_name ( [ argument [, ...] ] )
* [ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
* [ LATERAL ] function_name ( [ argument [, ...] ] ) [ AS ] alias ( column_definition [, ...] )
* [ LATERAL ] function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )
* [ LATERAL ] ROWS FROM( function_name ( [ argument [, ...] ] ) [ AS ( column_definition [, ...] ) ] [, ...] )
* [ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
* from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]
*
* and grouping_element can be one of:
*
* ( )
* expression
* ( expression [, ...] )
* ROLLUP ( { expression | ( expression [, ...] ) } [, ...] )
* CUBE ( { expression | ( expression [, ...] ) } [, ...] )
* GROUPING SETS ( grouping_element [, ...] )
*
* and with_query is:
*
* with_query_name [ ( column_name [, ...] ) ] AS ( select | values | insert | update | delete )
*
* TABLE [ ONLY ] table_name [ * ]
*/
public class SensitiveItemsFinder implements SelectVisitor, FromItemVisitor, ExpressionVisitor, ItemsListVisitor, SelectItemVisitor, StatementVisitor {
public static final String PATH_OF_FROM_ITEM = "FromItem";//LateralSubSelect|ParenthesisFromItem|SubJoin
public static final String PATH_OF_INSERT = "Insert";
public static final String PATH_OF_SELECT = "Select";
public static final String PATH_OF_SELECT_EXPRESSION_ITEM = "SelectExpressionItem";
public static final String PATH_OF_SUB_SELECT = "SubSelect";
public static final String PATH_OF_TRUNCATE = "Truncate";
public static final String PATH_OF_WITH_ITEM = "WithItem";
private static final String NOT_SUPPORTED_EXPRESSION_YET = "Not supported expression yet";
private static final String NOT_SUPPORTED_EXPRESSION_LIST_YET = "Not supported expression list yet";
private static final String NOT_SUPPORTED_FROM_ITEM_TYPE_YET = "Not supported from item type yet";
private static final String NOT_SUPPORTED_SELECT_ITEM_LIST_IN_WITH_ITEM_YET = "Not supported select item list in with item yet";
private static final String NOT_SUPPORTED_STATEMENT_TYPE_YET = "Not supported statement type yet";
private static final String THE_COLUMN_MUST_BE_LIKE_X_Y = "The column must be like x.y";
/**
* one aliasTableName mapping multiple realTableName
* one alias/readColumnName/* mapping multiple realColumnName
* lifecycle: just store in select or subSelect
*/
@Getter
@Setter
private Map, Map, Boolean>>>>> itemMap = Maps.newHashMap();
/**
* SensitiveItemsFinderPath
*/
@Getter
private Stack pathStack = new Stack<>();
/**
* null:out select expression item
* String0.EMPTY:in select expression item without alias
* alias:in select expression item with alias
*/
@Getter
@Setter
private String selectExpressionItemAlias = null;
/**
* SELECT (select (select a.host+b.host+c.host as c3 from mysql.user c where c.user = a.user) as c2 from mysql.user b where b.user = a.user) as c1 FROM mysql.user a;
*/
private Stack