package com.chenyang.druid.sql;

import com.chenyang.druid.sql.ast.SQLDataType;
import com.chenyang.druid.sql.ast.SQLDataTypeImpl;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.expr.SQLAllColumnExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOperator;
import com.chenyang.druid.sql.ast.expr.SQLCaseExpr;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntervalExpr;
import com.chenyang.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.chenyang.druid.sql.ast.expr.SQLNullExpr;
import com.chenyang.druid.sql.ast.expr.SQLNumericLiteralExpr;
import com.chenyang.druid.sql.ast.expr.SQLVariantRefExpr;
import com.chenyang.druid.sql.ast.statement.SQLCharacterDataType;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLJoinTableSource;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.dialect.oracle.ast.clause.OracleWithSubqueryEntry;
import com.chenyang.druid.sql.dialect.oracle.ast.expr.OracleSysdateExpr;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleSelectJoin;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleSelectSubqueryTableSource;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference;
import com.chenyang.druid.util.FnvHash;
import java.util.List;

public class SQLTransformUtils {
   public static SQLExpr transformDecode(SQLMethodInvokeExpr x) {
      if (x == null) {
         return null;
      } else if (FnvHash.Constants.DECODE != x.methodNameHashCode64()) {
         throw new IllegalArgumentException(x.getMethodName());
      } else {
         List<SQLExpr> arguments = x.getArguments();
         SQLCaseExpr caseExpr = new SQLCaseExpr();
         caseExpr.setParent(x.getParent());
         caseExpr.setValueExpr((SQLExpr)arguments.get(0));
         if (arguments.size() == 4) {
            SQLExpr param1 = (SQLExpr)arguments.get(1);
            x.setMethodName("if");
            SQLBinaryOpExpr condition;
            if (param1 instanceof SQLNullExpr) {
               condition = new SQLBinaryOpExpr((SQLExpr)arguments.get(0), SQLBinaryOperator.Is, param1);
            } else {
               condition = new SQLBinaryOpExpr((SQLExpr)arguments.get(0), SQLBinaryOperator.Equality, param1);
            }

            condition.setParent(x);
            arguments.set(0, condition);
            arguments.set(1, arguments.get(2));
            arguments.set(2, arguments.get(3));
            arguments.remove(3);
            return x;
         } else {
            for(int i = 1; i + 1 < arguments.size(); i += 2) {
               SQLCaseExpr.Item item = new SQLCaseExpr.Item();
               SQLExpr conditionExpr = (SQLExpr)arguments.get(i);
               item.setConditionExpr(conditionExpr);
               SQLExpr valueExpr = (SQLExpr)arguments.get(i + 1);
               if (valueExpr instanceof SQLMethodInvokeExpr) {
                  SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr)valueExpr;
                  if (FnvHash.Constants.DECODE == methodInvokeExpr.methodNameHashCode64()) {
                     valueExpr = transformDecode(methodInvokeExpr);
                  }
               }

               item.setValueExpr(valueExpr);
               caseExpr.addItem(item);
            }

            if (arguments.size() % 2 == 0) {
               SQLExpr defaultExpr = (SQLExpr)arguments.get(arguments.size() - 1);
               if (defaultExpr instanceof SQLMethodInvokeExpr) {
                  SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr)defaultExpr;
                  if (FnvHash.Constants.DECODE == methodInvokeExpr.methodNameHashCode64()) {
                     defaultExpr = transformDecode(methodInvokeExpr);
                  }
               }

               caseExpr.setElseExpr(defaultExpr);
            }

            caseExpr.setParent(x.getParent());
            return caseExpr;
         }
      }
   }

   public static SQLDataType transformOracleToMySql(SQLDataType x) {
      String name = x.getName();
      long nameHash = x.nameHashCode64();
      if (name == null) {
         return x;
      } else {
         List<SQLExpr> argumentns = x.getArguments();
         SQLDataType dataType;
         if (nameHash == FnvHash.Constants.UROWID) {
            int len = 4000;
            if (argumentns.size() == 1) {
               SQLExpr arg0 = (SQLExpr)argumentns.get(0);
               if (arg0 instanceof SQLIntegerExpr) {
                  len = ((SQLIntegerExpr)arg0).getNumber().intValue();
               }
            }

            dataType = new SQLDataTypeImpl("varchar", len);
         } else if (nameHash == FnvHash.Constants.ROWID) {
            dataType = new SQLDataTypeImpl("char", 10);
         } else if (nameHash == FnvHash.Constants.BOOLEAN) {
            dataType = new SQLDataTypeImpl("tinyint");
         } else if (nameHash == FnvHash.Constants.INTEGER) {
            dataType = new SQLDataTypeImpl("int");
         } else if (nameHash != FnvHash.Constants.FLOAT && nameHash != FnvHash.Constants.BINARY_FLOAT) {
            if (nameHash != FnvHash.Constants.REAL && nameHash != FnvHash.Constants.BINARY_DOUBLE && nameHash != FnvHash.Constants.DOUBLE_PRECISION) {
               if (nameHash == FnvHash.Constants.NUMBER) {
                  if (argumentns.size() == 0) {
                     dataType = new SQLDataTypeImpl("decimal", 38);
                  } else {
                     SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                     int scale = 0;
                     int precision;
                     if (arg0 instanceof SQLAllColumnExpr) {
                        precision = 9;
                     } else {
                        precision = ((SQLIntegerExpr)arg0).getNumber().intValue();
                     }

                     if (argumentns.size() > 1) {
                        scale = ((SQLIntegerExpr)argumentns.get(1)).getNumber().intValue();
                     }

                     if (scale > precision) {
                        if (arg0 instanceof SQLAllColumnExpr) {
                           precision = 19;
                           if (scale > precision) {
                              precision = scale;
                           }
                        } else {
                           precision = scale;
                        }
                     }

                     if (scale == 0) {
                        if (precision < 3) {
                           dataType = new SQLDataTypeImpl("tinyint");
                        } else if (precision < 5) {
                           dataType = new SQLDataTypeImpl("smallint");
                        } else if (precision < 9) {
                           dataType = new SQLDataTypeImpl("int");
                        } else if (precision <= 20) {
                           dataType = new SQLDataTypeImpl("bigint");
                        } else {
                           dataType = new SQLDataTypeImpl("decimal", precision);
                        }
                     } else {
                        dataType = new SQLDataTypeImpl("decimal", precision, scale);
                     }
                  }
               } else if (nameHash != FnvHash.Constants.DEC && nameHash != FnvHash.Constants.DECIMAL) {
                  if (nameHash == FnvHash.Constants.RAW) {
                     int len;
                     if (argumentns.size() == 0) {
                        len = -1;
                     } else {
                        if (argumentns.size() != 1) {
                           throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                        }

                        SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                        if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                           throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                        }

                        len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                     }

                     if (len == -1) {
                        dataType = new SQLDataTypeImpl("binary");
                     } else if (len <= 255) {
                        dataType = new SQLDataTypeImpl("binary", len);
                     } else {
                        dataType = new SQLDataTypeImpl("varbinary", len);
                     }
                  } else if (nameHash != FnvHash.Constants.CHAR && nameHash != FnvHash.Constants.CHARACTER) {
                     if (nameHash == FnvHash.Constants.NCHAR) {
                        if (argumentns.size() == 1) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           if (len <= 255) {
                              dataType = new SQLCharacterDataType("nchar", len);
                           } else {
                              dataType = new SQLCharacterDataType("nvarchar", len);
                           }
                        } else {
                           if (argumentns.size() != 0) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           dataType = new SQLCharacterDataType("nchar");
                        }
                     } else if (nameHash == FnvHash.Constants.VARCHAR2) {
                        if (argumentns.size() > 0) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           dataType = new SQLCharacterDataType("varchar", len);
                        } else {
                           dataType = new SQLCharacterDataType("varchar");
                        }
                     } else if (nameHash == FnvHash.Constants.NVARCHAR2) {
                        if (argumentns.size() > 0) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           dataType = new SQLCharacterDataType("nvarchar", len);
                        } else {
                           dataType = new SQLCharacterDataType("nvarchar");
                        }
                     } else if (nameHash == FnvHash.Constants.BFILE) {
                        dataType = new SQLCharacterDataType("varchar", 255);
                     } else if (nameHash != FnvHash.Constants.DATE && nameHash != FnvHash.Constants.TIMESTAMP) {
                        if (nameHash != FnvHash.Constants.BLOB && nameHash != FnvHash.Constants.LONG_RAW) {
                           if (nameHash != FnvHash.Constants.CLOB && nameHash != FnvHash.Constants.NCLOB && nameHash != FnvHash.Constants.LONG && nameHash != FnvHash.Constants.XMLTYPE) {
                              dataType = x;
                           } else {
                              argumentns.clear();
                              dataType = new SQLCharacterDataType("LONGTEXT");
                           }
                        } else {
                           argumentns.clear();
                           dataType = new SQLDataTypeImpl("LONGBLOB");
                        }
                     } else {
                        int len = -1;
                        if (argumentns.size() > 0) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                        }

                        if (len >= 0) {
                           if (len > 6) {
                              len = 6;
                           }

                           dataType = new SQLDataTypeImpl("datetime", len);
                        } else {
                           dataType = new SQLDataTypeImpl("datetime");
                        }
                     }
                  } else if (argumentns.size() == 1) {
                     SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                     if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                        throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                     }

                     int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                     if (len <= 255) {
                        dataType = new SQLCharacterDataType("char", len);
                     } else {
                        dataType = new SQLCharacterDataType("varchar", len);
                     }
                  } else {
                     if (argumentns.size() != 0) {
                        throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                     }

                     dataType = new SQLCharacterDataType("char");
                  }
               } else {
                  dataType = x.clone();
                  dataType.setName("decimal");
                  int precision = 0;
                  if (argumentns.size() > 0) {
                     precision = ((SQLIntegerExpr)argumentns.get(0)).getNumber().intValue();
                  }

                  int scale = 0;
                  if (argumentns.size() > 1) {
                     scale = ((SQLIntegerExpr)argumentns.get(1)).getNumber().intValue();
                     if (precision < scale) {
                        ((SQLIntegerExpr)dataType.getArguments().get(1)).setNumber(precision);
                     }
                  }
               }
            } else {
               dataType = new SQLDataTypeImpl("double");
            }
         } else {
            dataType = new SQLDataTypeImpl("float");
         }

         if (dataType != x) {
            dataType.setParent(x.getParent());
         }

         return dataType;
      }
   }

   public static SQLDataType transformOracleToAliyunAds(SQLDataType x) {
      String dataTypeName = x.getName().toLowerCase();
      SQLDataType dataType;
      if (!dataTypeName.equals("varchar2") && !dataTypeName.equals("varchar") && !dataTypeName.equals("char") && !dataTypeName.equals("nchar") && !dataTypeName.equals("nvarchar") && !dataTypeName.equals("nvarchar2") && !dataTypeName.equals("clob") && !dataTypeName.equals("nclob") && !dataTypeName.equals("blob") && !dataTypeName.equals("long") && !dataTypeName.equals("long raw") && !dataTypeName.equals("raw")) {
         if (!dataTypeName.equals("number") && !dataTypeName.equals("decimal") && !dataTypeName.equals("dec") && !dataTypeName.equals("numeric")) {
            if (!dataTypeName.equals("date") && !dataTypeName.equals("datetime") && !dataTypeName.equals("timestamp")) {
               if (!dataTypeName.equals("float") && !dataTypeName.equals("binary_float")) {
                  if (!dataTypeName.equals("double") && !dataTypeName.equals("binary_double")) {
                     dataType = x;
                  } else {
                     dataType = new SQLDataTypeImpl("double");
                  }
               } else {
                  dataType = new SQLDataTypeImpl("float");
               }
            } else {
               dataType = new SQLDataTypeImpl("timestamp");
            }
         } else {
            int scale = 0;
            if (x.getArguments().size() > 1) {
               scale = ((SQLIntegerExpr)x.getArguments().get(1)).getNumber().intValue();
            }

            if (scale == 0) {
               dataType = new SQLDataTypeImpl("bigint");
            } else {
               dataType = new SQLDataTypeImpl("double");
            }
         }
      } else {
         dataType = new SQLCharacterDataType("varchar");
      }

      if (dataType != x) {
         dataType.setParent(x.getParent());
      }

      return dataType;
   }

   public static SQLDataType transformOracleToPostgresql(SQLDataType x) {
      String name = x.getName();
      long nameHash = x.nameHashCode64();
      if (name == null) {
         return x;
      } else {
         List<SQLExpr> argumentns = x.getArguments();
         SQLDataType dataType;
         if (nameHash == FnvHash.Constants.UROWID) {
            int len = 4000;
            if (argumentns.size() == 1) {
               SQLExpr arg0 = (SQLExpr)argumentns.get(0);
               if (arg0 instanceof SQLIntegerExpr) {
                  len = ((SQLIntegerExpr)arg0).getNumber().intValue();
               }
            }

            dataType = new SQLDataTypeImpl("VARCHAR", len);
         } else if (nameHash == FnvHash.Constants.ROWID) {
            dataType = new SQLDataTypeImpl("CHAR", 10);
         } else if (nameHash != FnvHash.Constants.BOOLEAN && nameHash != FnvHash.Constants.SMALLINT) {
            if (nameHash != FnvHash.Constants.INTEGER && nameHash != FnvHash.Constants.INT) {
               if (nameHash == FnvHash.Constants.BINARY_FLOAT) {
                  dataType = new SQLDataTypeImpl("REAL");
               } else if (nameHash != FnvHash.Constants.BINARY_DOUBLE && nameHash != FnvHash.Constants.FLOAT && nameHash != FnvHash.Constants.DOUBLE && nameHash != FnvHash.Constants.REAL && nameHash != FnvHash.Constants.DOUBLE_PRECISION) {
                  if (nameHash == FnvHash.Constants.NUMBER) {
                     if (argumentns.size() == 0) {
                        dataType = new SQLDataTypeImpl("DECIMAL", 38);
                     } else {
                        SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                        int scale = 0;
                        int precision;
                        if (arg0 instanceof SQLAllColumnExpr) {
                           precision = 19;
                           scale = -1;
                        } else {
                           precision = ((SQLIntegerExpr)arg0).getNumber().intValue();
                        }

                        if (argumentns.size() > 1) {
                           scale = ((SQLIntegerExpr)argumentns.get(1)).getNumber().intValue();
                        }

                        if (scale > precision) {
                           if (arg0 instanceof SQLAllColumnExpr) {
                              precision = 19;
                              if (scale > precision) {
                                 precision = scale;
                              }
                           } else {
                              precision = scale;
                           }
                        }

                        if (scale == 0) {
                           if (precision < 5) {
                              dataType = new SQLDataTypeImpl("SMALLINT");
                           } else if (precision < 9) {
                              dataType = new SQLDataTypeImpl("INT");
                           } else if (precision <= 20) {
                              dataType = new SQLDataTypeImpl("BIGINT");
                           } else {
                              dataType = new SQLDataTypeImpl("DECIMAL", precision);
                           }
                        } else if (scale == -1) {
                           dataType = new SQLDataTypeImpl("DOUBLE PRECISION");
                        } else {
                           dataType = new SQLDataTypeImpl("DECIMAL", precision, scale);
                        }
                     }
                  } else if (nameHash != FnvHash.Constants.DEC && nameHash != FnvHash.Constants.DECIMAL) {
                     if (nameHash == FnvHash.Constants.CHARACTER) {
                        if (argumentns.size() == 1) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           dataType = new SQLCharacterDataType("CHAR", len);
                        } else {
                           if (argumentns.size() != 0) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           dataType = new SQLCharacterDataType("CHAR");
                        }
                     } else if (nameHash == FnvHash.Constants.CHAR) {
                        if (argumentns.size() == 1) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           if (len <= 2000) {
                              dataType = x;
                              x.setName("CHAR");
                           } else {
                              dataType = new SQLCharacterDataType("TEXT");
                           }
                        } else {
                           if (argumentns.size() != 0) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           dataType = new SQLCharacterDataType("CHAR");
                        }
                     } else if (nameHash == FnvHash.Constants.NCHAR) {
                        dataType = x;
                        x.setName("NCHAR");
                     } else if (nameHash != FnvHash.Constants.VARCHAR && nameHash != FnvHash.Constants.VARCHAR2) {
                        if (nameHash != FnvHash.Constants.NVARCHAR && nameHash != FnvHash.Constants.NVARCHAR2 && nameHash != FnvHash.Constants.NCHAR_VARYING) {
                           if (nameHash == FnvHash.Constants.BFILE) {
                              dataType = new SQLCharacterDataType("VARCHAR", 255);
                           } else if (nameHash == FnvHash.Constants.DATE) {
                              dataType = new SQLDataTypeImpl("TIMESTAMP", 0);
                           } else if (nameHash == FnvHash.Constants.TIMESTAMP) {
                              x.setName("TIMESTAMP");
                              if (x.isWithLocalTimeZone()) {
                                 x.setWithLocalTimeZone(false);
                                 x.setWithTimeZone((Boolean)null);
                              }

                              dataType = x;
                           } else if (nameHash == FnvHash.Constants.DATETIME) {
                              int len = -1;
                              if (argumentns.size() > 0) {
                                 SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                                 if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                                    throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                                 }

                                 len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                              }

                              if (len > 0) {
                                 dataType = new SQLDataTypeImpl("TIMESTAMP", len);
                              } else {
                                 dataType = new SQLDataTypeImpl("TIMESTAMP");
                              }
                           } else if (nameHash != FnvHash.Constants.BLOB && nameHash != FnvHash.Constants.LONG_RAW && nameHash != FnvHash.Constants.RAW) {
                              if (nameHash != FnvHash.Constants.CLOB && nameHash != FnvHash.Constants.NCLOB && nameHash != FnvHash.Constants.LONG) {
                                 if (nameHash == FnvHash.Constants.XMLTYPE) {
                                    dataType = new SQLDataTypeImpl("XML");
                                 } else {
                                    dataType = x;
                                 }
                              } else {
                                 argumentns.clear();
                                 dataType = new SQLCharacterDataType("TEXT");
                              }
                           } else {
                              argumentns.clear();
                              dataType = new SQLDataTypeImpl("BYTEA");
                           }
                        } else if (argumentns.size() > 0) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           dataType = new SQLCharacterDataType("VARCHAR", len);
                        } else {
                           dataType = new SQLCharacterDataType("VARCHAR");
                        }
                     } else if (argumentns.size() > 0) {
                        SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                        int len;
                        if (arg0 instanceof SQLNumericLiteralExpr) {
                           len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                        } else {
                           if (!(arg0 instanceof SQLVariantRefExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           len = 2000;
                        }

                        if (len <= 4000) {
                           dataType = new SQLCharacterDataType("VARCHAR", len);
                        } else {
                           dataType = new SQLCharacterDataType("TEXT");
                        }
                     } else {
                        dataType = new SQLCharacterDataType("VARCHAR");
                     }
                  } else {
                     dataType = x.clone();
                     dataType.setName("DECIMAL");
                     int precision = 0;
                     if (argumentns.size() > 0) {
                        precision = ((SQLIntegerExpr)argumentns.get(0)).getNumber().intValue();
                     }

                     int scale = 0;
                     if (argumentns.size() > 1) {
                        scale = ((SQLIntegerExpr)argumentns.get(1)).getNumber().intValue();
                        if (precision < scale) {
                           ((SQLIntegerExpr)dataType.getArguments().get(1)).setNumber(precision);
                        }
                     }
                  }
               } else {
                  dataType = new SQLDataTypeImpl("DOUBLE PRECISION");
               }
            } else {
               dataType = new SQLDataTypeImpl("DECIMAL", 38);
            }
         } else {
            dataType = new SQLDataTypeImpl("SMALLINT");
         }

         if (dataType != x) {
            dataType.setParent(x.getParent());
         }

         return dataType;
      }
   }

   public static SQLExpr transformOracleToPostgresql(SQLMethodInvokeExpr x) {
      long nameHashCode64 = x.methodNameHashCode64();
      List<SQLExpr> parameters = x.getArguments();
      if (nameHashCode64 == FnvHash.Constants.SYS_GUID) {
         SQLMethodInvokeExpr uuid_generate_v4 = new SQLMethodInvokeExpr("uuid_generate_v4");
         uuid_generate_v4.setParent(x.getParent());
         return uuid_generate_v4;
      } else {
         if (nameHashCode64 == FnvHash.Constants.TRUNC && parameters.size() == 1) {
            SQLExpr param0 = (SQLExpr)parameters.get(0);
            if (param0 instanceof OracleSysdateExpr || param0 instanceof SQLIdentifierExpr && ((SQLIdentifierExpr)param0).nameHashCode64() == FnvHash.Constants.CURRENT_TIMESTAMP) {
               SQLMethodInvokeExpr current_timestamp = new SQLMethodInvokeExpr("CURRENT_TIMESTAMP");
               current_timestamp.addArgument(new SQLIntegerExpr(0));
               current_timestamp.setParent(x.getParent());
               return current_timestamp;
            }
         }

         if (nameHashCode64 == FnvHash.Constants.CURRENT_TIMESTAMP && parameters.size() == 0 && x.getParent() instanceof SQLColumnDefinition) {
            SQLDataType dataType = ((SQLColumnDefinition)x.getParent()).getDataType();
            if (dataType.nameHashCode64() == FnvHash.Constants.TIMESTAMP && dataType.getArguments().size() == 1) {
               x.addArgument(((SQLExpr)dataType.getArguments().get(0)).clone());
            } else {
               x.addArgument(new SQLIntegerExpr(0));
            }

            return x;
         } else if (nameHashCode64 == FnvHash.Constants.SYSTIMESTAMP) {
            SQLMethodInvokeExpr xx = x.clone();
            xx.setMethodName("SYSTIMESTAMP");
            xx.setParent(x.getParent());
            return xx;
         } else if (nameHashCode64 == FnvHash.Constants.LOCALTIMESTAMP) {
            SQLMethodInvokeExpr xx = x.clone();
            xx.setMethodName("LOCALTIMESTAMP");
            xx.setParent(x.getParent());
            return xx;
         } else {
            if (nameHashCode64 == FnvHash.Constants.USERENV && x.getArguments().size() == 1) {
               SQLExpr param0 = (SQLExpr)x.getArguments().get(0);
               if (param0 instanceof SQLCharExpr) {
                  String text = ((SQLCharExpr)param0).getText();
                  if ("SESSIONID".equalsIgnoreCase(text)) {
                     SQLMethodInvokeExpr xx = new SQLMethodInvokeExpr();
                     xx.setMethodName("get_session_id");
                     xx.setParent(x.getParent());
                     return xx;
                  }
               }
            }

            if (nameHashCode64 == FnvHash.Constants.USERENV && x.getArguments().size() == 1) {
               SQLExpr param0 = (SQLExpr)x.getArguments().get(0);
               if (param0 instanceof SQLCharExpr) {
                  String text = ((SQLCharExpr)param0).getText();
                  if ("SESSIONID".equalsIgnoreCase(text)) {
                     SQLMethodInvokeExpr xx = new SQLMethodInvokeExpr();
                     xx.setMethodName("get_session_id");
                     xx.setParent(x.getParent());
                     return xx;
                  }
               }
            }

            if (nameHashCode64 == FnvHash.Constants.NUMTODSINTERVAL && x.getArguments().size() == 2) {
               SQLExpr param0 = (SQLExpr)x.getArguments().get(0);
               SQLExpr param1 = (SQLExpr)x.getArguments().get(1);
               if (param0 instanceof SQLIntegerExpr && param1 instanceof SQLCharExpr) {
                  String text = ((SQLCharExpr)param1).getText();
                  if ("DAY".equalsIgnoreCase(text)) {
                     SQLIntervalExpr intervalExpr = new SQLIntervalExpr();
                     intervalExpr.setValue(new SQLCharExpr(param0.toString() + " DAYS"));
                     intervalExpr.setParent(x.getParent());
                     return intervalExpr;
                  }
               }
            }

            return x;
         }
      }
   }

   public static SQLTableSource transformOracleToPostgresql(SQLTableSource x) {
      if (x instanceof OracleSelectTableReference) {
         OracleSelectTableReference xx = (OracleSelectTableReference)x;
         SQLExprTableSource y = new SQLExprTableSource();
         xx.cloneTo(y);
         y.setParent(x.getParent());
         return y;
      } else if (x instanceof OracleSelectJoin) {
         OracleSelectJoin xx = (OracleSelectJoin)x;
         SQLJoinTableSource y = new SQLJoinTableSource();
         xx.cloneTo(y);
         y.setLeft(transformOracleToPostgresql(y.getLeft()));
         y.setRight(transformOracleToPostgresql(y.getRight()));
         y.setParent(x.getParent());
         return y;
      } else if (x instanceof OracleSelectSubqueryTableSource) {
         OracleSelectSubqueryTableSource xx = (OracleSelectSubqueryTableSource)x;
         SQLSubqueryTableSource y = new SQLSubqueryTableSource();
         xx.cloneTo(y);
         y.setParent(x.getParent());
         return y;
      } else if (x instanceof OracleWithSubqueryEntry) {
         SQLWithSubqueryClause.Entry entry = new SQLWithSubqueryClause.Entry();
         ((OracleWithSubqueryEntry)x).cloneTo(entry);
         entry.setParent(x.getParent());
         return entry;
      } else {
         return x;
      }
   }

   public static SQLSelectQueryBlock transformOracleToPostgresql(SQLSelectQueryBlock x) {
      if (x instanceof OracleSelectQueryBlock) {
         OracleSelectQueryBlock xx = (OracleSelectQueryBlock)x;
         SQLSelectQueryBlock y = new SQLSelectQueryBlock();
         xx.cloneTo(y);
         y.setFrom(transformOracleToPostgresql(y.getFrom()));
         y.setParent(x.getParent());
         return y;
      } else {
         return x;
      }
   }

   public static SQLDataType transformOracleToPPAS(SQLDataType x) {
      String name = x.getName();
      long nameHash = x.nameHashCode64();
      if (name == null) {
         return x;
      } else {
         List<SQLExpr> argumentns = x.getArguments();
         SQLDataType dataType;
         if (nameHash == FnvHash.Constants.UROWID) {
            int len = 4000;
            if (argumentns.size() == 1) {
               SQLExpr arg0 = (SQLExpr)argumentns.get(0);
               if (arg0 instanceof SQLIntegerExpr) {
                  len = ((SQLIntegerExpr)arg0).getNumber().intValue();
               }
            }

            dataType = new SQLDataTypeImpl("VARCHAR", len);
         } else if (nameHash == FnvHash.Constants.ROWID) {
            dataType = new SQLDataTypeImpl("CHAR", 10);
         } else if (nameHash != FnvHash.Constants.BOOLEAN && nameHash != FnvHash.Constants.SMALLINT) {
            if (nameHash != FnvHash.Constants.INTEGER && nameHash != FnvHash.Constants.INT) {
               if (nameHash == FnvHash.Constants.BINARY_FLOAT) {
                  dataType = new SQLDataTypeImpl("REAL");
               } else if (nameHash != FnvHash.Constants.BINARY_DOUBLE && nameHash != FnvHash.Constants.FLOAT && nameHash != FnvHash.Constants.DOUBLE && nameHash != FnvHash.Constants.REAL && nameHash != FnvHash.Constants.DOUBLE_PRECISION) {
                  if (nameHash == FnvHash.Constants.NUMBER) {
                     dataType = x.clone();
                     if (argumentns.size() > 0) {
                        SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                        if (arg0 instanceof SQLAllColumnExpr) {
                           SQLIntegerExpr precisionExpr = new SQLIntegerExpr(38);
                           dataType.getArguments().set(0, precisionExpr);
                        }
                     }
                  } else if (nameHash != FnvHash.Constants.DEC && nameHash != FnvHash.Constants.DECIMAL) {
                     if (nameHash == FnvHash.Constants.CHARACTER) {
                        if (argumentns.size() == 1) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           dataType = new SQLCharacterDataType("CHAR", len);
                        } else {
                           if (argumentns.size() != 0) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           dataType = new SQLCharacterDataType("CHAR");
                        }
                     } else if (nameHash == FnvHash.Constants.CHAR) {
                        if (argumentns.size() == 1) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           if (len <= 2000) {
                              dataType = x;
                              x.setName("CHAR");
                           } else {
                              dataType = new SQLCharacterDataType("TEXT");
                           }
                        } else {
                           if (argumentns.size() != 0) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           dataType = new SQLCharacterDataType("CHAR");
                        }
                     } else if (nameHash == FnvHash.Constants.NCHAR) {
                        dataType = x;
                        x.setName("NCHAR");
                     } else if (nameHash != FnvHash.Constants.VARCHAR && nameHash != FnvHash.Constants.VARCHAR2) {
                        if (nameHash != FnvHash.Constants.NVARCHAR && nameHash != FnvHash.Constants.NVARCHAR2 && nameHash != FnvHash.Constants.NCHAR_VARYING) {
                           if (nameHash == FnvHash.Constants.BFILE) {
                              dataType = new SQLCharacterDataType("VARCHAR", 255);
                           } else if (nameHash == FnvHash.Constants.DATE) {
                              dataType = new SQLDataTypeImpl("TIMESTAMP", 0);
                           } else if (nameHash == FnvHash.Constants.TIMESTAMP) {
                              x.setName("TIMESTAMP");
                              if (x.isWithLocalTimeZone()) {
                                 x.setWithLocalTimeZone(false);
                                 x.setWithTimeZone((Boolean)null);
                              }

                              dataType = x;
                           } else if (nameHash == FnvHash.Constants.DATETIME) {
                              int len = -1;
                              if (argumentns.size() > 0) {
                                 SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                                 if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                                    throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                                 }

                                 len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                              }

                              if (len > 0) {
                                 dataType = new SQLDataTypeImpl("TIMESTAMP", len);
                              } else {
                                 dataType = new SQLDataTypeImpl("TIMESTAMP");
                              }
                           } else if (nameHash != FnvHash.Constants.BLOB && nameHash != FnvHash.Constants.LONG_RAW && nameHash != FnvHash.Constants.RAW) {
                              if (nameHash != FnvHash.Constants.CLOB && nameHash != FnvHash.Constants.NCLOB && nameHash != FnvHash.Constants.LONG) {
                                 if (nameHash == FnvHash.Constants.XMLTYPE) {
                                    dataType = new SQLDataTypeImpl("XML");
                                 } else {
                                    dataType = x;
                                 }
                              } else {
                                 argumentns.clear();
                                 dataType = new SQLCharacterDataType("TEXT");
                              }
                           } else {
                              argumentns.clear();
                              dataType = new SQLDataTypeImpl("BYTEA");
                           }
                        } else if (argumentns.size() > 0) {
                           SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                           if (!(arg0 instanceof SQLNumericLiteralExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           int len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                           dataType = new SQLCharacterDataType("VARCHAR", len);
                        } else {
                           dataType = new SQLCharacterDataType("VARCHAR");
                        }
                     } else if (argumentns.size() > 0) {
                        SQLExpr arg0 = (SQLExpr)argumentns.get(0);
                        int len;
                        if (arg0 instanceof SQLNumericLiteralExpr) {
                           len = ((SQLNumericLiteralExpr)arg0).getNumber().intValue();
                        } else {
                           if (!(arg0 instanceof SQLVariantRefExpr)) {
                              throw new UnsupportedOperationException(SQLUtils.toOracleString(x));
                           }

                           len = 2000;
                        }

                        if (len <= 4000) {
                           dataType = new SQLCharacterDataType("VARCHAR", len);
                        } else {
                           dataType = new SQLCharacterDataType("TEXT");
                        }
                     } else {
                        dataType = new SQLCharacterDataType("VARCHAR");
                     }
                  } else {
                     dataType = x.clone();
                     dataType.setName("DECIMAL");
                     int precision = 0;
                     if (argumentns.size() > 0) {
                        precision = ((SQLIntegerExpr)argumentns.get(0)).getNumber().intValue();
                     }

                     int scale = 0;
                     if (argumentns.size() > 1) {
                        scale = ((SQLIntegerExpr)argumentns.get(1)).getNumber().intValue();
                        if (precision < scale) {
                           ((SQLIntegerExpr)dataType.getArguments().get(1)).setNumber(precision);
                        }
                     }
                  }
               } else {
                  dataType = new SQLDataTypeImpl("DOUBLE PRECISION");
               }
            } else {
               dataType = new SQLDataTypeImpl("DECIMAL", 38);
            }
         } else {
            dataType = new SQLDataTypeImpl("SMALLINT");
         }

         if (dataType != x) {
            dataType.setParent(x.getParent());
         }

         return dataType;
      }
   }
}
