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