1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 package com.workingdogs.village;
54
55 import java.io.ByteArrayOutputStream;
56 import java.io.PrintWriter;
57
58 import java.math.BigDecimal;
59
60 import java.sql.Connection;
61 import java.sql.PreparedStatement;
62 import java.sql.ResultSet;
63 import java.sql.SQLException;
64
65 /***
66 * A Record represents a row in the database. It contains a collection of <a href="Value.html">Values</A> which are the individual
67 * contents of each column in the row.
68 *
69 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
70 * @version $Revision: 568 $
71 */
72 public class Record
73 {
74 /*** an array of Value objects, this is 1 based */
75 private Value [] values;
76
77 /*** a 1 To 1 relationship between Values and whether they are clean or not */
78 private boolean [] isClean;
79
80 /*** the parent DataSet for this Record */
81 private DataSet parentDataSet;
82
83 /*** number of columns in this Record */
84 private int numberOfColumns;
85
86 /*** this is the state of this record */
87 private int saveType = 0;
88
89 /*** a saved copy of the schema for this Record */
90 private Schema schema;
91
92 /***
93 * This isn't used and doesn't do anything.
94 */
95 public Record()
96 {
97
98 }
99
100 /***
101 * Creates a new Record and sets the parent dataset to the passed in value. This method also creates the Value objects which
102 * are associated with this Record.
103 *
104 * @param ds TODO: DOCUMENT ME!
105 *
106 * @throws DataSetException TODO: DOCUMENT ME!
107 * @throws SQLException TODO: DOCUMENT ME!
108 */
109 public Record(DataSet ds)
110 throws DataSetException, SQLException
111 {
112 setParentDataSet(ds);
113 initializeRecord();
114 createValues(dataset().resultSet());
115 }
116
117 /***
118 * This is a special case method for Record. This case is really only used when DataSet.addRecord() is called because we may
119 * not have an existing ResultSet so there will not be any values in the Value objects that are created. Passing null to
120 * createValues forces the Value object to be created, but no processing to be done within the Value object constructor.
121 *
122 * <P>
123 * This method is a package method only because it is really not useful outside of the package.
124 * </p>
125 *
126 * @param ds the dataset
127 * @param addRecord whether or not this method is being called from DataSet.addRecord()
128 *
129 * @throws DataSetException TODO: DOCUMENT ME!
130 * @throws SQLException TODO: DOCUMENT ME!
131 */
132 Record(DataSet ds, boolean addRecord)
133 throws DataSetException, SQLException
134 {
135 setParentDataSet(ds);
136 initializeRecord();
137 createValues(null);
138 }
139
140 /***
141 * Performs initialization for this Record.
142 *
143 * @throws DataSetException TODO: DOCUMENT ME!
144 */
145 private void initializeRecord()
146 throws DataSetException
147 {
148 this.schema = dataset().schema();
149 this.numberOfColumns = schema.numberOfColumns();
150 this.values = new Value[size() + 1];
151 this.isClean = new boolean[size() + 1];
152 setSaveType(Enums.UNKNOWN);
153
154 for (int i = 1; i <= size(); i++)
155 {
156 markValueClean(i);
157 this.values[i] = null;
158 }
159 }
160
161 /***
162 * Creates the value objects for this Record. It is 1 based
163 *
164 * @param rs TODO: DOCUMENT ME!
165 *
166 * @exception DataSetException
167 * @exception SQLException
168 */
169 private void createValues(ResultSet rs)
170 throws DataSetException, SQLException
171 {
172 for (int i = 1; i <= size(); i++)
173 {
174 Value val = new Value(rs, i, schema().column(i).typeEnum());
175 this.values[i] = val;
176 }
177 }
178
179 /***
180 * Saves the data in this Record to the database. Uses the parent dataset's connection.
181 *
182 * @return 1 if the save completed. 0 otherwise.
183 *
184 * @throws DataSetException TODO: DOCUMENT ME!
185 * @throws SQLException TODO: DOCUMENT ME!
186 */
187 public int save()
188 throws DataSetException, SQLException
189 {
190 return save(dataset().connection());
191 }
192
193 /***
194 * Saves the data in this Record to the database. Uses the connection passed into it.
195 *
196 * @param connection TODO: DOCUMENT ME!
197 *
198 * @return 1 if the save completed. 0 otherwise.
199 *
200 * @throws DataSetException TODO: DOCUMENT ME!
201 * @throws SQLException TODO: DOCUMENT ME!
202 */
203 public int save(Connection connection)
204 throws DataSetException, SQLException
205 {
206 int returnValue = 0;
207
208 if (dataset() instanceof QueryDataSet)
209 {
210 throw new DataSetException("You cannot save a QueryDataSet. Please use a TableDataSet instead.");
211 }
212
213 if (!needsToBeSaved())
214 {
215 return returnValue;
216 }
217
218 if (toBeSavedWithInsert())
219 {
220 returnValue = saveWithInsert(connection);
221 }
222 else if (toBeSavedWithUpdate())
223 {
224 returnValue = saveWithUpdate(connection);
225 }
226 else if (toBeSavedWithDelete())
227 {
228 returnValue = saveWithDelete(connection);
229 }
230
231 return returnValue;
232 }
233
234 /***
235 * Saves the data in this Record to the database with an DELETE statement
236 *
237 * @param connection TODO: DOCUMENT ME!
238 *
239 * @return SQL DELETE statement
240 *
241 * @throws DataSetException TODO: DOCUMENT ME!
242 * @throws SQLException TODO: DOCUMENT ME!
243 */
244 private int saveWithDelete(Connection connection)
245 throws DataSetException, SQLException
246 {
247 PreparedStatement stmt = null;
248
249 try
250 {
251 stmt = connection.prepareStatement(getSaveString());
252
253 int ps = 1;
254
255 for (int i = 1; i <= dataset().keydef().size(); i++)
256 {
257 Value val = getValue(dataset().keydef().getAttrib(i));
258
259 val.setPreparedStatementValue(stmt, ps++);
260 }
261
262 int ret = stmt.executeUpdate();
263
264
265
266
267
268
269
270
271 setSaveType(Enums.ZOMBIE);
272
273 if (ret > 1)
274 {
275 throw new SQLException("There were " + ret + " rows deleted with this records key value.");
276 }
277
278 return ret;
279 }
280 catch (SQLException e1)
281 {
282 throw e1;
283 }
284 finally
285 {
286 try
287 {
288 if (stmt != null)
289 {
290 stmt.close();
291 }
292 }
293 catch (SQLException e2)
294 {
295 throw e2;
296 }
297 }
298 }
299
300 /***
301 * Saves the data in this Record to the database with an UPDATE statement
302 *
303 * @param connection TODO: DOCUMENT ME!
304 *
305 * @return SQL UPDATE statement
306 *
307 * @throws DataSetException TODO: DOCUMENT ME!
308 * @throws SQLException TODO: DOCUMENT ME!
309 */
310 private int saveWithUpdate(Connection connection)
311 throws DataSetException, SQLException
312 {
313 PreparedStatement stmt = null;
314
315 try
316 {
317 stmt = connection.prepareStatement(getSaveString());
318
319 int ps = 1;
320
321 for (int i = 1; i <= size(); i++)
322 {
323 Value val = getValue(i);
324
325 if (!valueIsClean(i) && !schema().column(i).readOnly())
326 {
327 val.setPreparedStatementValue(stmt, ps++);
328 }
329 }
330
331 for (int i = 1; i <= dataset().keydef().size(); i++)
332 {
333 Value val = getValue(dataset().keydef().getAttrib(i));
334
335 val.setPreparedStatementValue(stmt, ps++);
336 }
337
338 int ret = stmt.executeUpdate();
339
340 if (((TableDataSet) dataset()).refreshOnSave())
341 {
342 refresh(dataset().connection());
343 }
344 else
345 {
346
347 markRecordClean();
348 }
349
350 setSaveType(Enums.AFTERUPDATE);
351
352 if (ret > 1)
353 {
354 throw new SQLException("There were " + ret + " rows updated with this records key value.");
355 }
356
357 return ret;
358 }
359 catch (SQLException e1)
360 {
361 throw e1;
362 }
363 finally
364 {
365 try
366 {
367 if (stmt != null)
368 {
369 stmt.close();
370 }
371 }
372 catch (SQLException e2)
373 {
374 throw e2;
375 }
376 }
377 }
378
379 /***
380 * Saves the data in this Record to the database with an INSERT statement
381 *
382 * @param connection TODO: DOCUMENT ME!
383 *
384 * @return SQL INSERT statement
385 *
386 * @throws DataSetException TODO: DOCUMENT ME!
387 * @throws SQLException TODO: DOCUMENT ME!
388 */
389 private int saveWithInsert(Connection connection)
390 throws DataSetException, SQLException
391 {
392 PreparedStatement stmt = null;
393
394 try
395 {
396 stmt = connection.prepareStatement(getSaveString());
397
398 int ps = 1;
399
400 for (int i = 1; i <= size(); i++)
401 {
402 Value val = getValue(i);
403
404 if (!valueIsClean(i) && !schema().column(i).readOnly())
405 {
406 val.setPreparedStatementValue(stmt, ps++);
407 }
408 }
409
410 int ret = stmt.executeUpdate();
411
412 if (((TableDataSet) dataset()).refreshOnSave())
413 {
414 refresh(dataset().connection());
415 }
416 else
417 {
418
419 markRecordClean();
420 }
421
422 setSaveType(Enums.AFTERINSERT);
423
424 if (ret > 1)
425 {
426 throw new SQLException("There were " + ret + " rows inserted with this records key value.");
427 }
428
429 return ret;
430 }
431 catch (SQLException e1)
432 {
433 throw e1;
434 }
435 finally
436 {
437 try
438 {
439 if (stmt != null)
440 {
441 stmt.close();
442 }
443 }
444 catch (SQLException e2)
445 {
446 throw e2;
447 }
448 }
449 }
450
451 /***
452 * Builds the SQL UPDATE statement for this Record
453 *
454 * @return SQL UPDATE statement
455 *
456 * @throws DataSetException TODO: DOCUMENT ME!
457 */
458 private String getUpdateSaveString()
459 throws DataSetException
460 {
461 KeyDef kd = dataset().keydef();
462
463 if ((kd == null) || (kd.size() == 0))
464 {
465 throw new DataSetException(
466 "You must specify KeyDef attributes for this TableDataSet in order to create a Record for update.");
467 }
468 else if (recordIsClean())
469 {
470 throw new DataSetException("You must Record.setValue() on a column before doing an update.");
471 }
472
473 StringBuffer iss1 = new StringBuffer(256);
474 StringBuffer iss2 = new StringBuffer(256);
475 boolean comma = false;
476
477 for (int i = 1; i <= size(); i++)
478 {
479 if (!valueIsClean(i) && !schema().column(i).readOnly())
480 {
481 if (!comma)
482 {
483 iss1.append(schema().column(i).name());
484 iss1.append(" = ?");
485 comma = true;
486 }
487 else
488 {
489 iss1.append(", ");
490 iss1.append(schema().column(i).name());
491 iss1.append(" = ?");
492 }
493 }
494 }
495
496 comma = false;
497
498 for (int i = 1; i <= kd.size(); i++)
499 {
500 String attrib = kd.getAttrib(i);
501
502 if (!valueIsClean(schema().index(attrib)))
503 {
504 throw new DataSetException("The value for column '" + attrib + "' is a key value and cannot be updated.");
505 }
506
507 if (!comma)
508 {
509 iss2.append(attrib);
510 iss2.append(" = ?");
511 comma = true;
512 }
513 else
514 {
515 iss2.append(" AND ");
516 iss2.append(attrib);
517 iss2.append(" = ?");
518 }
519 }
520
521 return "UPDATE " + schema().tableName() + " SET " + iss1.toString() + " WHERE " + iss2.toString();
522 }
523
524 /***
525 * Builds the SQL DELETE statement for this Record
526 *
527 * @return SQL DELETE statement
528 *
529 * @throws DataSetException TODO: DOCUMENT ME!
530 */
531 private String getDeleteSaveString()
532 throws DataSetException
533 {
534 KeyDef kd = dataset().keydef();
535
536 if ((kd == null) || (kd.size() == 0))
537 {
538 throw new DataSetException("You must specify KeyDef attributes for this TableDataSet in order to delete a Record.");
539 }
540
541 StringBuffer iss1 = new StringBuffer(256);
542
543 boolean comma = false;
544
545 for (int i = 1; i <= kd.size(); i++)
546 {
547 if (!comma)
548 {
549 iss1.append(kd.getAttrib(i));
550 iss1.append(" = ?");
551 comma = true;
552 }
553 else
554 {
555 iss1.append(" AND ");
556 iss1.append(kd.getAttrib(i));
557 iss1.append(" = ? ");
558 }
559 }
560
561 return "DELETE FROM " + schema().tableName() + " WHERE " + iss1.toString();
562 }
563
564 /***
565 * Builds the SQL INSERT statement for this Record
566 *
567 * @return SQL INSERT statement
568 *
569 * @throws DataSetException TODO: DOCUMENT ME!
570 */
571 private String getInsertSaveString()
572 throws DataSetException
573 {
574 StringBuffer iss1 = new StringBuffer(256);
575 StringBuffer iss2 = new StringBuffer(256);
576
577 boolean comma = false;
578
579 for (int i = 1; i <= size(); i++)
580 {
581 if (!valueIsClean(i) && !schema().column(i).readOnly())
582 {
583 if (!comma)
584 {
585 iss1.append(schema().column(i).name());
586 iss2.append("?");
587 comma = true;
588 }
589 else
590 {
591 iss1.append(", " + schema().column(i).name());
592 iss2.append(", ?");
593 }
594 }
595 }
596
597 return "INSERT INTO " + schema().tableName() + " ( " + iss1.toString() + " ) VALUES ( " + iss2.toString() + " )";
598 }
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614 /***
615 * Gets the appropriate SQL string for this record.
616 *
617 * @return SQL string
618 *
619 * @throws DataSetException TODO: DOCUMENT ME!
620 */
621 public String getSaveString()
622 throws DataSetException
623 {
624 if (toBeSavedWithInsert())
625 {
626 return getInsertSaveString();
627 }
628 else if (toBeSavedWithUpdate())
629 {
630 return getUpdateSaveString();
631 }
632 else if (toBeSavedWithDelete())
633 {
634 return getDeleteSaveString();
635 }
636 else
637 {
638 throw new DataSetException("Not able to return save string: " + this.saveType);
639 }
640 }
641
642 /***
643 * gets the value at index i
644 *
645 * @param i TODO: DOCUMENT ME!
646 *
647 * @return the Value object at index i
648 *
649 * @throws DataSetException TODO: DOCUMENT ME!
650 */
651 public Value getValue(int i)
652 throws DataSetException
653 {
654 if (i == 0)
655 {
656 throw new DataSetException("Values are 1 based!");
657 }
658 else if (i > size())
659 {
660 throw new DataSetException("Only " + size() + " columns exist!");
661 }
662 else if (values[i] == null)
663 {
664 throw new DataSetException("No values for the requested column!");
665 }
666
667 return values[i];
668 }
669
670 /***
671 * TODO: DOCUMENT ME!
672 *
673 * @param columnName TODO: DOCUMENT ME!
674 *
675 * @return TODO: DOCUMENT ME!
676 *
677 * @throws DataSetException TODO: DOCUMENT ME!
678 */
679 public Value getValue(String columnName)
680 throws DataSetException
681 {
682 return getValue(schema().index(columnName));
683 }
684
685 /***
686 * the number of columns in this object
687 *
688 * @return the number of columns in this object
689 */
690 public int size()
691 {
692 return numberOfColumns;
693 }
694
695 /***
696 * whether or not this Record is to be saved with an SQL insert statement
697 *
698 * @return true if saved with insert
699 */
700 public boolean toBeSavedWithInsert()
701 {
702 return (this.saveType == Enums.INSERT) ? true : false;
703 }
704
705 /***
706 * whether or not this Record is to be saved with an SQL update statement
707 *
708 * @return true if saved with update
709 */
710 public boolean toBeSavedWithUpdate()
711 {
712 return (this.saveType == Enums.UPDATE) ? true : false;
713 }
714
715 /***
716 * whether or not this Record is to be saved with an SQL delete statement
717 *
718 * @return true if saved with delete
719 */
720 public boolean toBeSavedWithDelete()
721 {
722 return (this.saveType == Enums.DELETE) ? true : false;
723 }
724
725 /***
726 * Marks all the values in this record as clean.
727 *
728 * @throws DataSetException TODO: DOCUMENT ME!
729 */
730 public void markRecordClean()
731 throws DataSetException
732 {
733 for (int i = 1; i <= size(); i++)
734 {
735 markValueClean(i);
736 }
737 }
738
739 /***
740 * Marks this record to be inserted when a save is executed.
741 *
742 * @throws DataSetException TODO: DOCUMENT ME!
743 */
744 public void markForInsert()
745 throws DataSetException
746 {
747 if (dataset() instanceof QueryDataSet)
748 {
749 throw new DataSetException("You cannot mark a record in a QueryDataSet for insert");
750 }
751
752 setSaveType(Enums.INSERT);
753 }
754
755 /***
756 * Marks this record to be updated when a save is executed.
757 *
758 * @throws DataSetException TODO: DOCUMENT ME!
759 */
760 public void markForUpdate()
761 throws DataSetException
762 {
763 if (dataset() instanceof QueryDataSet)
764 {
765 throw new DataSetException("You cannot mark a record in a QueryDataSet for update");
766 }
767
768 setSaveType(Enums.UPDATE);
769 }
770
771 /***
772 * Marks this record to be deleted when a save is executed.
773 *
774 * @return TODO: DOCUMENT ME!
775 *
776 * @throws DataSetException TODO: DOCUMENT ME!
777 */
778 public Record markToBeDeleted()
779 throws DataSetException
780 {
781 if (dataset() instanceof QueryDataSet)
782 {
783 throw new DataSetException("You cannot mark a record in a QueryDataSet for deletion");
784 }
785
786 setSaveType(Enums.DELETE);
787
788 return this;
789 }
790
791 /***
792 * Unmarks a record that has been marked for deletion.
793 *
794 * <P>
795 * WARNING: You must reset the save type before trying to save this record again.
796 * </p>
797 *
798 * @return TODO: DOCUMENT ME!
799 *
800 * @throws DataSetException TODO: DOCUMENT ME!
801 *
802 * @see #markForUpdate()
803 * @see #markForInsert()
804 * @see #markToBeDeleted()
805 */
806 public Record unmarkToBeDeleted()
807 throws DataSetException
808 {
809 if (this.saveType == Enums.ZOMBIE)
810 {
811 throw new DataSetException("This record has already been deleted!");
812 }
813
814 setSaveType(Enums.UNKNOWN);
815
816 return this;
817 }
818
819 /***
820 * marks a value at a given position as clean.
821 *
822 * @param pos TODO: DOCUMENT ME!
823 *
824 * @throws DataSetException TODO: DOCUMENT ME!
825 */
826 public void markValueClean(int pos)
827 throws DataSetException
828 {
829 if (pos == 0)
830 {
831 throw new DataSetException("Value position must be greater than 0.");
832 }
833 else if (pos > size())
834 {
835 throw new DataSetException("Value position is greater than number of values.");
836 }
837
838 this.isClean[pos] = true;
839 }
840
841 /***
842 * marks a value with a given column name as clean.
843 *
844 * @param columnName TODO: DOCUMENT ME!
845 *
846 * @throws DataSetException TODO: DOCUMENT ME!
847 */
848 public void markValueClean(String columnName)
849 throws DataSetException
850 {
851 markValueClean(schema().index(columnName));
852 }
853
854 /***
855 * marks a value at a given position as dirty.
856 *
857 * @param pos TODO: DOCUMENT ME!
858 *
859 * @throws DataSetException TODO: DOCUMENT ME!
860 */
861 public void markValueDirty(int pos)
862 throws DataSetException
863 {
864 if (pos == 0)
865 {
866 throw new DataSetException("Value position must be greater than 0.");
867 }
868 else if (pos > size())
869 {
870 throw new DataSetException("Value position is greater than number of values.");
871 }
872
873 this.isClean[pos] = false;
874 }
875
876 /***
877 * marks a value with a given column name as dirty.
878 *
879 * @param columnName TODO: DOCUMENT ME!
880 *
881 * @throws DataSetException TODO: DOCUMENT ME!
882 */
883 public void markValueDirty(String columnName)
884 throws DataSetException
885 {
886 markValueDirty(schema().index(columnName));
887 }
888
889 /***
890 * sets the internal save type as one of the defined privates (ie: ZOMBIE)
891 *
892 * @param type TODO: DOCUMENT ME!
893 */
894 void setSaveType(int type)
895 {
896 this.saveType = type;
897 }
898
899 /***
900 * gets the internal save type as one of the defined privates (ie: ZOMBIE)
901 *
902 * @return TODO: DOCUMENT ME!
903 */
904 int getSaveType()
905 {
906 return this.saveType;
907 }
908
909 /***
910 * sets the value at pos with a BigDecimal
911 *
912 * @param pos TODO: DOCUMENT ME!
913 * @param value TODO: DOCUMENT ME!
914 *
915 * @return TODO: DOCUMENT ME!
916 *
917 * @throws DataSetException TODO: DOCUMENT ME!
918 */
919 public Record setValue(int pos, BigDecimal value)
920 throws DataSetException
921 {
922 this.values[pos].setValue(value);
923 markValueDirty(pos);
924
925 return this;
926 }
927
928 /***
929 * sets the value at pos with a boolean
930 *
931 * @param pos TODO: DOCUMENT ME!
932 * @param value TODO: DOCUMENT ME!
933 *
934 * @return TODO: DOCUMENT ME!
935 *
936 * @throws DataSetException TODO: DOCUMENT ME!
937 */
938 public Record setValue(int pos, boolean value)
939 throws DataSetException
940 {
941 this.values[pos].setValue(Boolean.valueOf(value));
942 markValueDirty(pos);
943
944 return this;
945 }
946
947 /***
948 * sets the value at pos with a byte[]
949 *
950 * @param pos TODO: DOCUMENT ME!
951 * @param value TODO: DOCUMENT ME!
952 *
953 * @return TODO: DOCUMENT ME!
954 *
955 * @throws DataSetException TODO: DOCUMENT ME!
956 */
957 public Record setValue(int pos, byte [] value)
958 throws DataSetException
959 {
960 this.values[pos].setValue(value);
961 markValueDirty(pos);
962
963 return this;
964 }
965
966 /***
967 * sets the value at pos with a java.util.Date
968 *
969 * @param pos TODO: DOCUMENT ME!
970 * @param value TODO: DOCUMENT ME!
971 *
972 * @return TODO: DOCUMENT ME!
973 *
974 * @throws DataSetException TODO: DOCUMENT ME!
975 */
976 public Record setValue(int pos, java.util.Date value)
977 throws DataSetException
978 {
979 this.values[pos].setValue(value);
980 markValueDirty(pos);
981
982 return this;
983 }
984
985 /***
986 * sets the value at pos with a java.sql.Date
987 *
988 * @param pos TODO: DOCUMENT ME!
989 * @param value TODO: DOCUMENT ME!
990 *
991 * @return TODO: DOCUMENT ME!
992 *
993 * @throws DataSetException TODO: DOCUMENT ME!
994 */
995 public Record setValue(int pos, java.sql.Date value)
996 throws DataSetException
997 {
998 this.values[pos].setValue(value);
999 markValueDirty(pos);
1000
1001 return this;
1002 }
1003
1004 /***
1005 * sets the value at pos with a double
1006 *
1007 * @param pos TODO: DOCUMENT ME!
1008 * @param value TODO: DOCUMENT ME!
1009 *
1010 * @return TODO: DOCUMENT ME!
1011 *
1012 * @throws DataSetException TODO: DOCUMENT ME!
1013 */
1014 public Record setValue(int pos, double value)
1015 throws DataSetException
1016 {
1017 this.values[pos].setValue(new Double(value));
1018 markValueDirty(pos);
1019
1020 return this;
1021 }
1022
1023 /***
1024 * sets the value at pos with a float
1025 *
1026 * @param pos TODO: DOCUMENT ME!
1027 * @param value TODO: DOCUMENT ME!
1028 *
1029 * @return TODO: DOCUMENT ME!
1030 *
1031 * @throws DataSetException TODO: DOCUMENT ME!
1032 */
1033 public Record setValue(int pos, float value)
1034 throws DataSetException
1035 {
1036 this.values[pos].setValue(new Float(value));
1037 markValueDirty(pos);
1038
1039 return this;
1040 }
1041
1042 /***
1043 * sets the value at pos with a int
1044 *
1045 * @param pos TODO: DOCUMENT ME!
1046 * @param value TODO: DOCUMENT ME!
1047 *
1048 * @return TODO: DOCUMENT ME!
1049 *
1050 * @throws DataSetException TODO: DOCUMENT ME!
1051 */
1052 public Record setValue(int pos, int value)
1053 throws DataSetException
1054 {
1055 this.values[pos].setValue(new Integer(value));
1056 markValueDirty(pos);
1057
1058 return this;
1059 }
1060
1061 /***
1062 * sets the value at pos with a long
1063 *
1064 * @param pos TODO: DOCUMENT ME!
1065 * @param value TODO: DOCUMENT ME!
1066 *
1067 * @return TODO: DOCUMENT ME!
1068 *
1069 * @throws DataSetException TODO: DOCUMENT ME!
1070 */
1071 public Record setValue(int pos, long value)
1072 throws DataSetException
1073 {
1074 this.values[pos].setValue(new Long(value));
1075 markValueDirty(pos);
1076
1077 return this;
1078 }
1079
1080 /***
1081 * sets the value at pos with a String
1082 *
1083 * @param pos TODO: DOCUMENT ME!
1084 * @param value TODO: DOCUMENT ME!
1085 *
1086 * @return TODO: DOCUMENT ME!
1087 *
1088 * @throws DataSetException TODO: DOCUMENT ME!
1089 */
1090 public Record setValue(int pos, String value)
1091 throws DataSetException
1092 {
1093 this.values[pos].setValue(value);
1094 markValueDirty(pos);
1095
1096 return this;
1097 }
1098
1099 /***
1100 * sets the value at pos with a java.sql.Time
1101 *
1102 * @param pos TODO: DOCUMENT ME!
1103 * @param value TODO: DOCUMENT ME!
1104 *
1105 * @return TODO: DOCUMENT ME!
1106 *
1107 * @throws DataSetException TODO: DOCUMENT ME!
1108 */
1109 public Record setValue(int pos, java.sql.Time value)
1110 throws DataSetException
1111 {
1112 this.values[pos].setValue(value);
1113 markValueDirty(pos);
1114
1115 return this;
1116 }
1117
1118 /***
1119 * sets the value at pos with a java.sql.Timestamp
1120 *
1121 * @param pos TODO: DOCUMENT ME!
1122 * @param value TODO: DOCUMENT ME!
1123 *
1124 * @return TODO: DOCUMENT ME!
1125 *
1126 * @throws DataSetException TODO: DOCUMENT ME!
1127 */
1128 public Record setValue(int pos, java.sql.Timestamp value)
1129 throws DataSetException
1130 {
1131 this.values[pos].setValue(value);
1132 markValueDirty(pos);
1133
1134 return this;
1135 }
1136
1137 /***
1138 * sets the value at pos with a Value
1139 *
1140 * @param pos TODO: DOCUMENT ME!
1141 * @param value TODO: DOCUMENT ME!
1142 *
1143 * @return TODO: DOCUMENT ME!
1144 *
1145 * @throws DataSetException TODO: DOCUMENT ME!
1146 */
1147 public Record setValue(int pos, Value value)
1148 throws DataSetException
1149 {
1150 this.values[pos].setValue(value.getValue());
1151 markValueDirty(pos);
1152
1153 return this;
1154 }
1155
1156 /***
1157 * sets the value at column name with a BigDecimal
1158 *
1159 * @param columnName TODO: DOCUMENT ME!
1160 * @param value TODO: DOCUMENT ME!
1161 *
1162 * @return TODO: DOCUMENT ME!
1163 *
1164 * @throws DataSetException TODO: DOCUMENT ME!
1165 */
1166 public Record setValue(String columnName, BigDecimal value)
1167 throws DataSetException
1168 {
1169 setValue(schema().index(columnName), value);
1170
1171 return this;
1172 }
1173
1174 /***
1175 * sets the value at column name with a boolean
1176 *
1177 * @param columnName TODO: DOCUMENT ME!
1178 * @param value TODO: DOCUMENT ME!
1179 *
1180 * @return TODO: DOCUMENT ME!
1181 *
1182 * @throws DataSetException TODO: DOCUMENT ME!
1183 */
1184 public Record setValue(String columnName, boolean value)
1185 throws DataSetException
1186 {
1187 setValue(schema().index(columnName), value);
1188
1189 return this;
1190 }
1191
1192 /***
1193 * sets the value at column name with a byte[]
1194 *
1195 * @param columnName TODO: DOCUMENT ME!
1196 * @param value TODO: DOCUMENT ME!
1197 *
1198 * @return TODO: DOCUMENT ME!
1199 *
1200 * @throws DataSetException TODO: DOCUMENT ME!
1201 */
1202 public Record setValue(String columnName, byte [] value)
1203 throws DataSetException
1204 {
1205 setValue(schema().index(columnName), value);
1206
1207 return this;
1208 }
1209
1210 /***
1211 * sets the value at column name with a java.util.Date
1212 *
1213 * @param columnName TODO: DOCUMENT ME!
1214 * @param value TODO: DOCUMENT ME!
1215 *
1216 * @return TODO: DOCUMENT ME!
1217 *
1218 * @throws DataSetException TODO: DOCUMENT ME!
1219 */
1220 public Record setValue(String columnName, java.util.Date value)
1221 throws DataSetException
1222 {
1223 setValue(schema().index(columnName), value);
1224
1225 return this;
1226 }
1227
1228 /***
1229 * sets the value at column name with a java.sql.Date
1230 *
1231 * @param columnName TODO: DOCUMENT ME!
1232 * @param value TODO: DOCUMENT ME!
1233 *
1234 * @return TODO: DOCUMENT ME!
1235 *
1236 * @throws DataSetException TODO: DOCUMENT ME!
1237 */
1238 public Record setValue(String columnName, java.sql.Date value)
1239 throws DataSetException
1240 {
1241 setValue(schema().index(columnName), value);
1242
1243 return this;
1244 }
1245
1246 /***
1247 * sets the value at column name with a double
1248 *
1249 * @param columnName TODO: DOCUMENT ME!
1250 * @param value TODO: DOCUMENT ME!
1251 *
1252 * @return TODO: DOCUMENT ME!
1253 *
1254 * @throws DataSetException TODO: DOCUMENT ME!
1255 */
1256 public Record setValue(String columnName, double value)
1257 throws DataSetException
1258 {
1259 setValue(schema().index(columnName), value);
1260
1261 return this;
1262 }
1263
1264 /***
1265 * sets the value at column name with a float
1266 *
1267 * @param columnName TODO: DOCUMENT ME!
1268 * @param value TODO: DOCUMENT ME!
1269 *
1270 * @return TODO: DOCUMENT ME!
1271 *
1272 * @throws DataSetException TODO: DOCUMENT ME!
1273 */
1274 public Record setValue(String columnName, float value)
1275 throws DataSetException
1276 {
1277 setValue(schema().index(columnName), value);
1278
1279 return this;
1280 }
1281
1282 /***
1283 * sets the value at column name with a int
1284 *
1285 * @param columnName TODO: DOCUMENT ME!
1286 * @param value TODO: DOCUMENT ME!
1287 *
1288 * @return TODO: DOCUMENT ME!
1289 *
1290 * @throws DataSetException TODO: DOCUMENT ME!
1291 */
1292 public Record setValue(String columnName, int value)
1293 throws DataSetException
1294 {
1295 setValue(schema().index(columnName), value);
1296
1297 return this;
1298 }
1299
1300 /***
1301 * sets the value at column name with a long
1302 *
1303 * @param columnName TODO: DOCUMENT ME!
1304 * @param value TODO: DOCUMENT ME!
1305 *
1306 * @return TODO: DOCUMENT ME!
1307 *
1308 * @throws DataSetException TODO: DOCUMENT ME!
1309 */
1310 public Record setValue(String columnName, long value)
1311 throws DataSetException
1312 {
1313 setValue(schema().index(columnName), value);
1314
1315 return this;
1316 }
1317
1318 /***
1319 * sets the value at column name with a String
1320 *
1321 * @param columnName TODO: DOCUMENT ME!
1322 * @param value TODO: DOCUMENT ME!
1323 *
1324 * @return TODO: DOCUMENT ME!
1325 *
1326 * @throws DataSetException TODO: DOCUMENT ME!
1327 */
1328 public Record setValue(String columnName, String value)
1329 throws DataSetException
1330 {
1331 setValue(schema().index(columnName), value);
1332
1333 return this;
1334 }
1335
1336 /***
1337 * sets the value at column name with a java.sql.Time
1338 *
1339 * @param columnName TODO: DOCUMENT ME!
1340 * @param value TODO: DOCUMENT ME!
1341 *
1342 * @return TODO: DOCUMENT ME!
1343 *
1344 * @throws DataSetException TODO: DOCUMENT ME!
1345 */
1346 public Record setValue(String columnName, java.sql.Time value)
1347 throws DataSetException
1348 {
1349 setValue(schema().index(columnName), value);
1350
1351 return this;
1352 }
1353
1354 /***
1355 * sets the value at column name with a java.sql.Timestamp
1356 *
1357 * @param columnName TODO: DOCUMENT ME!
1358 * @param value TODO: DOCUMENT ME!
1359 *
1360 * @return TODO: DOCUMENT ME!
1361 *
1362 * @throws DataSetException TODO: DOCUMENT ME!
1363 */
1364 public Record setValue(String columnName, java.sql.Timestamp value)
1365 throws DataSetException
1366 {
1367 setValue(schema().index(columnName), value);
1368
1369 return this;
1370 }
1371
1372 /***
1373 * sets the value at column name with a Value
1374 *
1375 * @param columnName TODO: DOCUMENT ME!
1376 * @param value TODO: DOCUMENT ME!
1377 *
1378 * @return TODO: DOCUMENT ME!
1379 *
1380 * @throws DataSetException TODO: DOCUMENT ME!
1381 */
1382 public Record setValue(String columnName, Value value)
1383 throws DataSetException
1384 {
1385 setValue(schema().index(columnName), value);
1386
1387 return this;
1388 }
1389
1390 /***
1391 * sets the value at pos with a NULL
1392 *
1393 * @param pos TODO: DOCUMENT ME!
1394 *
1395 * @return TODO: DOCUMENT ME!
1396 *
1397 * @throws DataSetException TODO: DOCUMENT ME!
1398 */
1399 public Record setValueNull(int pos)
1400 throws DataSetException
1401 {
1402 if (pos == 0)
1403 {
1404 throw new DataSetException("Value position must be greater than 0.");
1405 }
1406 else if (pos > size())
1407 {
1408 throw new DataSetException("Value position is greater than number of values.");
1409 }
1410
1411 this.values[pos].setValue(null);
1412 markValueDirty(pos);
1413
1414 return this;
1415 }
1416
1417 /***
1418 * sets the value at column name with a NULL
1419 *
1420 * @param columnName TODO: DOCUMENT ME!
1421 *
1422 * @return TODO: DOCUMENT ME!
1423 *
1424 * @throws DataSetException TODO: DOCUMENT ME!
1425 */
1426 public Record setValueNull(String columnName)
1427 throws DataSetException
1428 {
1429 if ((columnName == null) || (columnName.length() == 0))
1430 {
1431 throw new DataSetException("You must specify a column name!");
1432 }
1433
1434 setValueNull(schema().index(columnName));
1435
1436 return this;
1437 }
1438
1439 /***
1440 * Determines if this record is a Zombie. A Zombie is a record that has been deleted from the database, but not yet removed
1441 * from the DataSet.
1442 *
1443 * @return a boolean
1444 */
1445 public boolean isAZombie()
1446 {
1447 return (this.saveType == Enums.ZOMBIE) ? true : false;
1448 }
1449
1450 /***
1451 * If the record is not clean, needs to be saved with an Update, Delete or Insert, it returns true.
1452 *
1453 * @return boolean
1454 */
1455 public boolean needsToBeSaved()
1456 {
1457 return !isAZombie() || !recordIsClean() || toBeSavedWithUpdate() || toBeSavedWithDelete() || toBeSavedWithInsert();
1458 }
1459
1460 /***
1461 * Determines whether or not a value stored in the record is clean.
1462 *
1463 * @param i TODO: DOCUMENT ME!
1464 *
1465 * @return true if clean
1466 */
1467 public boolean valueIsClean(int i)
1468 {
1469 return isClean[i];
1470 }
1471
1472 /***
1473 * Determines whether or not a value stored in the record is clean.
1474 *
1475 * @param column TODO: DOCUMENT ME!
1476 *
1477 * @return true if clean
1478 *
1479 * @throws DataSetException TODO: DOCUMENT ME!
1480 */
1481 boolean valueIsClean(String column)
1482 throws DataSetException
1483 {
1484 return isClean[getValue(column).columnNumber()];
1485 }
1486
1487 /***
1488 * Goes through all the values in the record to determine if it is clean or not.
1489 *
1490 * @return true if clean
1491 */
1492 public boolean recordIsClean()
1493 {
1494 for (int i = 1; i <= size(); i++)
1495 {
1496 if (!valueIsClean(i))
1497 {
1498 return false;
1499 }
1500 }
1501
1502 return true;
1503 }
1504
1505 /***
1506 * This method refreshes this Record's Value's. It can only be performed on a Record that has not been modified and has been
1507 * created with a TableDataSet and corresponding KeyDef.
1508 *
1509 * @param connection
1510 *
1511 * @exception DataSetException
1512 * @exception SQLException
1513 */
1514 public void refresh(Connection connection)
1515 throws DataSetException, SQLException
1516 {
1517 if (toBeSavedWithDelete())
1518 {
1519 return;
1520 }
1521 else if (toBeSavedWithInsert())
1522 {
1523 throw new DataSetException("There is no way to refresh a record which has been created with addRecord().");
1524 }
1525 else if (dataset() instanceof QueryDataSet)
1526 {
1527 throw new DataSetException("You can only perform a refresh on Records created with a TableDataSet.");
1528 }
1529
1530 PreparedStatement stmt = null;
1531
1532 try
1533 {
1534 stmt = connection.prepareStatement(getRefreshQueryString());
1535
1536 int ps = 1;
1537
1538 for (int i = 1; i <= dataset().keydef().size(); i++)
1539 {
1540 Value val = getValue(dataset().keydef().getAttrib(i));
1541
1542 if (val.isNull())
1543 {
1544 throw new DataSetException("You cannot execute an update with a null value for a KeyDef.");
1545 }
1546
1547 val.setPreparedStatementValue(stmt, ps++);
1548 }
1549
1550 ResultSet rs = stmt.executeQuery();
1551 rs.next();
1552
1553 initializeRecord();
1554
1555 createValues(rs);
1556 }
1557 catch (SQLException e1)
1558 {
1559 throw e1;
1560 }
1561 finally
1562 {
1563 try
1564 {
1565 if (stmt != null)
1566 {
1567 stmt.close();
1568 }
1569 }
1570 catch (SQLException e2)
1571 {
1572 throw e2;
1573 }
1574 }
1575 }
1576
1577 /***
1578 * This builds the SELECT statement in order to refresh the contents of this Record. It depends on a valid KeyDef to exist and
1579 * it must have been created with a TableDataSet.
1580 *
1581 * @return the SELECT string
1582 *
1583 * @exception DataSetException
1584 */
1585 public String getRefreshQueryString()
1586 throws DataSetException
1587 {
1588 if ((dataset().keydef() == null) || (dataset().keydef().size() == 0))
1589 {
1590 throw new DataSetException(
1591 "You can only perform a getRefreshQueryString on a TableDataSet that was created with a KeyDef.");
1592 }
1593 else if (dataset() instanceof QueryDataSet)
1594 {
1595 throw new DataSetException("You can only perform a getRefreshQueryString on Records created with a TableDataSet.");
1596 }
1597
1598 StringBuffer iss1 = new StringBuffer(256);
1599 StringBuffer iss2 = new StringBuffer(256);
1600 boolean comma = false;
1601
1602 for (int i = 1; i <= size(); i++)
1603 {
1604 if (!comma)
1605 {
1606 iss1.append(schema().column(i).name());
1607 comma = true;
1608 }
1609 else
1610 {
1611 iss1.append(", ");
1612 iss1.append(schema().column(i).name());
1613 }
1614 }
1615
1616 comma = false;
1617
1618 for (int i = 1; i <= dataset().keydef().size(); i++)
1619 {
1620 String attrib = dataset().keydef().getAttrib(i);
1621
1622 if (!valueIsClean(attrib))
1623 {
1624 throw new DataSetException("You cannot do a refresh from the database if the value "
1625 + "for a KeyDef column has been changed with a Record.setValue().");
1626 }
1627
1628 if (!comma)
1629 {
1630 iss2.append(attrib);
1631 iss2.append(" = ?");
1632 comma = true;
1633 }
1634 else
1635 {
1636 iss2.append(" AND ");
1637 iss2.append(attrib);
1638 iss2.append(" = ?");
1639 }
1640 }
1641
1642 return "SELECT " + iss1.toString() + " FROM " + schema().tableName() + " WHERE " + iss2.toString();
1643 }
1644
1645 /***
1646 * TODO: DOCUMENT ME!
1647 *
1648 * @throws DataSetException TODO: DOCUMENT ME!
1649 */
1650 public void saveWithoutStatusUpdate()
1651 throws DataSetException
1652 {
1653 throw new DataSetException("Record.saveWithoutStatusUpdate() is not yet implemented.");
1654 }
1655
1656 /***
1657 * Gets the schema for the parent DataSet
1658 *
1659 * @return the schema for the parent DataSet
1660 *
1661 * @throws DataSetException TODO: DOCUMENT ME!
1662 */
1663 public Schema schema()
1664 throws DataSetException
1665 {
1666 if (dataset() != null)
1667 {
1668 return this.schema;
1669 }
1670 else
1671 {
1672 throw new DataSetException("Internal Error: Record DataSet is null");
1673 }
1674 }
1675
1676 /***
1677 * Gets the DataSet for this Record
1678 *
1679 * @return the DataSet for this Record
1680 */
1681 public DataSet dataset()
1682 {
1683 return this.parentDataSet;
1684 }
1685
1686 /***
1687 * Sets the parent DataSet for this record.
1688 *
1689 * @param ds TODO: DOCUMENT ME!
1690 */
1691 void setParentDataSet(DataSet ds)
1692 {
1693 this.parentDataSet = ds;
1694 }
1695
1696 /***
1697 * return the value of each column as a string. Not yet implemented!
1698 *
1699 * @param valueseparator
1700 * @param maxwidths
1701 *
1702 * @return the formatted string
1703 *
1704 * @exception DataSetException
1705 */
1706 public String asFormattedString(String valueseparator, int [] maxwidths)
1707 throws DataSetException
1708 {
1709 throw new DataSetException("Not yet implemented!");
1710 }
1711
1712 /***
1713 * This returns a representation of this Record
1714 *
1715 * @return java.lang.String
1716 */
1717 public String toString()
1718 {
1719 try
1720 {
1721 ByteArrayOutputStream bout = new ByteArrayOutputStream();
1722 PrintWriter out = new PrintWriter(bout);
1723 out.print("{");
1724
1725 for (int i = 1; i <= size(); i++)
1726 {
1727 out.print("'" + getValue(i).asString() + "'");
1728
1729 if (i < size())
1730 {
1731 out.print(',');
1732 }
1733 }
1734
1735 out.print("}");
1736 out.flush();
1737
1738 return bout.toString();
1739 }
1740 catch (DataSetException e)
1741 {
1742 return "";
1743 }
1744 }
1745 }