Coverage Report - org.apache.ojb.broker.accesslayer.sql.SqlGeneratorDefaultImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
SqlGeneratorDefaultImpl
N/A
N/A
2.2
SqlGeneratorDefaultImpl$SqlForClass
N/A
N/A
2.2
 
 1  
 package org.apache.ojb.broker.accesslayer.sql;
 2  
 
 3  
 /* Copyright 2002-2005 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 import java.util.Collection;
 19  
 import java.util.Enumeration;
 20  
 import java.util.Map;
 21  
 
 22  
 import org.apache.commons.collections.map.ReferenceIdentityMap;
 23  
 import org.apache.ojb.broker.metadata.ClassDescriptor;
 24  
 import org.apache.ojb.broker.metadata.ProcedureDescriptor;
 25  
 import org.apache.ojb.broker.platforms.Platform;
 26  
 import org.apache.ojb.broker.query.BetweenCriteria;
 27  
 import org.apache.ojb.broker.query.Criteria;
 28  
 import org.apache.ojb.broker.query.ExistsCriteria;
 29  
 import org.apache.ojb.broker.query.FieldCriteria;
 30  
 import org.apache.ojb.broker.query.InCriteria;
 31  
 import org.apache.ojb.broker.query.NullCriteria;
 32  
 import org.apache.ojb.broker.query.Query;
 33  
 import org.apache.ojb.broker.query.SelectionCriteria;
 34  
 import org.apache.ojb.broker.query.SqlCriteria;
 35  
 import org.apache.ojb.broker.util.logging.Logger;
 36  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 37  
 
 38  
 /**
 39  
  * This Class is responsible for building sql statements
 40  
  * Objects fields and their repective values are accessed by Java reflection
 41  
  *
 42  
  * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
 43  
  * @author <a href="mailto:rgallagh@bellsouth.net">Ron Gallagher</a>
 44  
  * @author <a href="mailto:rburt3@mchsi.com">Randall Burt</a>
 45  
  * @version $Id: SqlGeneratorDefaultImpl.java,v 1.1 2007-08-24 22:17:39 ewestfal Exp $
 46  
  */
 47  
 public class SqlGeneratorDefaultImpl implements SqlGenerator
 48  
 {
 49  
     private Logger logger = LoggerFactory.getLogger(SqlGeneratorDefaultImpl.class);
 50  
     private Platform m_platform;
 51  
     /*
 52  
     arminw:
 53  
     TODO: In ClassDescriptor we need support for "field change event" listener if we allow
 54  
     to change metadata at runtime.
 55  
     Further on we have to deal with weak references to allow GC of outdated Metadata classes
 56  
     (key=cld of map have to be a weak reference and the metadata used in the SqlStatement classes too,
 57  
     because inner class SqlForClass indirectly refer the key=cld in some cases and SqlStatement
 58  
     implementation classes have references to metadata classes too).
 59  
 
 60  
     Field changes are not reflected in this implementation!
 61  
     */
 62  
     /** Cache for {@link SqlForClass} instances, keyed per class descriptor. */
 63  
     private Map sqlForClass = new ReferenceIdentityMap(ReferenceIdentityMap.WEAK, ReferenceIdentityMap.HARD);
 64  
 
 65  
     public SqlGeneratorDefaultImpl(Platform platform)
 66  
     {
 67  
         this.m_platform = platform;
 68  
     }
 69  
 
 70  
     /**
 71  
      * generate a prepared DELETE-Statement for the Class
 72  
      * described by cld.
 73  
      * @param cld the ClassDescriptor
 74  
      */
 75  
     public SqlStatement getPreparedDeleteStatement(ClassDescriptor cld)
 76  
     {
 77  
         SqlForClass sfc = getSqlForClass(cld);
 78  
         SqlStatement sql = sfc.getDeleteSql();
 79  
         if(sql == null)
 80  
         {
 81  
             ProcedureDescriptor pd = cld.getDeleteProcedure();
 82  
 
 83  
             if(pd == null)
 84  
             {
 85  
                 sql = new SqlDeleteByPkStatement(cld, logger);
 86  
             }
 87  
             else
 88  
             {
 89  
                 sql = new SqlProcedureStatement(pd, logger);
 90  
             }
 91  
             // set the sql string
 92  
             sfc.setDeleteSql(sql);
 93  
 
 94  
             if(logger.isDebugEnabled())
 95  
             {
 96  
                 logger.debug("SQL:" + sql.getStatement());
 97  
             }
 98  
         }
 99  
         return sql;
 100  
     }
 101  
 
 102  
     /**
 103  
      * generate a prepared INSERT-Statement for the Class
 104  
      * described by cld.
 105  
      *
 106  
      * @param cld the ClassDescriptor
 107  
      */
 108  
     public SqlStatement getPreparedInsertStatement(ClassDescriptor cld)
 109  
     {
 110  
         SqlStatement sql;
 111  
         SqlForClass sfc = getSqlForClass(cld);
 112  
         sql = sfc.getInsertSql();
 113  
         if(sql == null)
 114  
         {
 115  
             ProcedureDescriptor pd = cld.getInsertProcedure();
 116  
 
 117  
             if(pd == null)
 118  
             {
 119  
                 sql = new SqlInsertStatement(cld, logger);
 120  
             }
 121  
             else
 122  
             {
 123  
                 sql = new SqlProcedureStatement(pd, logger);
 124  
             }
 125  
             // set the sql string
 126  
             sfc.setInsertSql(sql);
 127  
 
 128  
             if(logger.isDebugEnabled())
 129  
             {
 130  
                 logger.debug("SQL:" + sql.getStatement());
 131  
             }
 132  
         }
 133  
         return sql;
 134  
     }
 135  
 
 136  
     /**
 137  
      * generate a prepared SELECT-Statement for the Class
 138  
      * described by cld
 139  
      * @param cld the ClassDescriptor
 140  
      */
 141  
     public SelectStatement getPreparedSelectByPkStatement(ClassDescriptor cld)
 142  
     {
 143  
         SelectStatement sql;
 144  
         SqlForClass sfc = getSqlForClass(cld);
 145  
         sql = sfc.getSelectByPKSql();
 146  
         if(sql == null)
 147  
         {
 148  
             sql = new SqlSelectByPkStatement(m_platform, cld, logger);
 149  
 
 150  
             // set the sql string
 151  
             sfc.setSelectByPKSql(sql);
 152  
 
 153  
             if(logger.isDebugEnabled())
 154  
             {
 155  
                 logger.debug("SQL:" + sql.getStatement());
 156  
             }
 157  
         }
 158  
         return sql;
 159  
     }
 160  
 
 161  
     public SqlStatement getPreparedExistsStatement(ClassDescriptor cld)
 162  
     {
 163  
         SqlStatement sql;
 164  
         SqlForClass sfc = getSqlForClass(cld);
 165  
         sql = sfc.getSelectExists();
 166  
         if(sql == null)
 167  
         {
 168  
             // TODO: Should we support a procedure call for this too??
 169  
             sql = new SqlExistStatement(cld, logger);
 170  
             // set the sql string
 171  
             sfc.setSelectExists(sql);
 172  
             if(logger.isDebugEnabled())
 173  
             {
 174  
                 logger.debug("SQL:" + sql.getStatement());
 175  
             }
 176  
         }
 177  
         return sql;
 178  
     }
 179  
 
 180  
     /**
 181  
      * generate a select-Statement according to query
 182  
      *
 183  
      * @param query the Query
 184  
      * @param cld the ClassDescriptor
 185  
      */
 186  
     public SelectStatement getPreparedSelectStatement(Query query, ClassDescriptor cld)
 187  
     {
 188  
         SelectStatement sql = new SqlSelectStatement(m_platform, cld, query, logger);
 189  
         if (logger.isDebugEnabled())
 190  
         {
 191  
             logger.debug("SQL:" + sql.getStatement());
 192  
         }
 193  
         return sql;
 194  
     }
 195  
 
 196  
     /**
 197  
      * generate a prepared UPDATE-Statement for the Class
 198  
      * described by cld
 199  
      * @param cld the ClassDescriptor
 200  
      */
 201  
     public SqlStatement getPreparedUpdateStatement(ClassDescriptor cld)
 202  
     {
 203  
         SqlForClass sfc = getSqlForClass(cld);
 204  
         SqlStatement result = sfc.getUpdateSql();
 205  
         if(result == null)
 206  
         {
 207  
             ProcedureDescriptor pd = cld.getUpdateProcedure();
 208  
 
 209  
             if(pd == null)
 210  
             {
 211  
                 result = new SqlUpdateStatement(cld, logger);
 212  
             }
 213  
             else
 214  
             {
 215  
                 result = new SqlProcedureStatement(pd, logger);
 216  
             }
 217  
             // set the sql string
 218  
             sfc.setUpdateSql(result);
 219  
 
 220  
             if(logger.isDebugEnabled())
 221  
             {
 222  
                 logger.debug("SQL:" + result.getStatement());
 223  
             }
 224  
         }
 225  
         return result;
 226  
     }
 227  
 
 228  
     /**
 229  
      * generate an INSERT-Statement for M:N indirection table
 230  
      *
 231  
      * @param table
 232  
      * @param pkColumns1
 233  
      * @param pkColumns2
 234  
      */
 235  
     public String getInsertMNStatement(String table, String[] pkColumns1, String[] pkColumns2)
 236  
     {
 237  
         SqlStatement sql;
 238  
         String result;
 239  
 
 240  
         String[] cols = new String[pkColumns1.length + pkColumns2.length];
 241  
         System.arraycopy(pkColumns1, 0, cols, 0, pkColumns1.length);
 242  
         System.arraycopy(pkColumns2, 0, cols, pkColumns1.length, pkColumns2.length);
 243  
 
 244  
         sql = new SqlInsertMNStatement(table, cols, logger);
 245  
         result = sql.getStatement();
 246  
 
 247  
         if (logger.isDebugEnabled())
 248  
         {
 249  
             logger.debug("SQL:" + result);
 250  
         }
 251  
         return result;
 252  
     }
 253  
 
 254  
     /**
 255  
      * generate a SELECT-Statement for M:N indirection table
 256  
      *
 257  
      * @param table the indirection table
 258  
      * @param selectColumns selected columns
 259  
      * @param columns for where
 260  
      */
 261  
     public String getSelectMNStatement(String table, String[] selectColumns, String[] columns)
 262  
     {
 263  
         SqlStatement sql;
 264  
         String result;
 265  
 
 266  
         sql = new SqlSelectMNStatement(table, selectColumns, columns, logger);
 267  
         result = sql.getStatement();
 268  
 
 269  
         if (logger.isDebugEnabled())
 270  
         {
 271  
             logger.debug("SQL:" + result);
 272  
         }
 273  
         return result;
 274  
     }
 275  
 
 276  
     /**
 277  
      * generate a DELETE-Statement for M:N indirection table
 278  
      *
 279  
      * @param table
 280  
      * @param pkColumns1
 281  
      * @param pkColumns2
 282  
      */
 283  
     public String getDeleteMNStatement(String table, String[] pkColumns1, String[] pkColumns2)
 284  
     {
 285  
         SqlStatement sql;
 286  
         String result;
 287  
         String[] cols;
 288  
 
 289  
         if (pkColumns2 == null)
 290  
         {
 291  
             cols = pkColumns1;
 292  
         }
 293  
         else
 294  
         {
 295  
             cols = new String[pkColumns1.length + pkColumns2.length];
 296  
             System.arraycopy(pkColumns1, 0, cols, 0, pkColumns1.length);
 297  
             System.arraycopy(pkColumns2, 0, cols, pkColumns1.length, pkColumns2.length);
 298  
         }
 299  
 
 300  
         sql = new SqlDeleteMNStatement(table, cols, logger);
 301  
         result = sql.getStatement();
 302  
 
 303  
         if (logger.isDebugEnabled())
 304  
         {
 305  
             logger.debug("SQL:" + result);
 306  
         }
 307  
         return result;
 308  
     }
 309  
 
 310  
     /**
 311  
      * generate a select-Statement according to query
 312  
      * @param query the Query
 313  
      * @param cld the ClassDescriptor
 314  
      */
 315  
     public SelectStatement getSelectStatementDep(Query query, ClassDescriptor cld)
 316  
     {
 317  
         // TODO: Why do we need this method?
 318  
         return getPreparedSelectStatement(query, cld);
 319  
     }
 320  
 
 321  
     /**
 322  
      * @param crit Selection criteria
 323  
      *
 324  
      * 26/06/99 Change statement to a StringBuffer for efficiency
 325  
      */
 326  
     public String asSQLStatement(Criteria crit, ClassDescriptor cld)
 327  
     {
 328  
         Enumeration e = crit.getElements();
 329  
         StringBuffer statement = new StringBuffer();
 330  
         while (e.hasMoreElements())
 331  
         {
 332  
             Object o = e.nextElement();
 333  
             if (o instanceof Criteria)
 334  
             {
 335  
                 String addAtStart;
 336  
                 String addAtEnd;
 337  
                 Criteria pc = (Criteria) o;
 338  
                 // need to add parenthesises?
 339  
                 if (pc.isEmbraced())
 340  
                 {
 341  
                     addAtStart = " (";
 342  
                     addAtEnd = ") ";
 343  
                 }
 344  
                 else
 345  
                 {
 346  
                     addAtStart = "";
 347  
                     addAtEnd = "";
 348  
                 }
 349  
 
 350  
                 switch (pc.getType())
 351  
                 {
 352  
                     case (Criteria.OR) :
 353  
                         {
 354  
                             statement.append(" OR ").append(addAtStart);
 355  
                             statement.append(asSQLStatement(pc, cld));
 356  
                             statement.append(addAtEnd);
 357  
                             break;
 358  
                         }
 359  
                     case (Criteria.AND) :
 360  
                         {
 361  
                             statement.insert(0, "( ");
 362  
                             statement.append(") ");
 363  
                             statement.append(" AND ").append(addAtStart);
 364  
                             statement.append(asSQLStatement(pc, cld));
 365  
                             statement.append(addAtEnd);
 366  
                             break;
 367  
                         }
 368  
                 }
 369  
             }
 370  
             else
 371  
             {
 372  
                 SelectionCriteria c = (SelectionCriteria) o;
 373  
                 if (statement.length() == 0)
 374  
                 {
 375  
                     statement.append(asSQLClause(c, cld));
 376  
                 }
 377  
                 else
 378  
                 {
 379  
                     statement.insert(0, "(");
 380  
                     statement.append(") ");
 381  
                     statement.append(" AND ");
 382  
                     statement.append(asSQLClause(c, cld));
 383  
                 }
 384  
             }
 385  
         } // while
 386  
         if (statement.length() == 0)
 387  
         {
 388  
             return null;
 389  
         }
 390  
         return statement.toString();
 391  
     }
 392  
 
 393  
     /**
 394  
      * Answer the SQL-Clause for a SelectionCriteria
 395  
      *
 396  
      * @param c SelectionCriteria
 397  
      * @param cld ClassDescriptor
 398  
      */
 399  
     protected String asSQLClause(SelectionCriteria c, ClassDescriptor cld)
 400  
     {
 401  
         if (c instanceof FieldCriteria)
 402  
             return toSQLClause((FieldCriteria) c, cld);
 403  
 
 404  
         if (c instanceof NullCriteria)
 405  
             return toSQLClause((NullCriteria) c);
 406  
 
 407  
         if (c instanceof BetweenCriteria)
 408  
             return toSQLClause((BetweenCriteria) c, cld);
 409  
 
 410  
         if (c instanceof InCriteria)
 411  
             return toSQLClause((InCriteria) c);
 412  
 
 413  
         if (c instanceof SqlCriteria)
 414  
             return toSQLClause((SqlCriteria) c);
 415  
 
 416  
         if (c instanceof ExistsCriteria)
 417  
             return toSQLClause((ExistsCriteria) c, cld);
 418  
 
 419  
         return toSQLClause(c, cld);
 420  
     }
 421  
 
 422  
     private String toSqlClause(Object attributeOrQuery, ClassDescriptor cld)
 423  
     {
 424  
         String result;
 425  
 
 426  
         if (attributeOrQuery instanceof Query)
 427  
         {
 428  
             Query q = (Query) attributeOrQuery;
 429  
             result = getPreparedSelectStatement(q, cld.getRepository().getDescriptorFor(q.getSearchClass()))
 430  
                     .getStatement();
 431  
         }
 432  
         else
 433  
         {
 434  
            result = (String)attributeOrQuery;
 435  
         }
 436  
 
 437  
         return result;
 438  
     }
 439  
 
 440  
     /**
 441  
      * Answer the SQL-Clause for a NullCriteria
 442  
      *
 443  
      * @param c NullCriteria
 444  
      */
 445  
     private String toSQLClause(NullCriteria c)
 446  
     {
 447  
         String colName = (String)c.getAttribute();
 448  
         return colName + c.getClause();
 449  
     }
 450  
 
 451  
     /**
 452  
      * Answer the SQL-Clause for a FieldCriteria
 453  
      *
 454  
      * @param c FieldCriteria
 455  
      * @param cld ClassDescriptor
 456  
      */
 457  
     private String toSQLClause(FieldCriteria c, ClassDescriptor cld)
 458  
     {
 459  
         String colName = toSqlClause(c.getAttribute(), cld);
 460  
         return colName + c.getClause() + c.getValue();
 461  
     }
 462  
 
 463  
     /**
 464  
      * Answer the SQL-Clause for a BetweenCriteria
 465  
      *
 466  
      * @param c BetweenCriteria
 467  
      * @param cld ClassDescriptor
 468  
      */
 469  
     private String toSQLClause(BetweenCriteria c, ClassDescriptor cld)
 470  
     {
 471  
         String colName = toSqlClause(c.getAttribute(), cld);
 472  
         return colName + c.getClause() + " ? AND ? ";
 473  
     }
 474  
 
 475  
     /**
 476  
      * Answer the SQL-Clause for an InCriteria
 477  
      *
 478  
      * @param c SelectionCriteria
 479  
      */
 480  
     private String toSQLClause(InCriteria c)
 481  
     {
 482  
         StringBuffer buf = new StringBuffer();
 483  
         Collection values = (Collection) c.getValue();
 484  
         int size = values.size();
 485  
 
 486  
         buf.append(c.getAttribute());
 487  
         buf.append(c.getClause());
 488  
         buf.append("(");
 489  
         for (int i = 0; i < size - 1; i++)
 490  
         {
 491  
             buf.append("?,");
 492  
         }
 493  
         buf.append("?)");
 494  
         return buf.toString();
 495  
     }
 496  
 
 497  
     /**
 498  
      * Answer the SQL-Clause for a SelectionCriteria
 499  
      *
 500  
      * @param c SelectionCriteria
 501  
      * @param cld ClassDescriptor
 502  
      */
 503  
     private String toSQLClause(SelectionCriteria c, ClassDescriptor cld)
 504  
     {
 505  
         String colName = toSqlClause(c.getAttribute(), cld);
 506  
         return colName + c.getClause() + " ? ";
 507  
     }
 508  
 
 509  
     /**
 510  
      * Answer the SQL-Clause for a SqlCriteria
 511  
      *
 512  
      * @param c SqlCriteria
 513  
      */
 514  
     private String toSQLClause(SqlCriteria c)
 515  
     {
 516  
         return c.getClause();
 517  
     }
 518  
 
 519  
     /**
 520  
      * Answer the SQL-Clause for an ExistsCriteria
 521  
      *
 522  
      * @param c ExistsCriteria
 523  
      * @param cld ClassDescriptor
 524  
      */
 525  
     private String toSQLClause(ExistsCriteria c, ClassDescriptor cld)
 526  
     {
 527  
         StringBuffer buf = new StringBuffer();
 528  
         Query subQuery = (Query) c.getValue();
 529  
 
 530  
         buf.append(c.getClause());
 531  
         buf.append(" (");
 532  
 
 533  
         // If it's a proper call
 534  
         if (cld != null)
 535  
         {
 536  
             buf.append(
 537  
                 getPreparedSelectStatement(
 538  
                     subQuery,
 539  
                     cld.getRepository().getDescriptorFor(subQuery.getSearchClass())));
 540  
 
 541  
             // Otherwise it's most likely a call to toString()
 542  
         }
 543  
         else
 544  
         {
 545  
             buf.append(subQuery);
 546  
         }
 547  
 
 548  
         buf.append(")");
 549  
         return buf.toString();
 550  
     }
 551  
 
 552  
     /**
 553  
      * generate a prepared DELETE-Statement according to query
 554  
      * @param query the Query
 555  
      * @param cld the ClassDescriptor
 556  
      */
 557  
     public SqlStatement getPreparedDeleteStatement(Query query, ClassDescriptor cld)
 558  
     {
 559  
         return new SqlDeleteByQuery(m_platform, cld, query, logger);
 560  
     }
 561  
 
 562  
     /* (non-Javadoc)
 563  
      * @see org.apache.ojb.broker.accesslayer.sql.SqlGenerator#getPlatform()
 564  
      */
 565  
     public Platform getPlatform()
 566  
     {
 567  
         return m_platform;
 568  
     }
 569  
 
 570  
     /**
 571  
      * Returns the {@link SqlForClass} instance for
 572  
      * the given class descriptor.
 573  
      *
 574  
      * @param cld The class descriptor.
 575  
      * @return The {@link SqlForClass}.
 576  
      */
 577  
     protected SqlForClass getSqlForClass(ClassDescriptor cld)
 578  
     {
 579  
         SqlForClass result = (SqlForClass) sqlForClass.get(cld);
 580  
         if(result == null)
 581  
         {
 582  
             result = newInstanceSqlForClass();
 583  
             sqlForClass.put(cld, result);
 584  
         }
 585  
         return result;
 586  
     }
 587  
 
 588  
     /**
 589  
      * User who want to extend this implementation can override this method to use
 590  
      * their own (extended) version of
 591  
      * {@link org.apache.ojb.broker.accesslayer.sql.SqlGeneratorDefaultImpl.SqlForClass}.
 592  
      *
 593  
      * @return A new instance.
 594  
      */
 595  
     protected SqlForClass newInstanceSqlForClass()
 596  
     {
 597  
         return new SqlForClass();
 598  
     }
 599  
 
 600  
     //===================================================================
 601  
     // inner class
 602  
     //===================================================================
 603  
 
 604  
     /**
 605  
      * This class serves as a cache for sql-Statements
 606  
      * used for persistence operations.
 607  
      */
 608  
     public static class SqlForClass
 609  
     {
 610  
         private SqlStatement deleteSql;
 611  
         private SqlStatement insertSql;
 612  
         private SqlStatement updateSql;
 613  
         private SelectStatement selectByPKSql;
 614  
         private SqlStatement selectExists;
 615  
 
 616  
         public SqlStatement getDeleteSql()
 617  
         {
 618  
             return deleteSql;
 619  
         }
 620  
 
 621  
         public void setDeleteSql(SqlStatement deleteSql)
 622  
         {
 623  
             this.deleteSql = deleteSql;
 624  
         }
 625  
 
 626  
         public SqlStatement getInsertSql()
 627  
         {
 628  
             return insertSql;
 629  
         }
 630  
 
 631  
         public void setInsertSql(SqlStatement insertSql)
 632  
         {
 633  
             this.insertSql = insertSql;
 634  
         }
 635  
 
 636  
         public SqlStatement getUpdateSql()
 637  
         {
 638  
             return updateSql;
 639  
         }
 640  
 
 641  
         public void setUpdateSql(SqlStatement updateSql)
 642  
         {
 643  
             this.updateSql = updateSql;
 644  
         }
 645  
 
 646  
         public SelectStatement getSelectByPKSql()
 647  
         {
 648  
             return selectByPKSql;
 649  
         }
 650  
 
 651  
         public void setSelectByPKSql(SelectStatement selectByPKSql)
 652  
         {
 653  
             this.selectByPKSql = selectByPKSql;
 654  
         }
 655  
 
 656  
         public SqlStatement getSelectExists()
 657  
         {
 658  
             return selectExists;
 659  
         }
 660  
 
 661  
         public void setSelectExists(SqlStatement selectExists)
 662  
         {
 663  
             this.selectExists = selectExists;
 664  
         }
 665  
     }
 666  
 
 667  
 }