DerbyQueryObject.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.utils.sql;

  21. import java.text.SimpleDateFormat;
  22. import java.util.Date;
  23. import java.util.Iterator;

  24. import org.openspcoop2.utils.TipiDatabase;
  25. import org.openspcoop2.utils.date.DateUtils;

  26. /**
  27.  * Implementazione per HyperSQL
  28.  *
  29.  * @author Poli Andrea (apoli@link.it)
  30.  * @author $Author$
  31.  * @version $Rev$, $Date$
  32.  */
  33. public class DerbyQueryObject extends SQLQueryObjectCore {

  34.     public DerbyQueryObject(TipiDatabase tipoDatabase) {
  35.         super(tipoDatabase);
  36.     }

  37.    
  38.     /**
  39.      * Ritorna una costante  di tipo 'timestamp'
  40.      *
  41.      * @param date Costante
  42.      */
  43.     @Override
  44.     public String getSelectTimestampConstantField(Date date) throws SQLQueryObjectException{
  45.         SimpleDateFormat sqlDateformat = DateUtils.getDefaultDateTimeFormatter("yyyy-MM-dd HH:mm:ss.SSS");
  46.         return "CAST('"+sqlDateformat.format(date)+"' AS TIMESTAMP)";
  47.     }
  48.    
  49.    
  50.    
  51.     @Override
  52.     public String getUnixTimestampConversion(String column){
  53.         /**return "((datediff('ss',CAST('1970-01-01 00:00:00' AS TIMESTAMP),"+column+")-3600)*1000)";*/
  54.         return "( "+
  55.                 "("+
  56.                 "(UNIX_TIMESTAMP("+column+")*1000) - "+
  57.                 "((EXTRACT(HOUR FROM TIMEZONE()))*60*60*1000)" +
  58.                 ") + "+
  59.                 "(CAST(CHAR ("+column+") AS INTEGER))" +
  60.                 ")"
  61.                 ;
  62.     }
  63.    
  64.     @Override
  65.     public String getDiffUnixTimestamp(String columnMax,String columnMin){
  66.         return "( "+getUnixTimestampConversion(columnMax)+" - "+getUnixTimestampConversion(columnMin)+" )";
  67.     }
  68.    
  69.    
  70.    
  71.     @Override
  72.     public ISQLQueryObject addSelectAvgTimestampField(String field, String alias)
  73.             throws SQLQueryObjectException {
  74.         if(field==null)
  75.             throw new SQLQueryObjectException(SQLQueryObjectCore.FIELD_DEVE_ESSERE_DIVERSO_NULL);
  76.         // Trasformo in UNIX_TIMESTAMP
  77.         String fieldSQL = "avg("+this.getUnixTimestampConversion(field)+")";
  78.         if(alias != null){
  79.             /** fieldSQL = fieldSQL + " as "+alias;*/
  80.             fieldSQL = fieldSQL +this.getDefaultAliasFieldKeyword()+alias;
  81.         }
  82.         this.engineAddSelectField(null,fieldSQL,null,false,true);
  83.         this.fieldNames.add(alias);
  84.         return this;
  85.     }

  86.     @Override
  87.     public ISQLQueryObject addSelectMaxTimestampField(String field, String alias)
  88.             throws SQLQueryObjectException {
  89.         if(field==null)
  90.             throw new SQLQueryObjectException(SQLQueryObjectCore.FIELD_DEVE_ESSERE_DIVERSO_NULL);
  91.         // Trasformo in UNIX_TIMESTAMP
  92.         String fieldSQL = "max("+this.getUnixTimestampConversion(field)+")";
  93.         if(alias != null){
  94.             /**fieldSQL = fieldSQL + " as "+alias;*/
  95.             fieldSQL = fieldSQL +this.getDefaultAliasFieldKeyword()+alias;
  96.         }
  97.         this.engineAddSelectField(null,fieldSQL,null,false,true);
  98.         this.fieldNames.add(alias);
  99.         return this;
  100.     }

  101.     @Override
  102.     public ISQLQueryObject addSelectMinTimestampField(String field, String alias)
  103.             throws SQLQueryObjectException {
  104.         if(field==null)
  105.             throw new SQLQueryObjectException(SQLQueryObjectCore.FIELD_DEVE_ESSERE_DIVERSO_NULL);
  106.         // Trasformo in UNIX_TIMESTAMP
  107.         String fieldSQL = "min("+this.getUnixTimestampConversion(field)+")";
  108.         if(alias != null){
  109.             /**fieldSQL = fieldSQL + " as "+alias;*/
  110.             fieldSQL = fieldSQL +this.getDefaultAliasFieldKeyword()+alias;
  111.         }
  112.         this.engineAddSelectField(null,fieldSQL,null,false,true);
  113.         this.fieldNames.add(alias);
  114.         return this;
  115.     }

  116.     @Override
  117.     public ISQLQueryObject addSelectSumTimestampField(String field, String alias)
  118.             throws SQLQueryObjectException {
  119.         if(field==null)
  120.             throw new SQLQueryObjectException(SQLQueryObjectCore.FIELD_DEVE_ESSERE_DIVERSO_NULL);
  121.         // Trasformo in UNIX_TIMESTAMP
  122.         String fieldSQL = "sum("+this.getUnixTimestampConversion(field)+")";
  123.         if(alias != null){
  124.             /**fieldSQL = fieldSQL + " as "+alias;*/
  125.             fieldSQL = fieldSQL +this.getDefaultAliasFieldKeyword()+alias;
  126.         }
  127.         this.engineAddSelectField(null,fieldSQL,null,false,true);
  128.         this.fieldNames.add(alias);
  129.         return this;
  130.     }
  131.    
  132.    
  133.    
  134.    
  135.    
  136.    
  137.     @Override
  138.     public ISQLQueryObject addFromTable(ISQLQueryObject subSelect)
  139.             throws SQLQueryObjectException {
  140.         StringBuilder bf = new StringBuilder();
  141.         bf.append(" ( ");
  142.         bf.append(subSelect.createSQLQuery());
  143.         bf.append(" ) ");
  144.         this.addFromTable(bf.toString());
  145.         return this;
  146.     }
  147.    
  148.    
  149.    
  150.    
  151.     @Override
  152.     protected EscapeSQLConfiguration getEscapeSQLConfiguration(){
  153.        
  154.         EscapeSQLConfiguration config = new EscapeSQLConfiguration();
  155.         config.addCharacter('_');
  156.         config.addCharacter('%');
  157.         config.addCharacter('\\');
  158.         config.setUseEscapeClausole(true);
  159.         config.setEscape('\\');
  160.        
  161.         // special
  162.         config.addCharacterWithOtherEscapeChar('\'','\'');
  163.        
  164.         return config;
  165.     }
  166.    
  167.    
  168.    
  169.    
  170.    
  171.    
  172.    
  173.    
  174.    
  175.    
  176.     private SQLQueryObjectException newSQLQueryObjectExceptionDayFormatEnum(DayFormatEnum dayFormat) {
  177.         return new SQLQueryObjectException("DayFormatEnum '"+dayFormat+"' unknown");
  178.     }
  179.     @Override
  180.     public String getExtractDayFormatFromTimestampFieldPrefix(DayFormatEnum dayFormat) throws SQLQueryObjectException {
  181.         if(dayFormat==null) {
  182.             throw new SQLQueryObjectException("dayFormat undefined");
  183.         }
  184.         switch (dayFormat) {
  185.         case FULL_DAY_NAME:
  186.             return "DAYNAME(";
  187.         case SHORT_DAY_NAME:
  188.             return "DATE_FORMAT(";
  189.         case DAY_OF_YEAR:
  190.             return "DAYOFYEAR(";
  191.         case DAY_OF_WEEK:
  192.             return "DAYOFWEEK(";
  193.         }
  194.         throw newSQLQueryObjectExceptionDayFormatEnum(dayFormat);
  195.     }
  196.     @Override
  197.     public String getExtractDayFormatFromTimestampFieldSuffix(DayFormatEnum dayFormat) throws SQLQueryObjectException {
  198.         if(dayFormat==null) {
  199.             throw new SQLQueryObjectException("dayFormat undefined");
  200.         }
  201.         switch (dayFormat) {
  202.         case SHORT_DAY_NAME:
  203.             return ", '%a')";
  204.         case FULL_DAY_NAME:
  205.         case DAY_OF_YEAR:
  206.         case DAY_OF_WEEK:
  207.             return ")";
  208.         }
  209.         throw newSQLQueryObjectExceptionDayFormatEnum(dayFormat);
  210.     }
  211.    
  212.    
  213.    
  214.    
  215.    
  216.    
  217.    
  218.     @Override
  219.     public String createSQLQuery() throws SQLQueryObjectException{
  220.         return this.createSQLQuery(false);
  221.     }
  222.     private String createSQLQuery(boolean union) throws SQLQueryObjectException{
  223.        
  224.         this.precheckBuildQuery();
  225.        
  226.         StringBuilder bf = new StringBuilder();
  227.        
  228.         bf.append("SELECT ");
  229.        
  230.         // forzatura di indici
  231.         Iterator<String> itForceIndex = this.forceIndexTableNames.iterator();
  232.         while(itForceIndex.hasNext()){
  233.             bf.append(" "+itForceIndex.next()+" ");
  234.         }
  235.        
  236.         if(this.isSelectDistinct())
  237.             bf.append(" DISTINCT ");
  238.        
  239.         // select field
  240.         if(this.fields.isEmpty()){
  241.             bf.append("*");
  242.         }else{
  243.             Iterator<String> it = this.fields.iterator();
  244.             boolean first = true;
  245.             while(it.hasNext()){
  246.                 if(!first)
  247.                     bf.append(",");
  248.                 else
  249.                     first = false;
  250.                 bf.append(it.next());
  251.             }
  252.         }
  253.        
  254.         bf.append(getSQL(false,false,false,union));
  255.        
  256.         /**if( this.offset>=0 || this.limit>=0)
  257.         //  System.out.println("SQL ["+bf.toString()+"]");*/
  258.        
  259.         return bf.toString();
  260.     }

  261.    
  262.    
  263.    
  264.     @Override
  265.     public String createSQLDeleteEngine() throws SQLQueryObjectException {
  266.         StringBuilder bf = new StringBuilder();
  267.                
  268.         bf.append("DELETE ");
  269.        
  270.         bf.append(getSQL(true,false,false,false));
  271.         return bf.toString();
  272.     }
  273.    
  274.    
  275.    
  276.    

  277.    
  278.     /**
  279.      * @return SQL
  280.      * @throws SQLQueryObjectException
  281.      */
  282.     private String getSQL(boolean delete,boolean update,boolean conditions,boolean union) throws SQLQueryObjectException {
  283.         StringBuilder bf = new StringBuilder();

  284.         if(this.selectForUpdate){
  285.             this.checkSelectForUpdate(update, delete, union);
  286.         }
  287.        
  288.         if(!update && !conditions){
  289.             // From
  290.             bf.append(SQLQueryObjectCore.FROM_SEPARATOR);
  291.            
  292.             // Table dove effettuare la ricerca 'FromTable'
  293.             if(this.tables.isEmpty()){
  294.                 throw new SQLQueryObjectException(SQLQueryObjectCore.TABELLA_RICERCA_FROM_NON_DEFINITA);
  295.             }else{
  296.                 if(delete && this.tables.size()>2)
  297.                     throw new SQLQueryObjectException("Non e' possibile effettuare una delete con piu' di una tabella alla volta");
  298.                 Iterator<String> it = this.tables.iterator();
  299.                 boolean first = true;
  300.                 while(it.hasNext()){
  301.                     if(!first)
  302.                         bf.append(",");
  303.                     else
  304.                         first = false;
  305.                     bf.append(it.next());
  306.                 }
  307.             }
  308.         }
  309.        
  310.         // Condizioni di Where
  311.         if(!this.conditions.isEmpty()){
  312.            
  313.             if(!conditions)
  314.                 bf.append(SQLQueryObjectCore.WHERE_SEPARATOR);
  315.            
  316.             if(this.notBeforeConditions){
  317.                 bf.append("NOT (");
  318.             }
  319.            
  320.             for(int i=0; i<this.conditions.size(); i++){
  321.                 if(i>0){
  322.                     if(this.andLogicOperator){
  323.                         bf.append(SQLQueryObjectCore.AND_SEPARATOR);
  324.                     }else{
  325.                         bf.append(SQLQueryObjectCore.OR_SEPARATOR);
  326.                     }
  327.                 }
  328.                 bf.append(this.conditions.get(i));
  329.             }
  330.            
  331.             if(this.notBeforeConditions){
  332.                 bf.append(")");
  333.             }
  334.         }
  335.        
  336.         // Condizione GroupBy
  337.         if((!this.getGroupByConditions().isEmpty()) && (!delete) && (!update) && (!conditions)){
  338.             bf.append(SQLQueryObjectCore.GROUP_BY_SEPARATOR);
  339.             Iterator<String> it = this.getGroupByConditions().iterator();
  340.             boolean first = true;
  341.             while(it.hasNext()){
  342.                 if(!first)
  343.                     bf.append(",");
  344.                 else
  345.                     first = false;
  346.                 bf.append(it.next());
  347.             }
  348.         }
  349.        
  350.         // Condizione OrderBy
  351. /**     if(union==false){ La condizione di OrderBy DEVE essere generata. In SQLServer e MySQL viene generata durante la condizione di LIMIT/OFFSET*/
  352.         // NOTA: L'order by insieme al LIMIT e OFFSET, all'interno di sotto-select come in questo caso della union, funziona solo con HSQL 2.x
  353.             if((!this.orderBy.isEmpty()) && (!delete) && (!update) && (!conditions) ){
  354.                 bf.append(SQLQueryObjectCore.ORDER_BY_SEPARATOR);
  355.                 Iterator<String> it = this.orderBy.iterator();
  356.                 boolean first = true;
  357.                 while(it.hasNext()){
  358.                     String column = it.next();
  359.                     if(!first)
  360.                         bf.append(",");
  361.                     else
  362.                         first = false;
  363.                     bf.append(column);
  364.                     boolean sortTypeAsc = this.sortTypeAsc;
  365.                     if(this.orderBySortType.containsKey(column)){
  366.                         sortTypeAsc = this.orderBySortType.get(column);
  367.                     }
  368.                     if(sortTypeAsc){
  369.                         bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  370.                     }else{
  371.                         bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  372.                     }
  373.                 }
  374.             }
  375. /**     }*/

  376.            
  377.         // Limit e Offset
  378.         /**if(this.limit>0 || this.offset>0){*/
  379.         // Rilascio vincolo di order by in caso di limit impostato.
  380.         // Il vincolo rimane per l'offset, per gestire le select annidate di qualche implementazioni come Oracle,SQLServer ...
  381.         if(this.offset>=0 &&
  382.             (this.orderBy.isEmpty())
  383.             ){
  384.             throw new SQLQueryObjectException(SQLQueryObjectCore.CONDIZIONI_ORDER_BY_RICHESTE);
  385.         }
  386.        
  387.        
  388.         // Offset
  389.         if((this.offset>=0) && (!delete) && (!update) && (!conditions)){
  390.             bf.append(" OFFSET ");
  391.             bf.append(this.offset);
  392.             bf.append(" ROWS ");
  393.         }
  394.        
  395.         // Limit (con offset)
  396.         if((this.limit>0) && (!delete) && (!update) && (!conditions)){
  397.             bf.append(" FETCH NEXT ");
  398.             bf.append(this.limit);
  399.             bf.append(" ROWS ONLY ");
  400.         }
  401.        
  402.         // ForUpdate
  403.         if(!conditions &&
  404.             (this.selectForUpdate)
  405.             ){
  406.             bf.append(" FOR UPDATE ");
  407.         }
  408.        
  409.         return bf.toString();
  410.     }
  411.    
  412.    
  413.    
  414.     @Override
  415.     public String createSQLUnion(boolean unionAll,
  416.             ISQLQueryObject... sqlQueryObject) throws SQLQueryObjectException {
  417.        
  418.         // Controllo parametro su cui effettuare la UNION
  419.         this.checkUnionField(false,sqlQueryObject);
  420.        
  421.         if(this.selectForUpdate){
  422.             this.checkSelectForUpdate(false, false, true);
  423.         }
  424.        
  425.         StringBuilder bf = new StringBuilder();
  426.        
  427.         bf.append("SELECT ");
  428.        
  429.         // Non ha senso, la union fa gia la distinct, a meno di usare la unionAll ma in quel caso non si vuole la distinct
  430.         /** if(this.isSelectDistinct())
  431.         //  bf.append(" DISTINCT ");*/
  432.        
  433.         // forzatura di indici
  434.         Iterator<String> itForceIndex = this.forceIndexTableNames.iterator();
  435.         while(itForceIndex.hasNext()){
  436.             bf.append(" "+itForceIndex.next()+" ");
  437.         }
  438.                
  439.         // select field
  440.         if(this.fields.isEmpty()){
  441.             bf.append("*");
  442.         }else{
  443.             Iterator<String> it = this.fields.iterator();
  444.             boolean first = true;
  445.             while(it.hasNext()){
  446.                 if(!first)
  447.                     bf.append(",");
  448.                 else
  449.                     first = false;
  450.                 bf.append(it.next());
  451.             }
  452.         }
  453.        
  454.         bf.append(SQLQueryObjectCore.FROM_SEPARATOR_APERTURA);
  455.        
  456.         for(int i=0; i<sqlQueryObject.length; i++){
  457.            
  458.             if(((DerbyQueryObject)sqlQueryObject[i]).selectForUpdate){
  459.                 try{
  460.                     ((DerbyQueryObject)sqlQueryObject[i]).checkSelectForUpdate(false, false, true);
  461.                 }catch(Exception e){
  462.                     throw new SQLQueryObjectException("Parametro SqlQueryObject["+i+"] non valido: "+e.getMessage());
  463.                 }
  464.             }
  465.            
  466.             if(i>0){
  467.                 bf.append(" UNION ");
  468.                 if(unionAll){
  469.                     bf.append(" ALL ");
  470.                 }
  471.             }
  472.            
  473.             bf.append("( ");
  474.            
  475.             bf.append(((DerbyQueryObject)sqlQueryObject[i]).createSQLQuery(true));
  476.            
  477.             bf.append(") ");
  478.         }
  479.        
  480.         bf.append(SQLQueryObjectCore.AS_SUBQUERY_SUFFIX+getSerial()+" ");
  481.        
  482.         // Condizione GroupBy
  483.         if((!this.getGroupByConditions().isEmpty()) ){
  484.             bf.append(SQLQueryObjectCore.GROUP_BY_SEPARATOR);
  485.             Iterator<String> it = this.getGroupByConditions().iterator();
  486.             boolean first = true;
  487.             while(it.hasNext()){
  488.                 if(!first)
  489.                     bf.append(",");
  490.                 else
  491.                     first = false;
  492.                 bf.append(it.next());
  493.             }
  494.         }
  495.        
  496.         // Condizione OrderBy
  497.         if(!this.orderBy.isEmpty()){
  498.             bf.append(SQLQueryObjectCore.ORDER_BY_SEPARATOR);
  499.             Iterator<String> it = this.orderBy.iterator();
  500.             boolean first = true;
  501.             while(it.hasNext()){
  502.                 String column = it.next();
  503.                 if(!first)
  504.                     bf.append(",");
  505.                 else
  506.                     first = false;
  507.                 bf.append(column);
  508.                 boolean sortTypeAsc = this.sortTypeAsc;
  509.                 if(this.orderBySortType.containsKey(column)){
  510.                     sortTypeAsc = this.orderBySortType.get(column);
  511.                 }
  512.                 if(sortTypeAsc){
  513.                     bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  514.                 }else{
  515.                     bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  516.                 }
  517.             }
  518.         }
  519.        
  520.         // Limit e Offset
  521.         /**if(this.limit>0 || this.offset>0){*/
  522.         // Rilascio vincolo di order by in caso di limit impostato.
  523.         // Il vincolo rimane per l'offset, per gestire le select annidate di qualche implementazioni come Oracle,SQLServer ...
  524.         if(this.offset>=0 &&
  525.             (this.orderBy.isEmpty())
  526.             ){
  527.             throw new SQLQueryObjectException(SQLQueryObjectCore.CONDIZIONI_ORDER_BY_RICHESTE);
  528.         }
  529.        
  530.         // Offset
  531.         if(this.offset>=0){
  532.             bf.append(" OFFSET ");
  533.             bf.append(this.offset);
  534.             bf.append(" ROWS ");
  535.         }
  536.        
  537.         // Limit
  538.         if(this.limit>0){
  539.             bf.append(" FETCH NEXT ");
  540.             bf.append(this.limit);
  541.             bf.append(" ROWS ONLY ");
  542.         }
  543.        
  544.         return bf.toString();
  545.        
  546.     }

  547.     @Override
  548.     public String createSQLUnionCount(boolean unionAll, String aliasCount,
  549.             ISQLQueryObject... sqlQueryObject) throws SQLQueryObjectException {
  550.         // Controllo parametro su cui effettuare la UNION
  551.         this.checkUnionField(true,sqlQueryObject);
  552.        
  553.         if(aliasCount==null){
  554.             throw new SQLQueryObjectException("Alias per il count non definito");
  555.         }
  556.        
  557.         StringBuilder bf = new StringBuilder();
  558.        
  559.         bf.append("SELECT count(*) "+this.getDefaultAliasFieldKeyword()+" ");
  560.         bf.append(aliasCount);
  561.         bf.append(SQLQueryObjectCore.FROM_SEPARATOR_APERTURA);
  562.        
  563.         bf.append( this.createSQLUnion(unionAll, sqlQueryObject) );
  564.        
  565.         bf.append(SQLQueryObjectCore.AS_SUBQUERY_SUFFIX+getSerial()+" ");
  566.            
  567.         return bf.toString();
  568.     }
  569.    
  570.    
  571.    

  572.     @Override
  573.     public String createSQLUpdateEngine() throws SQLQueryObjectException {

  574.         StringBuilder bf = new StringBuilder();
  575.         bf.append("UPDATE ");
  576.         bf.append(this.updateTable);
  577.         bf.append(" SET ");
  578.         for(int i=0; i<this.updateFieldsName.size(); i++){
  579.             if(i>0)
  580.                 bf.append(" , ");
  581.             bf.append(this.updateFieldsName.get(i));
  582.             bf.append(" = ");
  583.             bf.append(this.updateFieldsValue.get(i));
  584.         }
  585.         bf.append(getSQL(false,true,false,false));
  586.         return bf.toString();
  587.     }

  588.    

  589.    
  590.    
  591.     /* ---------------- WHERE CONDITIONS ------------------ */
  592.    
  593.     @Override
  594.     public String createSQLConditionsEngine() throws SQLQueryObjectException {
  595.        
  596.         StringBuilder bf = new StringBuilder();
  597.         bf.append(getSQL(false,false,true,false));
  598.         return bf.toString();
  599.     }

  600.    

  601.    
  602.    
  603.    
  604.    
  605.    

  606. }