View Javadoc
1   /*
2    * Prometheus: Application Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * 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, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.prometheus.database;
18  
19  import io.github.tonywasher.joceanus.gordianknot.util.GordianUtilities;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
21  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
22  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
23  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
24  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
25  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRate;
26  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
27  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusUnits;
28  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
29  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusBinaryColumn;
30  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusBooleanColumn;
31  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusDateColumn;
32  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusIdColumn;
33  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusIntegerColumn;
34  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusLongColumn;
35  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusMoneyColumn;
36  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusPriceColumn;
37  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusRateColumn;
38  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusRatioColumn;
39  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusReferenceColumn;
40  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusStringColumn;
41  import io.github.tonywasher.joceanus.prometheus.database.PrometheusColumnDefinition.PrometheusUnitsColumn;
42  import io.github.tonywasher.joceanus.prometheus.exc.PrometheusLogicException;
43  
44  import java.sql.PreparedStatement;
45  import java.sql.ResultSet;
46  import java.sql.SQLException;
47  import java.util.ArrayList;
48  import java.util.HashMap;
49  import java.util.Iterator;
50  import java.util.List;
51  import java.util.Map;
52  
53  /**
54   * Database field definition class. Maps each dataType to a database field.
55   */
56  public class PrometheusTableDefinition {
57      /**
58       * The index prefix.
59       */
60      private static final String PREFIX_INDEX = "idx_";
61  
62      /**
63       * The quote string.
64       */
65      protected static final String QUOTE_STRING = "\"";
66  
67      /**
68       * The Descending string.
69       */
70      protected static final String STR_DESC = " DESC";
71  
72      /**
73       * The Buffer length.
74       */
75      private static final int BUFFER_LEN = 1000;
76  
77      /**
78       * The Table name.
79       */
80      private final String theTableName;
81  
82      /**
83       * The Database driver.
84       */
85      private final PrometheusJDBCDriver theDriver;
86  
87      /**
88       * The Column Definitions.
89       */
90      private final List<PrometheusColumnDefinition> theList;
91  
92      /**
93       * The Sort List.
94       */
95      private final List<PrometheusColumnDefinition> theSortList;
96  
97      /**
98       * Are we sorting on a reference column.
99       */
100     private boolean sortOnReference;
101 
102     /**
103      * The array list for the columns.
104      */
105     private final Map<MetisDataFieldId, PrometheusColumnDefinition> theMap;
106 
107     /**
108      * The prepared statement for the insert/update.
109      */
110     private PreparedStatement theStatement;
111 
112     /**
113      * Constructor.
114      *
115      * @param pDriver the driver
116      * @param pName   the table name
117      */
118     protected PrometheusTableDefinition(final PrometheusJDBCDriver pDriver,
119                                         final String pName) {
120         /* Record the name and driver */
121         theTableName = pName;
122         theDriver = pDriver;
123 
124         /* Create the column list */
125         theList = new ArrayList<>();
126 
127         /* Create the sort list */
128         theSortList = new ArrayList<>();
129 
130         /* Create the initial column map */
131         theMap = new HashMap<>();
132 
133         /* Add an Id column */
134         theList.add(new PrometheusIdColumn(this));
135     }
136 
137     /**
138      * Obtain the table name.
139      *
140      * @return the table name
141      */
142     protected String getTableName() {
143         return theTableName;
144     }
145 
146     /**
147      * Obtain the column map.
148      *
149      * @return the map
150      */
151     protected Map<MetisDataFieldId, PrometheusColumnDefinition> getMap() {
152         return theMap;
153     }
154 
155     /**
156      * Is the table indexed.
157      *
158      * @return true/false
159      */
160     protected boolean isIndexed() {
161         return !theSortList.isEmpty();
162     }
163 
164     /**
165      * Column Definitions array.
166      *
167      * @return the columns
168      */
169     protected List<PrometheusColumnDefinition> getColumns() {
170         return theList;
171     }
172 
173     /**
174      * Sort List.
175      *
176      * @return the sort list
177      */
178     protected List<PrometheusColumnDefinition> getSortList() {
179         return theSortList;
180     }
181 
182     /**
183      * Obtain the driver.
184      *
185      * @return the driver
186      */
187     protected PrometheusJDBCDriver getDriver() {
188         return theDriver;
189     }
190 
191     /**
192      * Note that we have a sort on reference.
193      */
194     protected void setSortOnReference() {
195         sortOnReference = true;
196     }
197 
198     /**
199      * Add a reference column.
200      *
201      * @param pId  the column id
202      * @param pRef the reference table
203      * @return the reference column
204      */
205     public PrometheusReferenceColumn addReferenceColumn(final MetisDataFieldId pId,
206                                                         final String pRef) {
207         /* Create the new reference column */
208         final PrometheusReferenceColumn myColumn = new PrometheusReferenceColumn(this, pId, pRef);
209 
210         /* Add it to the list and return it */
211         theList.add(myColumn);
212         return myColumn;
213     }
214 
215     /**
216      * Add a reference column, which can be null.
217      *
218      * @param pId  the column id
219      * @param pRef the reference table
220      * @return the reference column
221      */
222     public PrometheusReferenceColumn addNullReferenceColumn(final MetisDataFieldId pId,
223                                                             final String pRef) {
224         final PrometheusReferenceColumn myColumn = addReferenceColumn(pId, pRef);
225         myColumn.setNullable();
226         return myColumn;
227     }
228 
229     /**
230      * Add an integer column.
231      *
232      * @param pId the column id
233      * @return the integer column
234      */
235     public PrometheusIntegerColumn addIntegerColumn(final MetisDataFieldId pId) {
236         /* Create the new integer column */
237         final PrometheusIntegerColumn myColumn = new PrometheusIntegerColumn(this, pId);
238 
239         /* Add it to the list and return it */
240         theList.add(myColumn);
241         return myColumn;
242     }
243 
244     /**
245      * Add an integer column, which can be null.
246      *
247      * @param pId the column id
248      * @return the integer column
249      */
250     public PrometheusIntegerColumn addNullIntegerColumn(final MetisDataFieldId pId) {
251         final PrometheusIntegerColumn myColumn = addIntegerColumn(pId);
252         myColumn.setNullable();
253         return myColumn;
254     }
255 
256     /**
257      * Add a long column.
258      *
259      * @param pId the column id
260      * @return the long column
261      */
262     public PrometheusLongColumn addLongColumn(final MetisDataFieldId pId) {
263         /* Create the new long column */
264         final PrometheusLongColumn myColumn = new PrometheusLongColumn(this, pId);
265 
266         /* Add it to the list and return it */
267         theList.add(myColumn);
268         return myColumn;
269     }
270 
271     /**
272      * Add a long column, which can be null.
273      *
274      * @param pId the column id
275      * @return the long column
276      */
277     public PrometheusLongColumn addNullLongColumn(final MetisDataFieldId pId) {
278         final PrometheusLongColumn myColumn = addLongColumn(pId);
279         myColumn.setNullable();
280         return myColumn;
281     }
282 
283     /**
284      * Add a boolean column.
285      *
286      * @param pId the column id
287      * @return the boolean column
288      */
289     public PrometheusBooleanColumn addBooleanColumn(final MetisDataFieldId pId) {
290         /* Create the new boolean column */
291         final PrometheusBooleanColumn myColumn = new PrometheusBooleanColumn(this, pId);
292 
293         /* Add it to the list and return it */
294         theList.add(myColumn);
295         return myColumn;
296     }
297 
298     /**
299      * Add a boolean column, which can be null.
300      *
301      * @param pId the column id
302      * @return the boolean column
303      */
304     public PrometheusBooleanColumn addNullBooleanColumn(final MetisDataFieldId pId) {
305         final PrometheusBooleanColumn myColumn = addBooleanColumn(pId);
306         myColumn.setNullable();
307         return myColumn;
308     }
309 
310     /**
311      * Add a date column.
312      *
313      * @param pId the column id
314      * @return the date column
315      */
316     public PrometheusDateColumn addDateColumn(final MetisDataFieldId pId) {
317         /* Create the new date column */
318         final PrometheusDateColumn myColumn = new PrometheusDateColumn(this, pId);
319 
320         /* Add it to the list and return it */
321         theList.add(myColumn);
322         return myColumn;
323     }
324 
325     /**
326      * Add a date column, which can be null.
327      *
328      * @param pId the column id
329      * @return the date column
330      */
331     public PrometheusDateColumn addNullDateColumn(final MetisDataFieldId pId) {
332         final PrometheusDateColumn myColumn = addDateColumn(pId);
333         myColumn.setNullable();
334         return myColumn;
335     }
336 
337     /**
338      * Add a money column.
339      *
340      * @param pId the column id
341      * @return the money column
342      */
343     public PrometheusMoneyColumn addMoneyColumn(final MetisDataFieldId pId) {
344         /* Create the new money column */
345         final PrometheusMoneyColumn myColumn = new PrometheusMoneyColumn(this, pId);
346 
347         /* Add it to the list and return it */
348         theList.add(myColumn);
349         return myColumn;
350     }
351 
352     /**
353      * Add a money column, which can be null.
354      *
355      * @param pId the column id
356      * @return the money column
357      */
358     public PrometheusMoneyColumn addNullMoneyColumn(final MetisDataFieldId pId) {
359         final PrometheusMoneyColumn myColumn = addMoneyColumn(pId);
360         myColumn.setNullable();
361         return myColumn;
362     }
363 
364     /**
365      * Add a rate column.
366      *
367      * @param pId the column id
368      * @return the rate column
369      */
370     public PrometheusRateColumn addRateColumn(final MetisDataFieldId pId) {
371         /* Create the new rate column */
372         final PrometheusRateColumn myColumn = new PrometheusRateColumn(this, pId);
373 
374         /* Add it to the list and return it */
375         theList.add(myColumn);
376         return myColumn;
377     }
378 
379     /**
380      * Add a rate column, which can be null.
381      *
382      * @param pId the column id
383      * @return the rate column
384      */
385     public PrometheusRateColumn addNullRateColumn(final MetisDataFieldId pId) {
386         final PrometheusRateColumn myColumn = addRateColumn(pId);
387         myColumn.setNullable();
388         return myColumn;
389     }
390 
391     /**
392      * Add a rate column.
393      *
394      * @param pId the column id
395      * @return the rate column
396      */
397     public PrometheusRatioColumn addRatioColumn(final MetisDataFieldId pId) {
398         /* Create the new rate column */
399         final PrometheusRatioColumn myColumn = new PrometheusRatioColumn(this, pId);
400 
401         /* Add it to the list and return it */
402         theList.add(myColumn);
403         return myColumn;
404     }
405 
406     /**
407      * Add a rate column, which can be null.
408      *
409      * @param pId the column id
410      * @return the rate column
411      */
412     public PrometheusRatioColumn addNullRatioColumn(final MetisDataFieldId pId) {
413         final PrometheusRatioColumn myColumn = addRatioColumn(pId);
414         myColumn.setNullable();
415         return myColumn;
416     }
417 
418     /**
419      * Add a binary column.
420      *
421      * @param pId     the column id
422      * @param pLength the underlying (character) length
423      * @return the binary column
424      */
425     public PrometheusBinaryColumn addBinaryColumn(final MetisDataFieldId pId,
426                                                   final int pLength) {
427         /* Create the new binary column */
428         final PrometheusBinaryColumn myColumn = new PrometheusBinaryColumn(this, pId, pLength);
429 
430         /* Add it to the list and return it */
431         theList.add(myColumn);
432         return myColumn;
433     }
434 
435     /**
436      * Add a binary column, which can be null.
437      *
438      * @param pId     the column id
439      * @param pLength the underlying (character) length
440      * @return the binary column
441      */
442     public PrometheusBinaryColumn addNullBinaryColumn(final MetisDataFieldId pId,
443                                                       final int pLength) {
444         final PrometheusBinaryColumn myColumn = addBinaryColumn(pId, pLength);
445         myColumn.setNullable();
446         return myColumn;
447     }
448 
449     /**
450      * Add an encrypted column.
451      *
452      * @param pId     the column id
453      * @param pLength the underlying (character) length
454      * @return the binary column
455      */
456     public PrometheusBinaryColumn addEncryptedColumn(final MetisDataFieldId pId,
457                                                      final int pLength) {
458         /* Create the new binary column */
459         final PrometheusBinaryColumn myColumn = new PrometheusBinaryColumn(this, pId, GordianUtilities.getKeySetEncryptionLength(pLength));
460 
461         /* Add it to the list and return it */
462         theList.add(myColumn);
463         return myColumn;
464     }
465 
466     /**
467      * Add an encrypted column, which can be null.
468      *
469      * @param pId     the column id
470      * @param pLength the underlying (character) length
471      * @return the binary column
472      */
473     public PrometheusBinaryColumn addNullEncryptedColumn(final MetisDataFieldId pId,
474                                                          final int pLength) {
475         final PrometheusBinaryColumn myColumn = addEncryptedColumn(pId, pLength);
476         myColumn.setNullable();
477         return myColumn;
478     }
479 
480     /**
481      * Add a string column.
482      *
483      * @param pId     the column id
484      * @param pLength the character length
485      * @return the binary column
486      */
487     public PrometheusStringColumn addStringColumn(final MetisDataFieldId pId,
488                                                   final int pLength) {
489         /* Create the new string column */
490         final PrometheusStringColumn myColumn = new PrometheusStringColumn(this, pId, pLength);
491 
492         /* Add it to the list and return it */
493         theList.add(myColumn);
494         return myColumn;
495     }
496 
497     /**
498      * Add a string column, which can be null.
499      *
500      * @param pId     the column id
501      * @param pLength the character length
502      * @return the binary column
503      */
504     public PrometheusStringColumn addNullStringColumn(final MetisDataFieldId pId,
505                                                       final int pLength) {
506         final PrometheusStringColumn myColumn = addStringColumn(pId, pLength);
507         myColumn.setNullable();
508         return myColumn;
509     }
510 
511     /**
512      * Locate reference.
513      *
514      * @param pTables the list of defined tables
515      */
516     protected void resolveReferences(final List<PrometheusTableDataItem<?>> pTables) {
517         /* Create the iterator */
518         final Iterator<PrometheusColumnDefinition> myIterator = theList.iterator();
519 
520         /* Loop through the columns */
521         while (myIterator.hasNext()) {
522             final PrometheusColumnDefinition myDef = myIterator.next();
523             myDef.locateReference(pTables);
524         }
525     }
526 
527     /**
528      * Load results.
529      *
530      * @param pResults the result set
531      * @throws SQLException on error
532      */
533     protected void loadResults(final ResultSet pResults) throws SQLException {
534         /* clear values */
535         clearValues();
536 
537         /* Create the iterator */
538         final Iterator<PrometheusColumnDefinition> myIterator = theList.iterator();
539         int myIndex = 1;
540 
541         /* Loop through the columns */
542         while (myIterator.hasNext()) {
543             final PrometheusColumnDefinition myDef = myIterator.next();
544             myDef.loadValue(pResults, myIndex++);
545         }
546     }
547 
548     /**
549      * Build column error string.
550      *
551      * @param pCol the column definition.
552      * @return the error string
553      */
554     private String getColumnError(final PrometheusColumnDefinition pCol) {
555         return "Column " + pCol.getColumnName() + " in table " + theTableName;
556     }
557 
558     /**
559      * Insert values.
560      *
561      * @param pStmt the statement
562      * @throws SQLException     on error
563      * @throws OceanusException on error
564      */
565     protected void insertValues(final PreparedStatement pStmt) throws SQLException, OceanusException {
566         /* Store the Statement */
567         theStatement = pStmt;
568 
569         /* Create the iterator */
570         final Iterator<PrometheusColumnDefinition> myIterator = theList.iterator();
571         int myIndex = 1;
572 
573         /* Loop through the columns */
574         while (myIterator.hasNext()) {
575             final PrometheusColumnDefinition myDef = myIterator.next();
576 
577             /* Reject if the value is not set */
578             if (!myDef.isValueSet()) {
579                 throw new PrometheusLogicException(getColumnError(myDef) + " has no value for insert");
580             }
581 
582             myDef.storeValue(theStatement, myIndex++);
583         }
584     }
585 
586     /**
587      * Update values.
588      *
589      * @param pStmt the statement
590      * @throws SQLException on error
591      */
592     protected void updateValues(final PreparedStatement pStmt) throws SQLException {
593         PrometheusColumnDefinition myId = null;
594 
595         /* Store the Statement */
596         theStatement = pStmt;
597 
598         /* Create the iterator */
599         final Iterator<PrometheusColumnDefinition> myIterator = theList.iterator();
600         int myIndex = 1;
601 
602         /* Loop through the columns */
603         while (myIterator.hasNext()) {
604             final PrometheusColumnDefinition myDef = myIterator.next();
605 
606             /* If this is the Id record */
607             if (myDef instanceof PrometheusIdColumn) {
608                 /* Remember the column */
609                 myId = myDef;
610 
611                 /* Store value if it has been set */
612             } else if (myDef.isValueSet()) {
613                 myDef.storeValue(theStatement, myIndex++);
614             }
615         }
616 
617         /* Store the Id */
618         if (myId != null) {
619             myId.storeValue(theStatement, myIndex);
620         }
621     }
622 
623     /**
624      * Clear values for table.
625      */
626     protected void clearValues() {
627         /* Loop over the Column Definitions */
628         for (PrometheusColumnDefinition myDef : theList) {
629             /* Clear value */
630             myDef.clearValue();
631         }
632     }
633 
634     /**
635      * Get Integer value for column.
636      *
637      * @param pId the column id
638      * @return the integer value
639      * @throws OceanusException on error
640      */
641     public Integer getIntegerValue(final MetisDataFieldId pId) throws OceanusException {
642         /* Obtain the correct id */
643         final PrometheusColumnDefinition myCol = getColumnForId(pId);
644 
645         /* Reject if this is not an integer column */
646         if (!(myCol instanceof PrometheusIntegerColumn)) {
647             throw new PrometheusLogicException(getColumnError(myCol) + " is not Integer type");
648         }
649 
650         /* Return the value */
651         final PrometheusIntegerColumn myIntCol = (PrometheusIntegerColumn) myCol;
652         return myIntCol.getValue();
653     }
654 
655     /**
656      * Get Long value for column.
657      *
658      * @param pId the column id
659      * @return the long value
660      * @throws OceanusException on error
661      */
662     public Long getLongValue(final MetisDataFieldId pId) throws OceanusException {
663         /* Obtain the correct id */
664         final PrometheusColumnDefinition myCol = getColumnForId(pId);
665 
666         /* Reject if this is not a long column */
667         if (!(myCol instanceof PrometheusLongColumn)) {
668             throw new PrometheusLogicException(getColumnError(myCol) + " is not Long type");
669         }
670 
671         /* Return the value */
672         final PrometheusLongColumn myLongCol = (PrometheusLongColumn) myCol;
673         return myLongCol.getValue();
674     }
675 
676     /**
677      * Get Date value for column.
678      *
679      * @param pId the column id
680      * @return the Date value
681      * @throws OceanusException on error
682      */
683     public OceanusDate getDateValue(final MetisDataFieldId pId) throws OceanusException {
684         /* Obtain the correct id */
685         final PrometheusColumnDefinition myCol = getColumnForId(pId);
686 
687         /* Reject if this is not a date column */
688         if (!(myCol instanceof PrometheusDateColumn)) {
689             throw new PrometheusLogicException(getColumnError(myCol) + " is not Date type");
690         }
691 
692         /* Return the value */
693         final PrometheusDateColumn myDateCol = (PrometheusDateColumn) myCol;
694         return myDateCol.getValue();
695     }
696 
697     /**
698      * Get Boolean value for column.
699      *
700      * @param pId the column id
701      * @return the boolean value
702      * @throws OceanusException on error
703      */
704     public Boolean getBooleanValue(final MetisDataFieldId pId) throws OceanusException {
705         /* Obtain the correct id */
706         final PrometheusColumnDefinition myCol = getColumnForId(pId);
707 
708         /* Reject if this is not a boolean column */
709         if (!(myCol instanceof PrometheusBooleanColumn)) {
710             throw new PrometheusLogicException("Column " + getColumnError(myCol) + " is not Boolean type");
711         }
712 
713         /* Return the value */
714         final PrometheusBooleanColumn myBoolCol = (PrometheusBooleanColumn) myCol;
715         return myBoolCol.getValue();
716     }
717 
718     /**
719      * Get String value for column.
720      *
721      * @param pId the column id
722      * @return the String value
723      * @throws OceanusException on error
724      */
725     public String getStringValue(final MetisDataFieldId pId) throws OceanusException {
726         /* Obtain the correct id */
727         final PrometheusColumnDefinition myCol = getColumnForId(pId);
728 
729         /* Reject if this is not a string column */
730         if (!(myCol instanceof PrometheusStringColumn)) {
731             throw new PrometheusLogicException(getColumnError(myCol) + " is not String type");
732         }
733 
734         /* Return the value */
735         final PrometheusStringColumn myStringCol = (PrometheusStringColumn) myCol;
736         return myStringCol.getValue();
737     }
738 
739     /**
740      * Get Money value for column.
741      *
742      * @param pId        the column id
743      * @param pFormatter the data formatter
744      * @return the Money value
745      * @throws OceanusException on error
746      */
747     public OceanusMoney getMoneyValue(final MetisDataFieldId pId,
748                                       final OceanusDataFormatter pFormatter) throws OceanusException {
749         /* Obtain the correct id */
750         final PrometheusColumnDefinition myCol = getColumnForId(pId);
751 
752         /* Reject if this is not a money column */
753         if (!(myCol instanceof PrometheusMoneyColumn)) {
754             throw new PrometheusLogicException(getColumnError(myCol) + " is not money type");
755         }
756 
757         /* Access the value */
758         final PrometheusMoneyColumn myMoneyCol = (PrometheusMoneyColumn) myCol;
759         return myMoneyCol.getValue(pFormatter);
760     }
761 
762     /**
763      * Get Price value for column.
764      *
765      * @param pId        the column id
766      * @param pFormatter the data formatter
767      * @return the price value
768      * @throws OceanusException on error
769      */
770     public OceanusPrice getPriceValue(final MetisDataFieldId pId,
771                                       final OceanusDataFormatter pFormatter) throws OceanusException {
772         /* Obtain the correct id */
773         final PrometheusColumnDefinition myCol = getColumnForId(pId);
774 
775         /* Reject if this is not a price column */
776         if (!(myCol instanceof PrometheusPriceColumn)) {
777             throw new PrometheusLogicException(getColumnError(myCol) + " is not Price type");
778         }
779 
780         /* Access the value */
781         final PrometheusPriceColumn myPriceCol = (PrometheusPriceColumn) myCol;
782         return myPriceCol.getValue(pFormatter);
783     }
784 
785     /**
786      * Get Rate value for column.
787      *
788      * @param pId        the column id
789      * @param pFormatter the data formatter
790      * @return the rate value
791      * @throws OceanusException on error
792      */
793     public OceanusRate getRateValue(final MetisDataFieldId pId,
794                                     final OceanusDataFormatter pFormatter) throws OceanusException {
795         /* Obtain the correct id */
796         final PrometheusColumnDefinition myCol = getColumnForId(pId);
797 
798         /* Reject if this is not a rate column */
799         if (!(myCol instanceof PrometheusRateColumn)) {
800             throw new PrometheusLogicException(getColumnError(myCol) + " is not Rate type");
801         }
802 
803         /* Access the value */
804         final PrometheusRateColumn myRateCol = (PrometheusRateColumn) myCol;
805         return myRateCol.getValue(pFormatter);
806     }
807 
808     /**
809      * Get Units value for column.
810      *
811      * @param pId        the column id
812      * @param pFormatter the data formatter
813      * @return the Units value
814      * @throws OceanusException on error
815      */
816     public OceanusUnits getUnitsValue(final MetisDataFieldId pId,
817                                       final OceanusDataFormatter pFormatter) throws OceanusException {
818         /* Obtain the correct id */
819         final PrometheusColumnDefinition myCol = getColumnForId(pId);
820 
821         /* Reject if this is not a units column */
822         if (!(myCol instanceof PrometheusUnitsColumn)) {
823             throw new PrometheusLogicException(getColumnError(myCol) + " is not Units type");
824         }
825 
826         /* Access the value */
827         final PrometheusUnitsColumn myUnitsCol = (PrometheusUnitsColumn) myCol;
828         return myUnitsCol.getValue(pFormatter);
829     }
830 
831     /**
832      * Get Ratio value for column.
833      *
834      * @param pId        the column id
835      * @param pFormatter the data formatter
836      * @return the Ratio value
837      * @throws OceanusException on error
838      */
839     public OceanusRatio getRatioValue(final MetisDataFieldId pId,
840                                       final OceanusDataFormatter pFormatter) throws OceanusException {
841         /* Obtain the correct id */
842         final PrometheusColumnDefinition myCol = getColumnForId(pId);
843 
844         /* Reject if this is not a ratio column */
845         if (!(myCol instanceof PrometheusRatioColumn)) {
846             throw new PrometheusLogicException(getColumnError(myCol) + " is not Ratio type");
847         }
848 
849         /* Access the value */
850         final PrometheusRatioColumn myRatioCol = (PrometheusRatioColumn) myCol;
851         return myRatioCol.getValue(pFormatter);
852     }
853 
854     /**
855      * Get Binary value for column.
856      *
857      * @param pId the column id
858      * @return the binary value
859      * @throws OceanusException on error
860      */
861     public byte[] getBinaryValue(final MetisDataFieldId pId) throws OceanusException {
862         /* Obtain the correct id */
863         final PrometheusColumnDefinition myCol = getColumnForId(pId);
864 
865         /* Reject if this is not a string column */
866         if (!(myCol instanceof PrometheusBinaryColumn)) {
867             throw new PrometheusLogicException(getColumnError(myCol) + " is not Binary type");
868         }
869 
870         /* Return the value */
871         final PrometheusBinaryColumn myBinaryCol = (PrometheusBinaryColumn) myCol;
872         return myBinaryCol.getValue();
873     }
874 
875     /**
876      * Set Integer value for column.
877      *
878      * @param pId    the column id
879      * @param pValue the value
880      * @throws OceanusException on error
881      */
882     public void setIntegerValue(final MetisDataFieldId pId,
883                                 final Integer pValue) throws OceanusException {
884         /* Obtain the correct id */
885         final PrometheusColumnDefinition myCol = getColumnForId(pId);
886 
887         /* Reject if this is not an integer column */
888         if (!(myCol instanceof PrometheusIntegerColumn)) {
889             throw new PrometheusLogicException(getColumnError(myCol) + " is not Integer type");
890         }
891 
892         /* Set the value */
893         final PrometheusIntegerColumn myIntCol = (PrometheusIntegerColumn) myCol;
894         myIntCol.setValue(pValue);
895     }
896 
897     /**
898      * Set Long value for column.
899      *
900      * @param pId    the column id
901      * @param pValue the value
902      * @throws OceanusException on error
903      */
904     public void setLongValue(final MetisDataFieldId pId,
905                              final Long pValue) throws OceanusException {
906         /* Obtain the correct id */
907         final PrometheusColumnDefinition myCol = getColumnForId(pId);
908 
909         /* Reject if this is not a long column */
910         if (!(myCol instanceof PrometheusLongColumn)) {
911             throw new PrometheusLogicException(getColumnError(myCol) + " is not Long type");
912         }
913 
914         /* Set the value */
915         final PrometheusLongColumn myLongCol = (PrometheusLongColumn) myCol;
916         myLongCol.setValue(pValue);
917     }
918 
919     /**
920      * Set Boolean value for column.
921      *
922      * @param pId    the column id
923      * @param pValue the value
924      * @throws OceanusException on error
925      */
926     public void setBooleanValue(final MetisDataFieldId pId,
927                                 final Boolean pValue) throws OceanusException {
928         /* Obtain the correct id */
929         final PrometheusColumnDefinition myCol = getColumnForId(pId);
930 
931         /* Reject if this is not a boolean column */
932         if (!(myCol instanceof PrometheusBooleanColumn)) {
933             throw new PrometheusLogicException(getColumnError(myCol) + " is not Boolean type");
934         }
935 
936         /* Set the value */
937         final PrometheusBooleanColumn myBoolCol = (PrometheusBooleanColumn) myCol;
938         myBoolCol.setValue(pValue);
939     }
940 
941     /**
942      * Set Date value for column.
943      *
944      * @param pId    the column id
945      * @param pValue the value
946      * @throws OceanusException on error
947      */
948     public void setDateValue(final MetisDataFieldId pId,
949                              final OceanusDate pValue) throws OceanusException {
950         /* Obtain the correct id */
951         final PrometheusColumnDefinition myCol = getColumnForId(pId);
952 
953         /* Reject if this is not a Date column */
954         if (!(myCol instanceof PrometheusDateColumn)) {
955             throw new PrometheusLogicException(getColumnError(myCol) + " is not Date type");
956         }
957 
958         /* Set the value */
959         final PrometheusDateColumn myDateCol = (PrometheusDateColumn) myCol;
960         myDateCol.setValue(pValue);
961     }
962 
963     /**
964      * Set String value for column.
965      *
966      * @param pId    the column id
967      * @param pValue the value
968      * @throws OceanusException on error
969      */
970     public void setStringValue(final MetisDataFieldId pId,
971                                final String pValue) throws OceanusException {
972         /* Obtain the correct id */
973         final PrometheusColumnDefinition myCol = getColumnForId(pId);
974 
975         /* Reject if this is not a string column */
976         if (!(myCol instanceof PrometheusStringColumn)) {
977             throw new PrometheusLogicException(getColumnError(myCol) + " is not String type");
978         }
979 
980         /* Set the value */
981         final PrometheusStringColumn myStringCol = (PrometheusStringColumn) myCol;
982         myStringCol.setValue(pValue);
983     }
984 
985     /**
986      * Set Binary value for column.
987      *
988      * @param pId    the column id
989      * @param pValue the value
990      * @throws OceanusException on error
991      */
992     public void setBinaryValue(final MetisDataFieldId pId,
993                                final byte[] pValue) throws OceanusException {
994         /* Obtain the correct id */
995         final PrometheusColumnDefinition myCol = getColumnForId(pId);
996 
997         /* Reject if this is not a binary column */
998         if (!(myCol instanceof PrometheusBinaryColumn)) {
999             throw new PrometheusLogicException(getColumnError(myCol) + " is not Binary type");
1000         }
1001 
1002         /* Set the value */
1003         final PrometheusBinaryColumn myBinaryCol = (PrometheusBinaryColumn) myCol;
1004         myBinaryCol.setValue(pValue);
1005     }
1006 
1007     /**
1008      * Set Money value for column.
1009      *
1010      * @param pId    the column id
1011      * @param pValue the value
1012      * @throws OceanusException on error
1013      */
1014     public void setMoneyValue(final MetisDataFieldId pId,
1015                               final OceanusMoney pValue) throws OceanusException {
1016         /* Obtain the correct id */
1017         final PrometheusColumnDefinition myCol = getColumnForId(pId);
1018 
1019         /* Reject if this is not a money column */
1020         if (!(myCol instanceof PrometheusMoneyColumn)) {
1021             throw new PrometheusLogicException(getColumnError(myCol) + " is not Money type");
1022         }
1023 
1024         /* Set the value */
1025         final PrometheusMoneyColumn myMoneyCol = (PrometheusMoneyColumn) myCol;
1026         myMoneyCol.setValue(pValue);
1027     }
1028 
1029     /**
1030      * Set Rate value for column.
1031      *
1032      * @param pId    the column id
1033      * @param pValue the value
1034      * @throws OceanusException on error
1035      */
1036     public void setRateValue(final MetisDataFieldId pId,
1037                              final OceanusRate pValue) throws OceanusException {
1038         /* Obtain the correct id */
1039         final PrometheusColumnDefinition myCol = getColumnForId(pId);
1040 
1041         /* Reject if this is not a rate column */
1042         if (!(myCol instanceof PrometheusRateColumn)) {
1043             throw new PrometheusLogicException(getColumnError(myCol) + " is not Rate type");
1044         }
1045 
1046         /* Set the value */
1047         final PrometheusRateColumn myRateCol = (PrometheusRateColumn) myCol;
1048         myRateCol.setValue(pValue);
1049     }
1050 
1051     /**
1052      * Set Ratio value for column.
1053      *
1054      * @param pId    the column id
1055      * @param pValue the value
1056      * @throws OceanusException on error
1057      */
1058     public void setRatioValue(final MetisDataFieldId pId,
1059                               final OceanusRatio pValue) throws OceanusException {
1060         /* Obtain the correct id */
1061         final PrometheusColumnDefinition myCol = getColumnForId(pId);
1062 
1063         /* Reject if this is not a ratio column */
1064         if (!(myCol instanceof PrometheusRatioColumn)) {
1065             throw new PrometheusLogicException(getColumnError(myCol) + " is not Ratio type");
1066         }
1067 
1068         /* Set the value */
1069         final PrometheusRatioColumn myRatioCol = (PrometheusRatioColumn) myCol;
1070         myRatioCol.setValue(pValue);
1071     }
1072 
1073     /**
1074      * Locate column for id.
1075      *
1076      * @param pId the id of the column
1077      * @return the column
1078      * @throws OceanusException on error
1079      */
1080     private PrometheusColumnDefinition getColumnForId(final MetisDataFieldId pId) throws OceanusException {
1081         /* Access the definition */
1082         final PrometheusColumnDefinition myDef = theMap.get(pId);
1083 
1084         /* Check that the id is in range and present */
1085         if (myDef == null) {
1086             throw new PrometheusLogicException("Invalid Column Id: " + pId + " for " + theTableName);
1087         }
1088 
1089         /* Return the column definition */
1090         return myDef;
1091     }
1092 
1093     /**
1094      * Build the create table string for the table.
1095      *
1096      * @return the SQL string
1097      */
1098     protected String getCreateTableString() {
1099         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1100 
1101         /* Build the initial create */
1102         myBuilder.append("create table ");
1103         addQuoteIfAllowed(myBuilder);
1104         myBuilder.append(theTableName);
1105         addQuoteIfAllowed(myBuilder);
1106         myBuilder.append(" (");
1107 
1108         /* Create the iterator */
1109         final Iterator<PrometheusColumnDefinition> myIterator = theList.iterator();
1110         boolean myFirst = true;
1111 
1112         /* Loop through the columns */
1113         while (myIterator.hasNext()) {
1114             final PrometheusColumnDefinition myDef = myIterator.next();
1115             if (!myFirst) {
1116                 myBuilder.append(", ");
1117             }
1118             myDef.buildCreateString(myBuilder);
1119             myFirst = false;
1120         }
1121 
1122         /* Close the statement and return it */
1123         myBuilder.append(')');
1124         return myBuilder.toString();
1125     }
1126 
1127     /**
1128      * Build the create index string for the table.
1129      *
1130      * @return the SQL string
1131      */
1132     protected String getCreateIndexString() {
1133         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1134 
1135         /* Return null if we are not indexed */
1136         if (!isIndexed()) {
1137             return null;
1138         }
1139 
1140         /* Build the initial create */
1141         myBuilder.append("create index ");
1142         addQuoteIfAllowed(myBuilder);
1143         myBuilder.append(PREFIX_INDEX);
1144         myBuilder.append(theTableName);
1145         addQuoteIfAllowed(myBuilder);
1146         myBuilder.append(" on ");
1147         addQuoteIfAllowed(myBuilder);
1148         myBuilder.append(theTableName);
1149         addQuoteIfAllowed(myBuilder);
1150         myBuilder.append(" (");
1151 
1152         /* Create the iterator */
1153         final Iterator<PrometheusColumnDefinition> myIterator = theSortList.iterator();
1154         boolean myFirst = true;
1155 
1156         /* Loop through the columns */
1157         while (myIterator.hasNext()) {
1158             final PrometheusColumnDefinition myDef = myIterator.next();
1159             if (!myFirst) {
1160                 myBuilder.append(", ");
1161             }
1162             addQuoteIfAllowed(myBuilder);
1163             myBuilder.append(myDef.getColumnName());
1164             addQuoteIfAllowed(myBuilder);
1165             if (myDef.getSortOrder() == PrometheusSortOrder.DESCENDING) {
1166                 myBuilder.append(STR_DESC);
1167             }
1168             myFirst = false;
1169         }
1170 
1171         /* Close the statement and return it */
1172         myBuilder.append(')');
1173         return myBuilder.toString();
1174     }
1175 
1176     /**
1177      * Build the drop table string for the table.
1178      *
1179      * @return the SQL string
1180      */
1181     protected String getDropTableString() {
1182         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1183         myBuilder.append("drop table if exists ");
1184         addQuoteIfAllowed(myBuilder);
1185         myBuilder.append(theTableName);
1186         addQuoteIfAllowed(myBuilder);
1187 
1188         /* Return the command */
1189         return myBuilder.toString();
1190     }
1191 
1192     /**
1193      * Build the drop index string for the table.
1194      *
1195      * @return the SQL string
1196      */
1197     protected String getDropIndexString() {
1198         /* Return null if we are not indexed */
1199         if (!isIndexed() || !theDriver.explicitDropIndex()) {
1200             return null;
1201         }
1202 
1203         /* Build the drop command */
1204         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1205         myBuilder.append("drop index if exists ");
1206         addQuoteIfAllowed(myBuilder);
1207         myBuilder.append(PREFIX_INDEX);
1208         myBuilder.append(theTableName);
1209         addQuoteIfAllowed(myBuilder);
1210         if (!PrometheusJDBCDriver.POSTGRESQL.equals(theDriver)) {
1211             myBuilder.append(" on ");
1212             addQuoteIfAllowed(myBuilder);
1213             myBuilder.append(theTableName);
1214             addQuoteIfAllowed(myBuilder);
1215         }
1216 
1217         /* Return the command */
1218         return myBuilder.toString();
1219     }
1220 
1221     /**
1222      * Build the load string for a list of columns.
1223      *
1224      * @return the SQL string
1225      */
1226     protected String getLoadString() {
1227         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1228 
1229         /* Build the initial select */
1230         myBuilder.append("select ");
1231 
1232         /* Create the iterator */
1233         final Iterator<PrometheusColumnDefinition> myIterator = theList.iterator();
1234         boolean myFirst = true;
1235 
1236         /* Loop through the columns */
1237         while (myIterator.hasNext()) {
1238             final PrometheusColumnDefinition myDef = myIterator.next();
1239             if (!myFirst) {
1240                 myBuilder.append(", ");
1241             }
1242             if (sortOnReference) {
1243                 myBuilder.append("a.");
1244             }
1245             addQuoteIfAllowed(myBuilder);
1246             myBuilder.append(myDef.getColumnName());
1247             addQuoteIfAllowed(myBuilder);
1248             myFirst = false;
1249         }
1250 
1251         /* Close the statement */
1252         myBuilder.append(" from ");
1253         addQuoteIfAllowed(myBuilder);
1254         myBuilder.append(theTableName);
1255         addQuoteIfAllowed(myBuilder);
1256         if (sortOnReference) {
1257             myBuilder.append(" a");
1258         }
1259 
1260         /* If we are indexed */
1261         if (isIndexed()) {
1262             /* Add Joins */
1263             if (sortOnReference) {
1264                 myBuilder.append(getJoinString('a', 1));
1265             }
1266 
1267             /* Add the order clause */
1268             myBuilder.append(" order by ");
1269 
1270             /* Build the order string */
1271             myBuilder.append(getOrderString('a', 0));
1272         }
1273 
1274         return myBuilder.toString();
1275     }
1276 
1277     /**
1278      * Build the Join string for the list of columns.
1279      *
1280      * @param pChar   the character for this table
1281      * @param pOffset the join offset
1282      * @return the SQL string
1283      */
1284     protected String getJoinString(final char pChar,
1285                                    final Integer pOffset) {
1286         /* Loop through the columns */
1287         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1288         for (PrometheusColumnDefinition myDef : theSortList) {
1289             /* Access next column and skip if not reference column */
1290             if (!(myDef instanceof PrometheusReferenceColumn)) {
1291                 continue;
1292             }
1293 
1294             /* Add the join */
1295             final PrometheusReferenceColumn myCol = (PrometheusReferenceColumn) myDef;
1296             myCol.buildJoinString(myBuilder, pChar, pOffset);
1297         }
1298 
1299         return myBuilder.toString();
1300     }
1301 
1302     /**
1303      * Build the Order string for the list of columns.
1304      *
1305      * @param pChar   the character for this table
1306      * @param pOffset the join offset
1307      * @return the SQL string
1308      */
1309     protected String getOrderString(final char pChar,
1310                                     final Integer pOffset) {
1311         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1312 
1313         /* Create the iterator */
1314         final Iterator<PrometheusColumnDefinition> myIterator = theSortList.iterator();
1315         boolean myFirst = true;
1316 
1317         /* Loop through the columns */
1318         while (myIterator.hasNext()) {
1319             final PrometheusColumnDefinition myDef = myIterator.next();
1320             /* Handle secondary columns */
1321             if (!myFirst) {
1322                 myBuilder.append(", ");
1323             }
1324 
1325             /* If we are using prefixes */
1326             if (sortOnReference || pChar > 'a') {
1327                 /* If this is a reference column */
1328                 if (myDef instanceof PrometheusReferenceColumn myCol) {
1329                     /* Handle Reference column */
1330                     myCol.buildOrderString(myBuilder, pOffset + 1);
1331                 } else {
1332                     /* Handle standard column with prefix */
1333                     myBuilder.append(pChar);
1334                     myBuilder.append(".");
1335                     addQuoteIfAllowed(myBuilder);
1336                     myBuilder.append(myDef.getColumnName());
1337                     addQuoteIfAllowed(myBuilder);
1338                     if (myDef.getSortOrder() == PrometheusSortOrder.DESCENDING) {
1339                         myBuilder.append(STR_DESC);
1340                     }
1341                 }
1342             } else {
1343                 /* Handle standard column */
1344                 addQuoteIfAllowed(myBuilder);
1345                 myBuilder.append(myDef.getColumnName());
1346                 addQuoteIfAllowed(myBuilder);
1347                 if (myDef.getSortOrder() == PrometheusSortOrder.DESCENDING) {
1348                     myBuilder.append(STR_DESC);
1349                 }
1350             }
1351 
1352             /* Note secondary columns */
1353             myFirst = false;
1354         }
1355 
1356         return myBuilder.toString();
1357     }
1358 
1359     /**
1360      * Build the insert string for a list of columns.
1361      *
1362      * @return the SQL string
1363      */
1364     protected String getInsertString() {
1365         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1366         final StringBuilder myValues = new StringBuilder(BUFFER_LEN);
1367 
1368         /* Build the initial insert */
1369         myBuilder.append("insert into ");
1370         addQuoteIfAllowed(myBuilder);
1371         myBuilder.append(theTableName);
1372         addQuoteIfAllowed(myBuilder);
1373         myBuilder.append(" (");
1374 
1375         /* Create the iterator */
1376         final Iterator<PrometheusColumnDefinition> myIterator = theList.iterator();
1377         boolean myFirst = true;
1378 
1379         /* Loop through the columns */
1380         while (myIterator.hasNext()) {
1381             final PrometheusColumnDefinition myDef = myIterator.next();
1382             if (!myFirst) {
1383                 myBuilder.append(", ");
1384                 myValues.append(", ");
1385             }
1386             addQuoteIfAllowed(myBuilder);
1387             myBuilder.append(myDef.getColumnName());
1388             addQuoteIfAllowed(myBuilder);
1389             myValues.append('?');
1390             myFirst = false;
1391         }
1392 
1393         /* Close the statement and return it */
1394         myBuilder.append(") values(");
1395         myBuilder.append(myValues);
1396         myBuilder.append(')');
1397         return myBuilder.toString();
1398     }
1399 
1400     /**
1401      * Build the update string for a list of columns.
1402      *
1403      * @return the SQL string
1404      * @throws OceanusException on error
1405      */
1406     protected String getUpdateString() throws OceanusException {
1407         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1408 
1409         /* Build the initial update */
1410         myBuilder.append("update ");
1411         addQuoteIfAllowed(myBuilder);
1412         myBuilder.append(theTableName);
1413         addQuoteIfAllowed(myBuilder);
1414         myBuilder.append(" set ");
1415 
1416         /* Create the iterator */
1417         final Iterator<PrometheusColumnDefinition> myIterator = theList.iterator();
1418         PrometheusColumnDefinition myId = null;
1419         boolean myFirst = true;
1420 
1421         /* Loop through the columns */
1422         while (myIterator.hasNext()) {
1423             final PrometheusColumnDefinition myDef = myIterator.next();
1424 
1425             /* If this is the Id record */
1426             if (myDef instanceof PrometheusIdColumn) {
1427                 /* Reject if the value is not set */
1428                 if (!myDef.isValueSet()) {
1429                     throw new PrometheusLogicException(getColumnError(myDef) + " has no value for update");
1430                 }
1431 
1432                 /* Remember the column */
1433                 myId = myDef;
1434 
1435                 /* If this column is to be updated */
1436             } else if (myDef.isValueSet()) {
1437                 /* Add the update of this column */
1438                 if (!myFirst) {
1439                     myBuilder.append(", ");
1440                 }
1441                 addQuoteIfAllowed(myBuilder);
1442                 myBuilder.append(myDef.getColumnName());
1443                 addQuoteIfAllowed(myBuilder);
1444                 myBuilder.append("=?");
1445                 myFirst = false;
1446             }
1447         }
1448 
1449         /* If we have no values then just return null */
1450         if (myFirst || myId == null) {
1451             return null;
1452         }
1453 
1454         /* Close the statement and return it */
1455         myBuilder.append(" where ");
1456         addQuoteIfAllowed(myBuilder);
1457         myBuilder.append(myId.getColumnName());
1458         addQuoteIfAllowed(myBuilder);
1459         myBuilder.append("=?");
1460         return myBuilder.toString();
1461     }
1462 
1463     /**
1464      * Build the delete string for a table.
1465      *
1466      * @return the SQL string
1467      */
1468     protected String getDeleteString() {
1469         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1470 
1471         /* Build the initial delete */
1472         myBuilder.append("delete from ");
1473         addQuoteIfAllowed(myBuilder);
1474         myBuilder.append(theTableName);
1475         addQuoteIfAllowed(myBuilder);
1476         myBuilder.append(" where ");
1477 
1478         /* Access the id definition */
1479         final PrometheusColumnDefinition myId = theList.get(0);
1480 
1481         /* Build the rest of the command */
1482         addQuoteIfAllowed(myBuilder);
1483         myBuilder.append(myId.getColumnName());
1484         addQuoteIfAllowed(myBuilder);
1485         myBuilder.append("=?");
1486         return myBuilder.toString();
1487     }
1488 
1489     /**
1490      * Build the purge string for a table.
1491      *
1492      * @return the SQL string
1493      */
1494     protected String getPurgeString() {
1495         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1496 
1497         /* Build the initial delete */
1498         myBuilder.append("delete from ");
1499         addQuoteIfAllowed(myBuilder);
1500         myBuilder.append(theTableName);
1501         addQuoteIfAllowed(myBuilder);
1502         return myBuilder.toString();
1503     }
1504 
1505     /**
1506      * Build the count string for a table.
1507      *
1508      * @return the SQL string
1509      */
1510     protected String getCountString() {
1511         final StringBuilder myBuilder = new StringBuilder(BUFFER_LEN);
1512 
1513         /* Build the initial delete */
1514         myBuilder.append("select count(*) from ");
1515         addQuoteIfAllowed(myBuilder);
1516         myBuilder.append(theTableName);
1517         addQuoteIfAllowed(myBuilder);
1518         return myBuilder.toString();
1519     }
1520 
1521     /**
1522      * Add quote if necessary.
1523      *
1524      * @param pBuilder the builder
1525      */
1526     void addQuoteIfAllowed(final StringBuilder pBuilder) {
1527         if (theDriver.useQuotes()) {
1528             pBuilder.append(QUOTE_STRING);
1529         }
1530     }
1531 
1532     /**
1533      * SortOrder.
1534      */
1535     public enum PrometheusSortOrder {
1536         /**
1537          * Ascending.
1538          */
1539         ASCENDING,
1540 
1541         /**
1542          * Descending.
1543          */
1544         DESCENDING;
1545     }
1546 }