SQLServerQueryObject.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.  * SQLServerQueryObject
  28.  *
  29.  *
  30.  * @author Poli Andrea (apoli@link.it)
  31.  * @author $Author$
  32.  * @version $Rev$, $Date$
  33.  */
  34. public class SQLServerQueryObject extends SQLQueryObjectCore {
  35.     /**private boolean sottoselect = false;*/


  36.     public SQLServerQueryObject(TipiDatabase tipoDatabase) {
  37.         super(tipoDatabase);
  38.     }


  39.    
  40.     @Override
  41.     protected boolean continueNormalizeField(String normalizeField){
  42.        
  43.         // Alcuni valori sono standard dei vendor dei database (es. gestione delle date)
  44.         // Il problema รจ che se contengono dei '.' o dei caratteri alias rientrano erroneamnete nei punti 2 e 3 della normalizzazione
  45.         // Per questo motivo viene quindi prima richiesto al vendor se effettuare o meno la classica normalizzazione del field in base a tali valori
  46.         // sul field in essere
  47.        
  48.         boolean contains = (normalizeField!=null &&
  49.                 // Con differenza su timezone:
  50. //              normalizeField.contains("(CAST(DATEDIFF(second,{d '1970-01-01'}")
  51. //              &&
  52. //              normalizeField.contains("as BIGINT)*1000) + (DATEPART(ms")
  53. //              &&
  54. //              normalizeField.contains("(CAST(DATEDIFF(HOUR,GETUTCDATE(),convert(datetime")
  55.                
  56.                 // senza differenza su timezone:
  57. //              normalizeField.contains("(CAST(DATEDIFF(second,{d '1970-01-01'}")
  58. //              &&
  59. //              normalizeField.contains("as BIGINT)*1000) + (DATEPART(ms")
  60.                
  61.                 // altro modo
  62.                 normalizeField.contains("(CAST(DATEDIFF(s, '1970-01-01 00:00:00',")
  63.                 &&
  64.                 normalizeField.contains("as BIGINT)*1000) + (DATEPART(ms")
  65.                
  66.                 );
  67.        
  68.         return !contains;
  69.        
  70.     }
  71.    
  72.    
  73.    
  74.    
  75.     /**
  76.      * Ritorna una costante  di tipo 'timestamp'
  77.      *
  78.      * @param date Costante
  79.      */
  80.     @Override
  81.     public String getSelectTimestampConstantField(Date date) throws SQLQueryObjectException{
  82.         SimpleDateFormat sqlDateformat = DateUtils.getDefaultDateTimeFormatter("yyyy-MM-dd HH:mm:ss.SSS");
  83.         return "CAST('"+sqlDateformat.format(date)+"' AS datetime2)";
  84.     }
  85.    
  86.    
  87.    
  88.    
  89.     @Override
  90.     public String getUnixTimestampConversion(String column){
  91.         // Con differenza su timezone:
  92. /**     String format = "yyyy-MM-dd HH:mm:ss";
  93. //      java.text.SimpleDateFormat dateformat = new java.text.SimpleDateFormat (format);
  94. //      return "("+
  95. //      " (CAST(DATEDIFF(second,{d '1970-01-01'},"+column+") as BIGINT)*1000) + (DATEPART(ms,"+column+"))"+
  96. //      " - "+
  97. //      " (CAST(DATEDIFF(HOUR,GETUTCDATE(),convert(datetime, '"+dateformat.format(org.openspcoop2.utils.date.DateManager.getDate())+"', 120)) as BIGINT)*60*60*1000) "+
  98. //      ")";*/
  99.        
  100.         // senza differenza su timezone:
  101. /**     return " (CAST(DATEDIFF(second,{d '1970-01-01'},"+column+") as BIGINT)*1000) + (DATEPART(ms,"+column+"))";*/
  102.        
  103.         // altro modo
  104.         return "(CAST(DATEDIFF(s, '1970-01-01 00:00:00', "+column+") as BIGINT)*1000) + (DATEPART(ms,"+column+"))";
  105.     }

  106.     @Override
  107.     public String getDiffUnixTimestamp(String columnMax,String columnMin){
  108.         return "( "+getUnixTimestampConversion(columnMax)+" - "+getUnixTimestampConversion(columnMin)+" )";
  109.     }





  110.     @Override
  111.     public ISQLQueryObject addSelectAvgTimestampField(String field,
  112.             String alias) throws SQLQueryObjectException {
  113.         if(field==null)
  114.             throw new SQLQueryObjectException(SQLQueryObjectCore.FIELD_DEVE_ESSERE_DIVERSO_NULL);
  115.         // Trasformo in UNIX_TIMESTAMP
  116.         String fieldSQL = "avg("+this.getUnixTimestampConversion(field)+")";
  117.         if(alias != null){
  118.             /**fieldSQL = fieldSQL + " as "+alias;*/
  119.             fieldSQL = fieldSQL + this.getDefaultAliasFieldKeyword() + alias;
  120.         }
  121.         this.engineAddSelectField(null,fieldSQL,null,false,true);
  122.         this.fieldNames.add(alias);
  123.         return this;
  124.     }


  125.     @Override
  126.     public ISQLQueryObject addSelectMaxTimestampField(String field, String alias)
  127.             throws SQLQueryObjectException {
  128.         if(field==null)
  129.             throw new SQLQueryObjectException(SQLQueryObjectCore.FIELD_DEVE_ESSERE_DIVERSO_NULL);
  130.         // Trasformo in UNIX_TIMESTAMP
  131.         String fieldSQL = "max("+this.getUnixTimestampConversion(field)+")";
  132.         if(alias != null){
  133.             /**fieldSQL = fieldSQL + " as "+alias;*/
  134.             fieldSQL = fieldSQL + this.getDefaultAliasFieldKeyword() + alias;
  135.         }
  136.         this.engineAddSelectField(null,fieldSQL,null,false,true);
  137.         this.fieldNames.add(alias);
  138.         return this;
  139.     }


  140.     @Override
  141.     public ISQLQueryObject addSelectMinTimestampField(String field, String alias)
  142.             throws SQLQueryObjectException {
  143.         if(field==null)
  144.             throw new SQLQueryObjectException(SQLQueryObjectCore.FIELD_DEVE_ESSERE_DIVERSO_NULL);
  145.         // Trasformo in UNIX_TIMESTAMP
  146.         String fieldSQL = "min("+this.getUnixTimestampConversion(field)+")";
  147.         if(alias != null){
  148.             /**fieldSQL = fieldSQL + " as "+alias;*/
  149.             fieldSQL = fieldSQL + this.getDefaultAliasFieldKeyword() + alias;
  150.         }
  151.         this.engineAddSelectField(null,fieldSQL,null,false,true);
  152.         this.fieldNames.add(alias);
  153.         return this;
  154.     }


  155.     @Override
  156.     public ISQLQueryObject addSelectSumTimestampField(String field, String alias)
  157.             throws SQLQueryObjectException {
  158.         if(field==null)
  159.             throw new SQLQueryObjectException(SQLQueryObjectCore.FIELD_DEVE_ESSERE_DIVERSO_NULL);
  160.         // Trasformo in UNIX_TIMESTAMP
  161.         String fieldSQL = "sum("+this.getUnixTimestampConversion(field)+")";
  162.         if(alias != null){
  163.             /**fieldSQL = fieldSQL + " as "+alias;*/
  164.             fieldSQL = fieldSQL + this.getDefaultAliasFieldKeyword() + alias;
  165.         }
  166.         this.engineAddSelectField(null,fieldSQL,null,false,true);
  167.         this.fieldNames.add(alias);
  168.         return this;
  169.     }





  170.     @Override
  171.     public ISQLQueryObject addFromTable(ISQLQueryObject subSelect)
  172.             throws SQLQueryObjectException {
  173.         StringBuilder bf = new StringBuilder();
  174.         bf.append(" ( ");
  175.         bf.append(subSelect.createSQLQuery());
  176.         bf.append(" ) ");
  177.         // Devo forzare l'utilizzo di un alias su una sottoselct dentro il FROM
  178.         // Genero Tre caratteri alafabetici casuali per dare un alias del tipo "tabellaXXX"
  179.         StringBuilder subselectalias = new StringBuilder();
  180.         subselectalias.append("tabella");
  181.         int rnd;
  182.         char base;
  183.         for (int count=0 ; count < 3; count++ ){
  184.             rnd = (SQLQueryObjectCore.getRandom().nextInt(52) );
  185.             base = (rnd < 26) ? 'A' : 'a';
  186.             subselectalias.append((char) (base + rnd % 26));            
  187.         }
  188.         this.addFromTable(bf.toString(),subselectalias.toString());
  189.         return this;
  190.     }




  191.     @Override
  192.     protected EscapeSQLConfiguration getEscapeSQLConfiguration(){
  193.        
  194.         EscapeSQLConfiguration config = new EscapeSQLConfiguration();
  195.         config.addCharacter('_');
  196.         config.addCharacter('%');
  197.         config.addCharacter('\\');
  198.         config.addCharacter('[');
  199.         config.addCharacter(']');
  200.         config.addCharacter('^');
  201.         config.setUseEscapeClausole(true);
  202.         config.setEscape('\\');
  203.        
  204.         // special
  205.         config.addCharacterWithOtherEscapeChar('\'','\'');

  206.         return config;
  207.     }



  208.    
  209.    
  210.    
  211.     @Override
  212.     public String getExtractDateTimePartFromTimestampFieldPrefix(DateTimePartEnum dateTimePart) throws SQLQueryObjectException {
  213.         if(dateTimePart==null) {
  214.             throw new SQLQueryObjectException("dateTimePart undefined");
  215.         }
  216.         String dateTimePartString = getDateTimePart(dateTimePart);
  217.         return "DATEPART("+dateTimePartString+FROM_SEPARATOR;
  218.     }

  219.    
  220.    
  221.    
  222.    
  223.     private static final String DAY_FORMAT_FULL_DAY_NAME = "dddd";
  224.     private static final String DAY_FORMAT_SHORT_DAY_NAME = "ddd";
  225.     private static final String DAY_FORMAT_DAY_OF_YEAR = "dy";
  226.     private static final String DAY_FORMAT_DAY_OF_WEEK = "WEEKDAY";
  227.    
  228.     private SQLQueryObjectException newSQLQueryObjectExceptionDayFormatEnum(DayFormatEnum dayFormat) {
  229.         return new SQLQueryObjectException("DayFormatEnum '"+dayFormat+"' unknown");
  230.     }
  231.     @Override
  232.     protected String getDayFormat(DayFormatEnum dayFormat) throws SQLQueryObjectException {
  233.         switch (dayFormat) {
  234.         case FULL_DAY_NAME:
  235.             return DAY_FORMAT_FULL_DAY_NAME;
  236.         case SHORT_DAY_NAME:
  237.             return DAY_FORMAT_SHORT_DAY_NAME;
  238.         case DAY_OF_YEAR:
  239.             return DAY_FORMAT_DAY_OF_YEAR;
  240.         case DAY_OF_WEEK:
  241.             return DAY_FORMAT_DAY_OF_WEEK;
  242.         }
  243.         throw newSQLQueryObjectExceptionDayFormatEnum(dayFormat);
  244.     }
  245.     @Override
  246.     public String getExtractDayFormatFromTimestampFieldPrefix(DayFormatEnum dayFormat) throws SQLQueryObjectException {
  247.         if(dayFormat==null) {
  248.             throw new SQLQueryObjectException("dayFormat undefined");
  249.         }
  250.         switch (dayFormat) {
  251.         case FULL_DAY_NAME:
  252.         case SHORT_DAY_NAME:
  253.             return "FORMAT(";
  254.         case DAY_OF_YEAR:
  255.             return "DATENAME("+getDayFormat(dayFormat)+" , ";
  256.         case DAY_OF_WEEK:
  257.             return "DATEPART("+getDayFormat(dayFormat)+", ";
  258.         }
  259.         throw newSQLQueryObjectExceptionDayFormatEnum(dayFormat);
  260.     }
  261.     @Override
  262.     public String getExtractDayFormatFromTimestampFieldSuffix(DayFormatEnum dayFormat) throws SQLQueryObjectException {
  263.         if(dayFormat==null) {
  264.             throw new SQLQueryObjectException("dayFormat undefined");
  265.         }
  266.         switch (dayFormat) {
  267.         case FULL_DAY_NAME:
  268.         case SHORT_DAY_NAME:
  269.             String dayFormatString = getDayFormat(dayFormat);
  270.             return ", '"+dayFormatString+"')";
  271.         case DAY_OF_YEAR:
  272.         case DAY_OF_WEEK:
  273.             return ")";
  274.         }
  275.         throw newSQLQueryObjectExceptionDayFormatEnum(dayFormat);
  276.     }
  277.    
  278.    
  279.    
  280.    


  281.     @Override
  282.     public String createSQLQuery() throws SQLQueryObjectException{
  283.         return this.createSQLQuery(false);
  284.     }
  285.     private String createSQLQuery(boolean union) throws SQLQueryObjectException{

  286.         this.precheckBuildQuery();

  287.         StringBuilder bf = new StringBuilder();

  288. /**     StringBuilder cursorName = null;
  289. //      if(this.selectForUpdate){
  290. //          
  291. //          cursorName = new StringBuilder();
  292. //          cursorName.append("cursorName");
  293. //          Random rand = new Random();
  294. //          int rnd;
  295. //          char base;
  296. //          for (int count=0 ; count < 3; count++ ){
  297. //              rnd = (rand.nextInt(52) );
  298. //              base = (rnd < 26) ? 'A' : 'a';
  299. //              cursorName.append((char) (base + rnd % 26));            
  300. //          }
  301. //          
  302. //          bf.append("DECLARE "+cursorName+" CURSOR FOR ");
  303. //      }*/
  304.        
  305.         bf.append("SELECT ");

  306.         if(this.isSelectDistinct())
  307.             bf.append(" DISTINCT ");

  308.         // Limit (senza offset)
  309.         if(this.offset<0 && this.limit>0){
  310.             bf.append(" TOP ");
  311.             bf.append(this.limit);
  312.             bf.append(" ");
  313.         }
  314.         else{
  315.             // Questa istruzione ci vuole altrimenti in presenza di order by, group by si ottiene il seguente errore:
  316.             // The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
  317.             bf.append("TOP 100 PERCENT ");
  318.         }

  319.         // forzatura di indici
  320.         if( !(this.offset>=0 || this.limit>=0) ){
  321.             Iterator<String> itForceIndex = this.forceIndexTableNames.iterator();
  322.             while(itForceIndex.hasNext()){
  323.                 bf.append(" "+itForceIndex.next()+" ");
  324.             }
  325.         }

  326.         // select field
  327.         addSQLQuerySelectField(bf);

  328.         bf.append(getSQL(false,false,false,union));

  329.         /**if( this.offset>=0 || this.limit>=0)
  330.         //  System.out.println("SQL ["+bf.toString()+"]");*/
  331.        
  332. /**     if(this.selectForUpdate){
  333. //          
  334. //          bf.append("OPEN "+cursorName.toString()+" ");
  335. //          bf.append("FETCH NEXT FROM "+cursorName.toString()+" ");
  336. //          bf.append("WHILE @@FETCH_STATUS = 0 ");
  337. //          bf.append("BEGIN ");
  338. //          bf.append("FETCH NEXT FROM "+cursorName.toString()+" ");
  339. //          bf.append("END ");
  340. //          bf.append("CLOSE "+cursorName.toString()+" ");
  341. //          bf.append("DEALLOCATE "+cursorName.toString()+" ");
  342. //          
  343. //      }*/
  344.        
  345.         return bf.toString();
  346.     }
  347.     private void addSQLQuerySelectField(StringBuilder bf) {
  348.         if(this.fields.isEmpty()){
  349.             bf.append("*");
  350.         }else{
  351.             Iterator<String> it = this.fields.iterator();
  352.             boolean first = true;
  353.             while(it.hasNext()){
  354.                 if(!first)
  355.                     bf.append(",");
  356.                 else
  357.                     first = false;

  358.                 String field = it.next();
  359.                 if( this.offset>=0 ){

  360.                     field = this.normalizeField(field, false);

  361.                 }
  362.                 bf.append(field);
  363.             }
  364.         }
  365.     }





  366.     @Override
  367.     public String createSQLDeleteEngine() throws SQLQueryObjectException {

  368.         StringBuilder bf = new StringBuilder();

  369.         bf.append("DELETE ");

  370.         bf.append(getSQL(true,false,false,false));
  371.         return bf.toString();
  372.     }





  373.     private String getSQL(boolean delete,boolean update,boolean conditions,boolean union) throws SQLQueryObjectException {  
  374.         StringBuilder bf = new StringBuilder();

  375.         if(this.selectForUpdate){
  376.             this.checkSelectForUpdate(update, delete, union);
  377.         }
  378.        
  379.         if(!update && !conditions){
  380.             // From
  381.             bf.append(SQLQueryObjectCore.FROM_SEPARATOR);


  382.             // Se e' presente Offset o Limit
  383.             /**if( (this.offset>=0 || this.limit>=0) && (delete==false)) {*/
  384.             // Rilascio vincolo di order by in caso di limit impostato.
  385.             // Il vincolo rimane per l'offset, per gestire le select annidate di qualche implementazioni come Oracle,SQLServer ...
  386.             if( (this.offset>=0) && (!delete)){

  387.                 /**java.util.List<String> aliasOrderByDistinct = new java.util.ArrayList<>();*/

  388.                 /**if(this.isSelectDistinct()==false)*/        
  389.                 bf.append(SQLQueryObjectCore.SELECT_SEPARATOR_CON_INIZIO_APERTURA);
  390.                 /**else
  391.                 //  bf.append(" ( SELECT DISTINCT ");*/

  392.                 // Questa istruzione ci vuole altrimenti in presenza di order by, group by si ottiene il seguente errore:
  393.                 // The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
  394.                 // In questo segmento di select forse non server?
  395.                 /** bf.append("TOP 100 PERCENT ");*/

  396.                 Iterator<String> itForceIndex = this.forceIndexTableNames.iterator();
  397.                 while(itForceIndex.hasNext()){
  398.                     bf.append(" "+itForceIndex.next()+" ");
  399.                 }

  400.                 if(this.isSelectDistinct()){
  401.                     // select field
  402.                     if(this.fields.isEmpty()){
  403.                         bf.append("*");
  404.                     }else{
  405.                         Iterator<String> it = this.fields.iterator();
  406.                         boolean first = true;
  407.                         while(it.hasNext()){
  408.                             if(!first)
  409.                                 bf.append(",");
  410.                             else
  411.                                 first = false;

  412.                             String field = it.next();
  413.                             if( this.offset>=0 ){

  414.                                 field = this.normalizeField(field, false);

  415.                             }
  416.                             bf.append(field);
  417.                         }
  418.                     }
  419.                 }
  420.                 else{          
  421.                     if(this.fields.isEmpty()){
  422.                         bf.append("*");
  423.                     }else{
  424.                         Iterator<String> it = this.fields.iterator();
  425.                         boolean first = true;
  426.                         while(it.hasNext()){
  427.                             if(!first)
  428.                                 bf.append(",");
  429.                             else
  430.                                 first = false;
  431.                             String f = it.next();
  432.                             bf.append(f);
  433.                         }
  434.                     }
  435.                 }


  436.                 bf.append(" , ROW_NUMBER() OVER ( ORDER BY ");

  437.                 // Condizione OrderBy
  438.                 if(this.orderBy.isEmpty()){
  439.                     throw new SQLQueryObjectException(SQLQueryObjectCore.CONDIZIONI_ORDER_BY_RICHESTE);
  440.                 }
  441.                 if(!this.orderBy.isEmpty()){
  442.                     Iterator<String> it = this.orderBy.iterator();
  443.                     boolean first = true;
  444.                     while(it.hasNext()){
  445.                         if(!first)
  446.                             bf.append(",");
  447.                         else
  448.                             first = false;
  449.                         String condizione = it.next();
  450.                         /**System.out.println("=======================");
  451.                         System.out.println("alias: "+this.alias);
  452.                         System.out.println("condizione: "+condizione);
  453.                         System.out.println("KEY: "+(this.alias.containsKey(condizione)));
  454.                         System.out.println("VALUE: "+(this.alias.containsValue(condizione)));
  455.                         System.out.println("DISTINCT: "+(this.isSelectDistinct()));
  456.                         System.out.println("=======================");*/
  457.                         if(this.alias.containsKey(condizione)){
  458.                             if(this.isSelectDistinct()){
  459.                                 bf.append(condizione);
  460.                             }
  461.                             else{
  462.                                 bf.append(this.alias.get(condizione));
  463.                             }
  464.                         }else if(this.alias.containsValue(condizione)) {
  465.                             bf.append(condizione);
  466.                         }
  467.                         else{
  468.                             bf.append(this.normalizeField(condizione,false));
  469.                         }
  470.                         boolean sortTypeAsc = this.sortTypeAsc;
  471.                         if(this.orderBySortType.containsKey(condizione)){
  472.                             sortTypeAsc = this.orderBySortType.get(condizione);
  473.                         }
  474.                         if(sortTypeAsc){
  475.                             bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  476.                         }else{
  477.                             bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  478.                         }
  479.                     }
  480.                 }

  481.                 bf.append(" ) AS rowNumber ");


  482.                 bf.append(SQLQueryObjectCore.FROM_SEPARATOR);

  483.                 if(this.isSelectDistinct()){

  484.                     bf.append(" ( SELECT DISTINCT TOP 100 PERCENT ");

  485.                     if(this.fields.isEmpty()){
  486.                         bf.append("*");
  487.                     }else{
  488.                         Iterator<String> it = this.fields.iterator();
  489.                         boolean first = true;
  490.                         while(it.hasNext()){
  491.                             if(!first)
  492.                                 bf.append(",");
  493.                             else
  494.                                 first = false;
  495.                             String f = it.next();
  496.                             bf.append(f);
  497.                         }
  498.                     }

  499.                     bf.append(SQLQueryObjectCore.FROM_SEPARATOR);
  500.                 }

  501.                 // Table dove effettuare la ricerca 'FromTable'
  502.                 if(this.tables.isEmpty()){
  503.                     throw new SQLQueryObjectException(SQLQueryObjectCore.TABELLA_RICERCA_FROM_NON_DEFINITA);
  504.                 }else{
  505.                     Iterator<String> it = this.tables.iterator();
  506.                     boolean first = true;
  507.                     while(it.hasNext()){
  508.                         if(!first)
  509.                             bf.append(",");
  510.                         else
  511.                             first = false;
  512.                         bf.append(it.next());
  513.                     }
  514.                 }

  515.                 // Condizioni di Where
  516.                 if(!this.conditions.isEmpty()){

  517.                     bf.append(SQLQueryObjectCore.WHERE_SEPARATOR);

  518.                     if(this.notBeforeConditions){
  519.                         bf.append(SQLQueryObjectCore.NOT_SEPARATOR_APERTURA);
  520.                     }

  521.                     for(int i=0; i<this.conditions.size(); i++){

  522.                         if(i>0){
  523.                             if(this.andLogicOperator){
  524.                                 bf.append(SQLQueryObjectCore.AND_SEPARATOR);
  525.                             }else{
  526.                                 bf.append(SQLQueryObjectCore.OR_SEPARATOR);
  527.                             }
  528.                         }
  529.                         String cond = this.conditions.get(i);              
  530.                         bf.append(cond);
  531.                     }

  532.                     if(this.notBeforeConditions){
  533.                         bf.append(" )");
  534.                     }
  535.                 }

  536.                 // Condizione GroupBy
  537.                 if((!this.getGroupByConditions().isEmpty()) && (!delete)){
  538.                     bf.append(SQLQueryObjectCore.GROUP_BY_SEPARATOR);
  539.                     Iterator<String> it = this.getGroupByConditions().iterator();
  540.                     boolean first = true;
  541.                     while(it.hasNext()){
  542.                         if(!first)
  543.                             bf.append(",");
  544.                         else
  545.                             first = false;
  546.                         bf.append(it.next());
  547.                     }
  548.                 }

  549.                 if(this.isSelectDistinct()){

  550.                     // Order solo in presenza di select distinct
  551.                     if((!this.orderBy.isEmpty()) && (!delete)){
  552.                         bf.append(SQLQueryObjectCore.ORDER_BY_SEPARATOR);
  553.                         Iterator<String> it = this.orderBy.iterator();
  554.                         boolean first = true;
  555.                         while(it.hasNext()){
  556.                             String column = it.next();
  557.                             if(!first)
  558.                                 bf.append(",");
  559.                             else
  560.                                 first = false;
  561.                             bf.append(column);
  562.                             boolean sortTypeAsc = this.sortTypeAsc;
  563.                             if(this.orderBySortType.containsKey(column)){
  564.                                 sortTypeAsc = this.orderBySortType.get(column);
  565.                             }
  566.                             if(sortTypeAsc){
  567.                                 bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  568.                             }else{
  569.                                 bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  570.                             }
  571.                         }
  572.                     }

  573.                     // Devo forzare l'utilizzo di un alias su una sottoselct dentro il FROM        
  574.                     bf.append(" ) ");
  575.                     bf.append(this.getDefaultAliasFieldKeyword());
  576.                     bf.append("tableSelectRaw");
  577.                     // Genero Tre caratteri alfabetici casuali per dare un alias del tipo "tabellaXXX"
  578.                     int rnd;
  579.                     char base;
  580.                     for (int count=0 ; count < 3; count++ ){
  581.                         rnd = (SQLQueryObjectCore.getRandom().nextInt(52) );
  582.                         base = (rnd < 26) ? 'A' : 'a';
  583.                         bf.append((char) (base + rnd % 26));

  584.                     }
  585.                 }


  586.                 // Devo forzare l'utilizzo di un alias su una sottoselct dentro il FROM        
  587.                 bf.append(" ) ");
  588.                 bf.append(this.getDefaultAliasFieldKeyword());
  589.                 bf.append("tabella");
  590.                 // Genero Tre caratteri alfabetici casuali per dare un alias del tipo "tabellaXXX"
  591.                 int rnd;
  592.                 char base;
  593.                 for (int count=0 ; count < 3; count++ ){
  594.                     rnd = (SQLQueryObjectCore.getRandom().nextInt(52) );
  595.                     base = (rnd < 26) ? 'A' : 'a';
  596.                     bf.append((char) (base + rnd % 26));

  597.                 }
  598.                 bf.append(" WHERE ( ");

  599.                 if(this.offset>=0){
  600.                     bf.append(" rowNumber > ");
  601.                     bf.append(this.offset);
  602.                 }
  603.                 if(this.limit>=0){
  604.                     if(this.offset>=0)
  605.                         bf.append(" AND");
  606.                     bf.append(" rowNumber <=  ");
  607.                     if(this.offset>=0)
  608.                         bf.append(this.offset+this.limit);
  609.                     else
  610.                         bf.append(this.limit);
  611.                 }
  612.                 bf.append(" )");


  613.                 // ORDER BY FINALE
  614.                 if(!union &&
  615.                     (!this.orderBy.isEmpty())
  616.                     ){
  617.                     bf.append(SQLQueryObjectCore.ORDER_BY_SEPARATOR);
  618.                     Iterator<String> it = this.orderBy.iterator();
  619.                     boolean first = true;
  620.                     while(it.hasNext()){
  621.                         if(!first)
  622.                             bf.append(",");
  623.                         else
  624.                             first = false;
  625.                         String originalField = it.next();

  626.                         String field = this.normalizeField(originalField);
  627.                         bf.append(field);  
  628.                         boolean sortTypeAsc = this.sortTypeAsc;
  629.                         if(this.orderBySortType.containsKey(originalField)){
  630.                             sortTypeAsc = this.orderBySortType.get(originalField);
  631.                         }
  632.                         if(sortTypeAsc){
  633.                             bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  634.                         }else{
  635.                             bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  636.                         }
  637.                     }
  638.                 }

  639.                 /**
  640.                  * OLD ALIAS
  641.             if(aliasOrderByDistinct.size()>0){
  642.                 bf.append(SQLQueryObjectCore.ORDER_BY_SEPARATOR);
  643.                 Iterator<String> it = aliasOrderByDistinct.iterator();
  644.                 boolean first = true;
  645.                 while(it.hasNext()){
  646.                     if(!first)
  647.                         bf.append(",");
  648.                     else
  649.                         first = false;
  650.                     bf.append(it.next());
  651.                 }
  652.                 if(this.sortTypeAsc){
  653.                     bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  654.                 }else{
  655.                     bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  656.                 }
  657.             }
  658.                  */

  659.                 // ForUpdate (Non si puรฒ utilizzarlo con offset o limit in oracle)
  660. /**             if(this.selectForUpdate){
  661. //                  bf.append(" FOR UPDATE ");
  662. //              }*/
  663.                
  664.             }else{

  665.                 // Offset non presente

  666.                 // Table dove effettuare la ricerca 'FromTable'
  667.                 if(this.tables.isEmpty()){
  668.                     throw new SQLQueryObjectException(SQLQueryObjectCore.TABELLA_RICERCA_FROM_NON_DEFINITA);
  669.                 }else{

  670.                     if(delete && this.tables.size()>2)
  671.                         throw new SQLQueryObjectException("Non e' possibile effettuare una delete con piu' di una tabella alla volta");

  672.                     Iterator<String> it = this.tables.iterator();
  673.                     boolean first = true;
  674.                     while(it.hasNext()){
  675.                         if(!first)
  676.                             bf.append(",");
  677.                         else
  678.                             first = false;
  679.                         bf.append(it.next());
  680.                     }
  681.                 }

  682.                 // For Update
  683.                 if(this.selectForUpdate){
  684.                     bf.append(" WITH (ROWLOCK) ");
  685.                 }
  686.                
  687.                 // Condizioni di Where
  688.                 if(!this.conditions.isEmpty()){
  689.                     bf.append(SQLQueryObjectCore.WHERE_SEPARATOR);

  690.                     if(this.notBeforeConditions){
  691.                         bf.append("NOT (");
  692.                     }

  693.                     for(int i=0; i<this.conditions.size(); i++){
  694.                         if(i>0){
  695.                             if(this.andLogicOperator){
  696.                                 bf.append(SQLQueryObjectCore.AND_SEPARATOR);
  697.                             }else{
  698.                                 bf.append(SQLQueryObjectCore.OR_SEPARATOR);
  699.                             }
  700.                         }
  701.                         bf.append(this.conditions.get(i));
  702.                     }

  703.                     if(this.notBeforeConditions){
  704.                         bf.append(")");
  705.                     }

  706.                 }

  707.                 // Condizione GroupBy
  708.                 if((!this.getGroupByConditions().isEmpty()) && (!delete)){
  709.                     bf.append(SQLQueryObjectCore.GROUP_BY_SEPARATOR);
  710.                     Iterator<String> it = this.getGroupByConditions().iterator();
  711.                     boolean first = true;
  712.                     while(it.hasNext()){
  713.                         if(!first)
  714.                             bf.append(",");
  715.                         else
  716.                             first = false;
  717.                         bf.append(it.next());
  718.                     }
  719.                 }

  720.                 // Condizione OrderBy
  721.                 if(!union &&
  722.                     (!this.orderBy.isEmpty()) && (!delete)
  723.                     ){
  724.                     bf.append(SQLQueryObjectCore.ORDER_BY_SEPARATOR);
  725.                     Iterator<String> it = this.orderBy.iterator();
  726.                     boolean first = true;
  727.                     while(it.hasNext()){
  728.                         String column = it.next();
  729.                         if(!first)
  730.                             bf.append(",");
  731.                         else
  732.                             first = false;
  733.                         bf.append(column);
  734.                         boolean sortTypeAsc = this.sortTypeAsc;
  735.                         if(this.orderBySortType.containsKey(column)){
  736.                             sortTypeAsc = this.orderBySortType.get(column);
  737.                         }
  738.                         if(sortTypeAsc){
  739.                             bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  740.                         }else{
  741.                             bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  742.                         }
  743.                     }
  744.                 }
  745.                
  746. //              // ForUpdate
  747. /**             if(this.selectForUpdate){
  748. //                  bf.append(" FOR UPDATE ");
  749. //              }*/
  750.             }
  751.         }else{

  752.             // UPDATE, conditions

  753.             // Non genero per le condizioni, per update viene sollevata eccezione prima
  754.             // For Update
  755. /**         if(this.selectForUpdate){
  756. //              bf.append(" WITH (ROWLOCK) ");
  757. //          }*/
  758.            
  759.             // Condizioni di Where
  760.             if(!this.conditions.isEmpty()){

  761.                 if(!conditions)
  762.                     bf.append(SQLQueryObjectCore.WHERE_SEPARATOR);

  763.                 if(this.notBeforeConditions){
  764.                     bf.append("NOT (");
  765.                 }

  766.                 for(int i=0; i<this.conditions.size(); i++){
  767.                     if(i>0){
  768.                         if(this.andLogicOperator){
  769.                             bf.append(SQLQueryObjectCore.AND_SEPARATOR);
  770.                         }else{
  771.                             bf.append(SQLQueryObjectCore.OR_SEPARATOR);
  772.                         }
  773.                     }
  774.                     bf.append(this.conditions.get(i));
  775.                 }

  776.                 if(this.notBeforeConditions){
  777.                     bf.append(")");
  778.                 }

  779.             }
  780.            
  781. //          // ForUpdate
  782. /**         if(this.selectForUpdate){
  783. //              bf.append(" FOR UPDATE ");
  784. //          }*/
  785.         }

  786.         return bf.toString();
  787.     }

  788.     @Override
  789.     public String createSQLUnion(boolean unionAll,
  790.             ISQLQueryObject... sqlQueryObject) throws SQLQueryObjectException {

  791.         // Controllo parametro su cui effettuare la UNION
  792.         this.checkUnionField(false,sqlQueryObject);

  793.         if(this.selectForUpdate){
  794.             this.checkSelectForUpdate(false, false, true);
  795.         }
  796.        
  797.         StringBuilder bf = new StringBuilder();

  798.         // Non ha senso, la union fa gia la distinct, a meno di usare la unionAll ma in quel caso non si vuole la distinct
  799.         /** if(this.isSelectDistinct())
  800.         //  bf.append(" DISTINCT ");*/

  801.         // Se e' presente Offset o Limit
  802.         // Rilascio vincolo di order by in caso di limit impostato.
  803.         // Il vincolo rimane per l'offset, per gestire le select annidate di qualche implementazioni come Oracle,SQLServer ...
  804.         /**if( (this.offset>=0 || this.limit>=0) ){*/
  805.         if( this.offset>=0 ){

  806.             bf.append("SELECT TOP 100 PERCENT * from ");

  807.             bf.append(SQLQueryObjectCore.SELECT_SEPARATOR_CON_INIZIO_APERTURA);

  808.             // Questa istruzione ci vuole altrimenti in presenza di order by, group by si ottiene il seguente errore:
  809.             // The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
  810.             // In questo segmento di select forse non server?
  811.             /** bf.append("TOP 100 PERCENT ");*/

  812.             if(this.fields.isEmpty()){
  813.                 bf.append("*");
  814.             }else{
  815.                 Iterator<String> it = this.fields.iterator();
  816.                 boolean first = true;
  817.                 while(it.hasNext()){
  818.                     if(!first)
  819.                         bf.append(",");
  820.                     else
  821.                         first = false;
  822.                     String f = it.next();
  823.                     bf.append(f);
  824.                 }
  825.             }

  826.             bf.append(" , ROW_NUMBER() OVER ( ORDER BY ");

  827.             // Condizione OrderBy
  828.             if(this.orderBy.isEmpty()){
  829.                 throw new SQLQueryObjectException(SQLQueryObjectCore.CONDIZIONI_ORDER_BY_RICHESTE);
  830.             }
  831.             if(!this.orderBy.isEmpty()){
  832.                 Iterator<String> it = this.orderBy.iterator();
  833.                 boolean first = true;
  834.                 while(it.hasNext()){
  835.                     if(!first)
  836.                         bf.append(",");
  837.                     else
  838.                         first = false;
  839.                     String condizione = it.next();
  840.                     if(this.alias.containsKey(condizione)){
  841.                         bf.append(this.alias.get(condizione));
  842.                     }else{
  843.                         bf.append(condizione);
  844.                     }
  845.                     boolean sortTypeAsc = this.sortTypeAsc;
  846.                     if(this.orderBySortType.containsKey(condizione)){
  847.                         sortTypeAsc = this.orderBySortType.get(condizione);
  848.                     }
  849.                     if(sortTypeAsc){
  850.                         bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  851.                     }else{
  852.                         bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  853.                     }
  854.                 }
  855.             }

  856.             bf.append(" ) AS rowNumber ");

  857.             // Table dove effettuare la ricerca 'FromTable'
  858.             bf.append(SQLQueryObjectCore.FROM_SEPARATOR_APERTURA);

  859.             for(int i=0; i<sqlQueryObject.length; i++){

  860.                 if(((SQLServerQueryObject)sqlQueryObject[i]).selectForUpdate){
  861.                     try{
  862.                         ((SQLServerQueryObject)sqlQueryObject[i]).checkSelectForUpdate(false, false, true);
  863.                     }catch(Exception e){
  864.                         throw new SQLQueryObjectException("Parametro SqlQueryObject["+i+"] non valido: "+e.getMessage());
  865.                     }
  866.                 }
  867.                
  868.                 if(i>0){
  869.                     bf.append(" UNION ");
  870.                     if(unionAll){
  871.                         bf.append(" ALL ");
  872.                     }
  873.                 }

  874.                 bf.append("( ");

  875.                 bf.append(((SQLServerQueryObject)sqlQueryObject[i]).createSQLQuery(true));

  876.                 bf.append(") ");
  877.             }

  878.             bf.append(SQLQueryObjectCore.AS_SUBQUERY_SUFFIX+getSerial()+" ");

  879.             // Condizioni di Where
  880.             if(!this.conditions.isEmpty()){

  881.                 bf.append(SQLQueryObjectCore.WHERE_SEPARATOR);

  882.                 if(this.notBeforeConditions){
  883.                     bf.append(SQLQueryObjectCore.NOT_SEPARATOR_APERTURA);
  884.                 }

  885.                 for(int i=0; i<this.conditions.size(); i++){

  886.                     if(i>0){
  887.                         if(this.andLogicOperator){
  888.                             bf.append(SQLQueryObjectCore.AND_SEPARATOR);
  889.                         }else{
  890.                             bf.append(SQLQueryObjectCore.OR_SEPARATOR);
  891.                         }
  892.                     }
  893.                     String cond = this.conditions.get(i);
  894.                     bf.append(cond);
  895.                 }

  896.                 if(this.notBeforeConditions){
  897.                     bf.append(" )");
  898.                 }
  899.             }

  900.             // Condizione GroupBy
  901.             if((!this.getGroupByConditions().isEmpty())){
  902.                 bf.append(SQLQueryObjectCore.GROUP_BY_SEPARATOR);
  903.                 Iterator<String> it = this.getGroupByConditions().iterator();
  904.                 boolean first = true;
  905.                 while(it.hasNext()){
  906.                     if(!first)
  907.                         bf.append(",");
  908.                     else
  909.                         first = false;
  910.                     bf.append(it.next());
  911.                 }
  912.             }

  913.             bf.append(SQLQueryObjectCore.AS_SUBQUERY_SUFFIX+getSerial()+" ");

  914.             bf.append(" WHERE ( ");
  915.             if(this.offset>=0){
  916.                 bf.append(" rowNumber > ");
  917.                 bf.append(this.offset);
  918.             }
  919.             if(this.limit>=0){
  920.                 if(this.offset>=0)
  921.                     bf.append(" AND");
  922.                 bf.append(" rowNumber <=  ");
  923.                 if(this.offset>=0)
  924.                     bf.append(this.offset+this.limit);
  925.                 else
  926.                     bf.append(this.limit);
  927.             }
  928.             bf.append(" )");


  929.         }else{

  930.             // no offset

  931.             bf.append("SELECT ");

  932.             // Limit (senza offset)
  933.             if(this.offset<0 && this.limit>0){
  934.                 bf.append("TOP ");
  935.                 bf.append(this.limit);
  936.                 bf.append(" ");
  937.             }
  938.             else{
  939.                 // Questa istruzione ci vuole altrimenti in presenza di order by, group by si ottiene il seguente errore:
  940.                 // The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
  941.                 bf.append("TOP 100 PERCENT ");
  942.             }


  943.             Iterator<String> itForceIndex = this.forceIndexTableNames.iterator();
  944.             while(itForceIndex.hasNext()){
  945.                 bf.append(" "+itForceIndex.next()+" ");
  946.             }

  947.             if(this.fields.isEmpty()){
  948.                 bf.append("*");
  949.             }else{
  950.                 Iterator<String> it = this.fields.iterator();
  951.                 boolean first = true;
  952.                 while(it.hasNext()){
  953.                     if(!first)
  954.                         bf.append(",");
  955.                     else
  956.                         first = false;
  957.                     String f = it.next();
  958.                     bf.append(f);
  959.                 }
  960.             }

  961.             bf.append(SQLQueryObjectCore.FROM_SEPARATOR_APERTURA);

  962.             for(int i=0; i<sqlQueryObject.length; i++){

  963.                 if(((SQLServerQueryObject)sqlQueryObject[i]).selectForUpdate){
  964.                     try{
  965.                         ((SQLServerQueryObject)sqlQueryObject[i]).checkSelectForUpdate(false, false, true);
  966.                     }catch(Exception e){
  967.                         throw new SQLQueryObjectException("Parametro SqlQueryObject["+i+"] non valido: "+e.getMessage());
  968.                     }
  969.                 }
  970.                
  971.                 if(i>0){
  972.                     bf.append(" UNION ");
  973.                     if(unionAll){
  974.                         bf.append(" ALL ");
  975.                     }
  976.                 }

  977.                 bf.append("( ");

  978.                 bf.append(((SQLServerQueryObject)sqlQueryObject[i]).createSQLQuery(true));

  979.                 bf.append(") ");
  980.             }

  981.             bf.append(SQLQueryObjectCore.AS_SUBQUERY_SUFFIX+getSerial()+" ");


  982.             // Condizione GroupBy
  983.             if((!this.getGroupByConditions().isEmpty())){
  984.                 bf.append(SQLQueryObjectCore.GROUP_BY_SEPARATOR);
  985.                 Iterator<String> it = this.getGroupByConditions().iterator();
  986.                 boolean first = true;
  987.                 while(it.hasNext()){
  988.                     if(!first)
  989.                         bf.append(",");
  990.                     else
  991.                         first = false;
  992.                     bf.append(it.next());
  993.                 }
  994.             }

  995.             // Condizione OrderBy
  996.             if(!this.orderBy.isEmpty()){
  997.                 bf.append(SQLQueryObjectCore.ORDER_BY_SEPARATOR);
  998.                 Iterator<String> it = this.orderBy.iterator();
  999.                 boolean first = true;
  1000.                 while(it.hasNext()){
  1001.                     String column = it.next();
  1002.                     if(!first)
  1003.                         bf.append(",");
  1004.                     else
  1005.                         first = false;
  1006.                     bf.append(column);
  1007.                     boolean sortTypeAsc = this.sortTypeAsc;
  1008.                     if(this.orderBySortType.containsKey(column)){
  1009.                         sortTypeAsc = this.orderBySortType.get(column);
  1010.                     }
  1011.                     if(sortTypeAsc){
  1012.                         bf.append(SQLQueryObjectCore.ASC_SEPARATOR);
  1013.                     }else{
  1014.                         bf.append(SQLQueryObjectCore.DESC_SEPARATOR);
  1015.                     }
  1016.                 }
  1017.             }
  1018.         }

  1019.         return bf.toString();
  1020.     }

  1021.     @Override
  1022.     public String createSQLUnionCount(boolean unionAll, String aliasCount,
  1023.             ISQLQueryObject... sqlQueryObject) throws SQLQueryObjectException {

  1024.         // Controllo parametro su cui effettuare la UNION
  1025.         this.checkUnionField(true,sqlQueryObject);

  1026.         if(aliasCount==null){
  1027.             throw new SQLQueryObjectException("Alias per il count non definito");
  1028.         }

  1029.         StringBuilder bf = new StringBuilder();

  1030.         bf.append("SELECT count(*) "+this.getDefaultAliasFieldKeyword()+" ");
  1031.         bf.append(aliasCount);
  1032.         bf.append(SQLQueryObjectCore.FROM_SEPARATOR_APERTURA);

  1033.         bf.append( this.createSQLUnion(unionAll, sqlQueryObject) );

  1034.         bf.append(SQLQueryObjectCore.AS_SUBQUERY_SUFFIX+getSerial()+" ");

  1035.         return bf.toString();
  1036.     }

  1037.     @Override
  1038.     public String createSQLUpdateEngine() throws SQLQueryObjectException {
  1039.        
  1040.         StringBuilder bf = new StringBuilder();
  1041.         bf.append("UPDATE ");
  1042.         bf.append(this.updateTable);
  1043.         bf.append(" SET ");
  1044.         for(int i=0; i<this.updateFieldsName.size(); i++){
  1045.             if(i>0)
  1046.                 bf.append(" , ");
  1047.             bf.append(this.updateFieldsName.get(i));
  1048.             bf.append(" = ");
  1049.             bf.append(this.updateFieldsValue.get(i));
  1050.         }
  1051.         bf.append(getSQL(false,true,false,false));
  1052.         return bf.toString();
  1053.     }








  1054.     /* ---------------- WHERE CONDITIONS ------------------ */

  1055.     @Override
  1056.     public String createSQLConditionsEngine() throws SQLQueryObjectException {
  1057.        
  1058.         StringBuilder bf = new StringBuilder();
  1059.         bf.append(getSQL(false,false,true,false));
  1060.         return bf.toString();
  1061.     }



  1062. }