Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/vrspace/server/db/SQLDB.java


1   package org.vrspace.server.db;
2   
3   import org.vrspace.server.DB;
4   import org.vrspace.util.Logger;
5   import org.vrspace.server.*;
6   import org.vrspace.*;
7   
8   import java.io.*;
9   import java.lang.reflect.Field;
10  import java.lang.reflect.Method;
11  import java.lang.reflect.Array;
12  import java.lang.reflect.Modifier;
13  import java.net.URL;
14  import java.util.ArrayList;
15  import java.util.Date;
16  import java.util.HashMap;
17  import java.util.StringTokenizer;
18  import java.sql.*;
19  
20   /**
21    DB store objects by storing all public fields:
22    * all primitive types and primitive arrays (java.lang.String,
23       java.net.URL and java.util.Date are considered as primitive)
24    * all objects and object arrays that are contained inside object (recursive)
25  
26    Requirements and restrictions:
27    * every object that will be stored in DB must have defined
28      "public long db_id" field (or must inherit from class that have db_id field)
29    * objects that have encapsulated data - private fields and get/set methods
30      for retrieving/storing that fields can't be stored correctly!
31      This is common for JDK classes - that classes can be stored by
32      manually coding (it's already done for String, Date, URL and Float)
33    
34    Description of DB structure:
35    DB has "repository" tables and "object" tables. "repository" tables stores
36    information about classes, objects and packages; "object" tables store objects.
37  
38    "repository" tables:
39  
40    mysql> describe classes;
41     +--------------+--------------+------+-----+---------+-------+
42     | Field        | Type         | Null | Key | Default | Extra |
43     +--------------+--------------+------+-----+---------+-------+
44     | classID      | bigint(20)   |      | PRI | 0       |       |
45     | superClassID | bigint(20)   | YES  |     | NULL    |       |
46     | packageID    | bigint(20)   | YES  |     | NULL    |       |
47     | className    | varchar(255) | YES  |     | NULL    |       |
48     +--------------+--------------+------+-----+---------+-------+
49  
50    mysql> describe packages;
51     +-------------+--------------+------+-----+---------+-------+
52     | Field       | Type         | Null | Key | Default | Extra |
53     +-------------+--------------+------+-----+---------+-------+
54     | packageID   | bigint(20)   |      | PRI | 0       |       |
55     | packageName | varchar(255) | YES  |     | NULL    |       |
56     +-------------+--------------+------+-----+---------+-------+
57  
58    mysql> describe objects;
59     +----------+------------+------+-----+---------+-------+
60     | Field    | Type       | Null | Key | Default | Extra |
61     +----------+------------+------+-----+---------+-------+
62     | objectID | bigint(20) |      | PRI | 0       |       |
63     | classID  | bigint(20) | YES  |     | NULL    |       |
64     +----------+------------+------+-----+---------+-------+
65    
66    details about "repository" tables:
67       * relations in repository tables
68         (these are just logical relations - not explicitly created):
69         - superClassID in one classes record must exist as classID in another
70           classes record (except for java.lang.Object when superClassID is null)
71         - classID in objects table must exist in classes table
72         - packageID in classes table must exist in packages table
73       * className is full class name with dots replaced by optional char
74         example: when optional char is '_', org.vrspace.server.File is stored
75         as org_vrspace_server_File. This is done because some db's can't have
76         points in table names
77    
78    details about "object" tables:
79       - names are full class names as stored in "classes" repository table
80       - names of columns in tables are names of object fields
81       - every table has "db_id" column that contains object ID stored in
82         "objects" repository table
83       - tables are divided into five groups:
84         * object:
85           - for storing "main" object (the one that is referenced in put/get method)
86           - if object consist of several inherited classes, every class is stored
87             in separated table
88           - primary key is "db_id"
89           - object fields are stored as follows:
90             * if field is primitive, its value is stored. The type of a column
91               is a type of that primitive mapped to matching database type
92             * if field is a primitive array, object or object array, than
93               that column has integer type and stores a unique reference inside object
94               for that primitive array, object or object array; primitive array,
95               object or object array itself are stored in another table (described below),
96               if they are null, column has null value and there's no recods in another table
97           - if class has "db_id" field it isn't explicitly stored because it's 
98             already stored as primary key
99         * object_array:
100          - for storing "main" object array (the one that is referenced in put/get method)
101          - table name has suffix "_arr"
102          - has column "arr_id" that stores index of object in array
103          - primary key is "db_id" + "arr_id"
104          - has column "isNull" which is true if object is null
105          - fields are stored according to rules from object tables
106        * object_contained:
107          - for storing objects that are contained inside "main" object
108          - table name has suffix "_cnt"
109          - has column "cnt_id" that stores reference described in object table
110          - primary key is "db_id" + "cnt_id"
111          - fields are stored according to rules from object tables
112        * object_array_contained:
113          - for storing object arrays that are contained inside "main" object
114          - table name has suffix "_arr_cnt"
115          - has column "cnt_id" that stores reference described in object table
116          - has column "arr_id" that stores index of object in array
117          - primary key is "db_id" + "cnt_id" + "arr_id"
118          - has column "isNull" which is true if object is null
119          - fields are stored according to rules from object tables
120        * primitive_array_contained:
121          - for storing primitive arrays that are contained inside "main" object
122          - table name is primitive name + "_arr"
123          - has column "cnt_id" that stores reference described in object table
124          - has column "arr_id" that stores index of object in array
125          - primary key is "db_id" + "cnt_id" + "arr_id"
126          - in column "value" is stored value of that primitive
127   
128   How objects are stored:
129    - "repository" tables are created automatically first time when db starts
130   
131    - when storing object of class that is inherited from other class(es),
132      every field is stored in table of class that declare that field.
133   
134    - if some class in hierarchy has no public fields, table for that class will
135      not be created, but class itself will be added to classes table.
136      example class is java.lang.Object
137   
138    - if object contains another object(s), than contained object(s) is stored
139      in object_contained table(s) with above rules
140   
141    - if object contains object array(s) than contained array(s) is stored in
142      object_array table(s) with above rules
143   
144    - if object has primitive array(s) than contained array(s) is stored in
145      primitive array table
146   
147   ******************************************************************************
148   
149   Example - storing object of class D:
150   
151     // A.java
152     package org.vrspace;
153     public class A {
154       public long db_id;
155       public int  a1 = 6;
156       public char a2 = 'a';
157     }
158   
159     // B.java
160     package org.vrspace;
161     public class B extends A {
162       public String b1 = "Hawkwind";
163     }
164   
165     // C.java
166     package org.vrspace;
167     public class C extends B {
168     }
169   
170     // D.java
171     package org.vrspace;
172     import java.net.URL;
173     import org.vrspace.test.*;
174     public class D extends C {
175       public long  d1 = 666;
176       public float d2 = 6.66f;
177       public URL   d3 = new URL("http://vrspace.org");
178       public E     d4 = new E();
179       public int[] d5 = new int[10];
180     }
181   
182     // E.java
183     package org.vrspace.test;
184     public class E {
185       public String  e1 = "Ozrics";
186       public int e2 = 6;
187     }
188   
189     contens of "repository":
190     ------------------------
191   
192           mysql> select * from classes;
193           +---------+--------------+-----------+--------------------+
194           | classID | superClassID | packageID | className          |
195           +---------+--------------+-----------+--------------------+
196           |       1 |            0 |         1 | java_lang_Object   |
197           |       2 |            1 |         2 | org_vrspace_A      |
198           |       3 |            2 |         2 | org_vrspace_B      |
199           |       4 |            3 |         2 | org_vrspace_C      |
200           |       5 |            4 |         2 | org_vrspace_D      |
201           |       6 |            1 |         3 | org_vrspace_test_E |
202           +---------+--------------+-----------+--------------------+
203   
204           mysql> select * from packages;
205           +-----------+------------------+
206           | packageID | packageName      |
207           +-----------+------------------+
208           |         1 | java_lang        |
209           |         2 | org_vrspace      |
210           |         3 | org_vrspace_test |
211           +-----------+------------------+
212   
213           mysql> select * from objects;
214           +----------+---------+
215           | objectID | classID |
216           +----------+---------+
217           |        1 |       5 |
218           +----------+---------+
219   
220     created "object" tables:
221     ------------------------
222   
223           mysql> describe org_vrspace_a;
224           +-------+--------------+------+-----+---------+-------+
225           | Field | Type         | Null | Key | Default | Extra |
226           +-------+--------------+------+-----+---------+-------+
227           | db_id | bigint(20)   |      | PRI | 0       |       |
228           | a1    | mediumint(9) | YES  |     | NULL    |       |
229           | a2    | char(1)      | YES  |     | NULL    |       |
230           +-------+--------------+------+-----+---------+-------+
231   
232           mysql> describe org_vrspace_b;
233           +-------+--------------+------+-----+---------+-------+
234           | Field | Type         | Null | Key | Default | Extra |
235           +-------+--------------+------+-----+---------+-------+
236           | db_id | bigint(20)   |      | PRI | 0       |       |
237           | b1    | varchar(255) | YES  |     | NULL    |       |
238           +-------+--------------+------+-----+---------+-------+
239   
240           mysql> describe org_vrspace_d;
241           +-------+--------------+------+-----+---------+-------+
242           | Field | Type         | Null | Key | Default | Extra |
243           +-------+--------------+------+-----+---------+-------+
244           | db_id | bigint(20)   |      | PRI | 0       |       |
245           | d1    | bigint(20)   | YES  |     | NULL    |       |
246           | d2    | float(10,2)  | YES  |     | NULL    |       |
247           | d3    | varchar(255) | YES  |     | NULL    |       |
248           | d4    | bigint(20)   | YES  |     | NULL    |       |
249           | d5    | bigint(20)   | YES  |     | NULL    |       |
250           +-------+--------------+------+-----+---------+-------+
251   
252           mysql> describe int_array;
253           +--------+--------------+------+-----+---------+-------+
254           | Field  | Type         | Null | Key | Default | Extra |
255           +--------+--------------+------+-----+---------+-------+
256           | db_id  | bigint(20)   |      | PRI | 0       |       |
257           | arr_id | bigint(20)   |      | PRI | 0       |       |
258           | nr_id  | bigint(20)   |      | PRI | 0       |       |
259           | value  | mediumint(9) | YES  |     | NULL    |       |
260           +--------+--------------+------+-----+---------+-------+
261   
262           mysql> describe org_vrspace_test_e_array;
263           +--------+--------------+------+-----+---------+-------+
264           | Field  | Type         | Null | Key | Default | Extra |
265           +--------+--------------+------+-----+---------+-------+
266           | db_id  | bigint(20)   |      | PRI | 0       |       |
267           | arr_id | bigint(20)   |      | PRI | 0       |       |
268           | nr_id  | bigint(20)   |      | PRI | 0       |       |
269           | e1     | varchar(255) | YES  |     | NULL    |       |
270           | e2     | mediumint(9) | YES  |     | NULL    |       |
271           +--------+--------------+------+-----+---------+-------+
272   
273     contens of "object" tables:
274     ---------------------------
275   
276           mysql> select * from org_vrspace_a;
277           +-------+------+------+
278           | db_id | a1   | a2   |
279           +-------+------+------+
280           |     1 |    6 | a    |
281           +-------+------+------+
282   
283           mysql> select * from org_vrspace_b;
284           +-------+----------+
285           | db_id | b1       |
286           +-------+----------+
287           |     1 | Hawkwind |
288           +-------+----------+
289   
290           mysql> select * from org_vrspace_d;
291           +-------+------+------+--------------------+------+------+
292           | db_id | d1   | d2   | d3                 | d4   | d5   |
293           +-------+------+------+--------------------+------+------+
294           |     1 |  666 | 6.66 | http://vrspace.org |    0 |    1 |
295           +-------+------+------+--------------------+------+------+
296   
297           mysql> select * from org_vrspace_test_e_array;
298           +-------+--------+-------+--------+------+
299           | db_id | arr_id | nr_id | e1     | e2   |
300           +-------+--------+-------+--------+------+
301           |     1 |      0 |     0 | Ozrics |    6 |
302           +-------+--------+-------+--------+------+
303   
304           mysql> select * from int_array;
305           +-------+--------+-------+-------+
306           | db_id | arr_id | nr_id | value |
307           +-------+--------+-------+-------+
308           |     1 |      0 |     1 |     0 |
309           |     1 |      1 |     1 |     0 |
310           |     1 |      2 |     1 |     0 |
311           |     1 |      3 |     1 |     0 |
312           |     1 |      4 |     1 |     0 |
313           |     1 |      5 |     1 |     0 |
314           |     1 |      6 |     1 |     0 |
315           |     1 |      7 |     1 |     0 |
316           |     1 |      8 |     1 |     0 |
317           |     1 |      9 |     1 |     0 |
318           +-------+--------+-------+-------+
319   @author eddie@vrspace.org
320 */
321 
322 public abstract class SQLDB extends DB {
323 
324   // object field types, needed for storing field info (name/type) in repository
325   // and later for faster retrieving/storing values in fields
326   protected static final int BOOLEAN        = 1;
327   protected static final int BYTE           = 2;
328   protected static final int SHORT          = 3;
329   protected static final int INT            = 4;
330   protected static final int LONG           = 5;
331   protected static final int FLOAT          = 6;
332   protected static final int DOUBLE         = 7;
333   protected static final int CHAR           = 8;
334   protected static final int FLOAT_OBJ      = 9;
335   protected static final int STRING_OBJ     = 10;
336   protected static final int DATE_OBJ       = 11;
337   protected static final int URL_OBJ        = 12;
338   protected static final int OBJECT         = 13;
339   protected static final int BOOLEAN_ARR    = 14;
340   protected static final int BYTE_ARR       = 15;
341   protected static final int SHORT_ARR      = 16;
342   protected static final int INT_ARR        = 17;
343   protected static final int LONG_ARR       = 18;
344   protected static final int FLOAT_ARR      = 19;
345   protected static final int DOUBLE_ARR     = 20;
346   protected static final int CHAR_ARR       = 21;
347   protected static final int FLOAT_OBJ_ARR  = 22;
348   protected static final int STRING_OBJ_ARR = 23;
349   protected static final int DATE_OBJ_ARR   = 24;
350   protected static final int URL_OBJ_ARR    = 25;
351   protected static final int OBJECT_ARR     = 26;
352 
353   // field types as text for forming SQL text, DB dependent,
354   // value must be provided in actual DB implementation (subclass of this class)
355   protected String BYTE_TYPE;
356   protected String SHORT_TYPE;
357   protected String INT_TYPE;
358   protected String LONG_TYPE;
359   protected String FLOAT_TYPE;
360   protected String DOUBLE_TYPE;
361   protected String CHAR_TYPE;
362   protected String STRING_TYPE;
363   protected String DATE_TYPE;
364 
365   // SQL text of various queries, DB dependent,
366   // value must be provided in actual DB implementation (subclass of this class)
367   protected String SQL_SHOW_TABLES;
368   protected String SQL_CREATE_OBJECTS_TABLE;
369   protected String SQL_CREATE_CLASSES_TABLE;
370   protected String SQL_CREATE_PACKAGES_TABLE;
371   protected String SQL_COUNT_OBJECTS;
372   protected String SQL_COUNT_CLASSES;
373   protected String SQL_COUNT_PACKAGES;
374   protected String SQL_GET_CLASSES;
375   protected String SQL_CHECK_CLASS;
376   protected String SQL_CHECK_PACKAGE;
377   protected String SQL_INSERT_CLASS;
378   protected String SQL_INSERT_PACKAGE;
379   protected String SQL_INSERT_OBJECT;
380   protected String SQL_DELETE_OBJECT;
381   protected String SQL_DEL_OBJECT;
382   protected String SQL_GET_OBJECT_1;
383   protected String SQL_GET_OBJECT_2;
384   protected String SQL_GET_OBJECT_3;
385   protected String SQL_GET_OBJECT_4;
386   protected String SQL_CREATE_OBJ_TABLE_1;
387   protected String SQL_CREATE_OBJ_TABLE_2;
388   protected String SQL_INSERT_PRIM_1;
389   protected String SQL_INSERT_PRIM_2;
390   protected String SQL_CREATE_PRIM_TABLE_1;
391   protected String SQL_CREATE_PRIM_TABLE_2;
392   protected String SQL_CREATE_PRIM_TABLE_3;
393   protected String SQL_GET_ARR_1;
394   protected String SQL_GET_ARR_2;
395   protected String SQL_GET_ARR_3;
396   protected String SQL_GET_ARR_4;
397   protected String SQL_GET_PRIM_ARR_1;
398   protected String SQL_GET_PRIM_ARR_2;
399   protected String SQL_GET_PRIM_ARR_3;
400   protected String SQL_GET_OBJ_ARR_1;
401   protected String SQL_GET_OBJ_ARR_2;
402   protected String SQL_GET_OBJ_ARR_3;
403   protected String SQL_GET_RANGE_1;
404   protected String SQL_GET_RANGE_2;
405   protected String SQL_GET_RANGE_3;
406   protected String SQL_GET_ALL;
407 
408   PreparedStatement stmtCheckClass;
409   PreparedStatement stmtCheckPackage;
410   PreparedStatement stmtInsertClass;
411   PreparedStatement stmtInsertPackage;
412   PreparedStatement stmtInsertObject;
413   PreparedStatement stmtDeleteObject;
414   PreparedStatement stmtDelObject;
415   PreparedStatement stmtGetObject;
416   PreparedStatement stmtInsertPrim;
417 
418   Connection conn;
419   Statement  stmt;
420   ResultSet  rs;
421 
422   static long objID = 0;
423   static long pkgID = 0;
424   static long clsID = 0;
425 
426   /**
427   in-memory repository that contains information about classes
428   key: class name
429   value: SQLClass object
430   */
431   static HashMap clsRepository;
432 
433   Logger logger = new Logger();
434 
435 
436   /** Override this in actual implementations. Called from connect( String ) */
437   protected abstract boolean loadDriver();
438 
439   public abstract String create( String name );
440 
441   /**
442   Connect to the database
443   @param name database URL
444   */
445   public void connect( String name ) throws Exception {
446 
447     loadDriver();
448     conn = DriverManager.getConnection( name );
449     stmt                = conn.createStatement();
450     stmtCheckClass      = conn.prepareStatement( SQL_CHECK_CLASS       );
451     stmtCheckPackage    = conn.prepareStatement( SQL_CHECK_PACKAGE     );
452     stmtInsertClass     = conn.prepareStatement( SQL_INSERT_CLASS      );
453     stmtInsertPackage   = conn.prepareStatement( SQL_INSERT_PACKAGE    );
454     stmtInsertObject    = conn.prepareStatement( SQL_INSERT_OBJECT     );
455     stmtDeleteObject    = conn.prepareStatement( SQL_DELETE_OBJECT     );
456     stmtDelObject       = conn.prepareStatement( SQL_DEL_OBJECT        );
457     //stmtGetObject       = conn.prepareStatement( SQL_GET_OBJECT        );
458     //stmtCreatePrimTable = conn.prepareStatement( SQL_CREATE_PRIM_TABLE );
459     //stmtInsertPrim      = conn.prepareStatement( SQL_INSERT_PRIM       );
460 
461     // first time create repository tables
462     rs = query( SQL_SHOW_TABLES );
463     if ( ! rs.next() ) {
464       update( SQL_CREATE_OBJECTS_TABLE );
465       update( SQL_CREATE_CLASSES_TABLE );
466       update( SQL_CREATE_PACKAGES_TABLE );
467     }
468 
469     // find ID's
470     // - objects can be deleted so count() is not valid for ID detection
471     // - classes and packages can't be deleted, count() is OK
472     synchronized( this ) {
473       rs = query( SQL_COUNT_OBJECTS );
474       rs.next();
475       objID = rs.getLong(1);
476       Logger.logDebug("max ID = " + objID );
477 
478       rs = query( SQL_COUNT_CLASSES );
479       rs.next();
480       clsID = rs.getLong(1);
481 
482       rs = query( SQL_COUNT_PACKAGES );
483       rs.next();
484       pkgID = rs.getLong(1);
485     }
486 
487     // create and load in-memory repository
488     clsRepository = new HashMap( (int)clsID );
489     rs = query( SQL_GET_CLASSES );
490     while ( rs.next() ) {
491       SQLClass sqlcls     = new SQLClass();
492       sqlcls.classID      = rs.getLong(1);
493       sqlcls.superClassID = rs.getLong(2);
494       sqlcls.packageID    = rs.getLong(3);
495       sqlcls.className    = rs.getString(4);
496       sqlcls.stmt = conn.prepareStatement( rs.getString(5) );
497       StringTokenizer st = new StringTokenizer( rs.getString(6), ",;" );
498       int nrOfFields = Integer.parseInt( st.nextToken() );
499       if ( nrOfFields == 0 ) {
500         continue;
501       }
502       sqlcls.fieldNames = new String[nrOfFields];
503       sqlcls.fieldTypes = new int[nrOfFields];
504       sqlcls.fieldCntIDs = new long[nrOfFields];
505       sqlcls.fields = new Field[nrOfFields];
506       for ( int i=0; i<nrOfFields; i++ ) {
507         sqlcls.fieldNames[i] = st.nextToken();
508         sqlcls.fieldTypes[i] = Integer.parseInt( st.nextToken() );
509         sqlcls.fieldCntIDs[i] = Long.parseLong( st.nextToken() );
510         sqlcls.fields[i] = Class.forName(sqlcls.className.replace('_','.')).getField( sqlcls.fieldNames[i] );
511       }
512       synchronized( this ) {
513         clsRepository.put( sqlcls.className, sqlcls );
514       }
515     }
516 
517   }
518 
519 
520   /**
521   Stores <b>obj</b> to the database.
522   */
523   public void put( Object obj ) throws Exception {
524     Class objClass = obj.getClass();
525 
526     if ( obj == null ){
527       Logger.logWarning( "SQLDB: object of class " + objClass.getName() + " is null!" );
528       return;
529     }
530 
531     SQLClass sqlcls = analizeClass( objClass );
532 
533     // create and assign new unique id to this object
534     long objectID = getObjectID( sqlcls.classID );   
535     try {
536       objClass.getField( "db_id" ).setLong( obj, objectID );
537     } catch ( NoSuchFieldException e1 ) {
538       Logger.logError( "SQLDB: db_id field in " + sqlcls.className + " doesn't exist!");
539       return;
540     } catch ( SecurityException e2 ) {
541       Logger.logError( "SQLDB: db_id field in " + sqlcls.className + " can't be modified!");
542       return;
543     }
544 
545     do {
546       insertObject( obj, objectID, getClass(objClass), 0, 0 );
547       objClass = objClass.getSuperclass();
548     } while ( objClass != null );
549 
550   }
551 
552 
553   /**
554   Stores object array to the database.
555   */
556   public void put( Object[] obj ) throws Exception {
557     Class objClass = obj.getClass().getComponentType();
558 
559     if ( obj == null ){
560       Logger.logWarning( "SQLDB: object of class " + objClass.getName() + " is null!" );
561       return;
562     }
563 
564     SQLClass sqlcls = analizeClass( objClass );
565 
566     // create and assign new unique id to this object
567     long objectID = getObjectID( sqlcls.classID );   
568     try {
569       objClass.getField( "db_id" ).setLong( obj, objectID );
570     } catch ( NoSuchFieldException e1 ) {
571       Logger.logError( "SQLDB: db_id field in " + sqlcls.className + " doesn't exist!");
572       return;
573     } catch ( SecurityException e2 ) {
574       Logger.logError( "SQLDB: db_id field in " + sqlcls.className + " can't be modified!");
575       return;
576     }
577 
578     for ( int i=0; i<obj.length; i++ ) {
579       do {
580         insertObject( obj, objectID, getClass(objClass), 0, i );
581         objClass = objClass.getSuperclass();
582       } while ( objClass != null );
583     }
584 
585   }
586 
587 
588   /**
589   Internal, called from put(Object obj) and put(Object[] obj)
590   */
591   protected void insertObject( Object obj, long objectID, SQLClass cls, long cntID, long arrID ) 
592                              throws Exception {
593     if ( cls == null || cls.fieldNames.length == 0) {
594       return;
595     }
596 
597     PreparedStatement stmt = cls.stmt;
598     int fldNr = 1;
599     // set object ID
600     stmt.setLong( fldNr++, objectID );
601     // check if object is contained inside another object
602     stmt.setLong( fldNr++, cntID );
603     // check if object is member of array
604     stmt.setLong( fldNr++, arrID );
605     if ( obj == null ) {
606       stmt.setByte( fldNr++, (byte)1 );
607       stmt.executeUpdate();
608       return;
609     } else {
610       stmt.setByte( fldNr++, (byte)0 );
611     }
612 
613     // set object's fields
614     int size = cls.fieldNames.length;
615     Class objClass = obj.getClass();
616     for ( int i=0; i<size; i++ ) {
617       Field field = objClass.getField( cls.fieldNames[i] );
618       int type = cls.fieldTypes[i];
619       switch( type ) {
620         // primitive
621         case BOOLEAN: boolean bool = field.getBoolean(obj);
622                       if ( bool ) {
623                         stmt.setByte( fldNr, (byte)1 );
624                       } else {
625                         stmt.setByte( fldNr, (byte)0 );
626                       }
627                       break;
628         case BYTE:    stmt.setByte( fldNr, field.getByte(obj) );
629                       break;
630         case SHORT:   stmt.setShort( fldNr, field.getShort(obj) );
631                       break;
632         case INT:     stmt.setInt( fldNr, field.getInt(obj) );
633                       break;
634         case LONG:    stmt.setLong( fldNr, field.getLong(obj) );
635                       break;
636         case FLOAT:   stmt.setFloat( fldNr, field.getFloat(obj) );
637                       break;
638         case DOUBLE:  stmt.setDouble( fldNr, field.getDouble(obj) );
639                       break;
640         case CHAR:    stmt.setString( fldNr, new Character(field.getChar(obj)).toString() );
641                       break;
642         // object (mapped to primitive)
643         case STRING_OBJ: String s = (String)field.get(obj);
644                          if ( s == null ) {
645                            stmt.setNull( fldNr, Types.VARCHAR );
646                          } else {
647                            stmt.setString( fldNr, s );
648                          }
649                          break;
650         case FLOAT_OBJ:  Float f = (Float)field.get(obj);
651                          if ( f == null ) {
652                            stmt.setNull( fldNr, Types.FLOAT );
653                          } else {
654                            stmt.setFloat( fldNr, f.floatValue() );
655                          }
656                          break;
657         case DATE_OBJ:   Date date = (Date)field.get(obj);
658                          if ( date == null ) {
659                            stmt.setNull( fldNr, Types.DATE );
660                          } else {
661                            stmt.setDate( fldNr, new java.sql.Date(date.getTime()) );
662                          }
663                          break;
664         case URL_OBJ:    URL url = (URL)field.get(obj);
665                          if ( url == null ) {
666                            stmt.setNull( fldNr, Types.VARCHAR );
667                          } else {
668                            stmt.setString( fldNr, url.toString() );
669                          }
670                          break;
671         // object (general)
672         case OBJECT:     Object o = field.get(obj); 
673                          if ( o == null ) {
674                            stmt.setNull( fldNr, Types.BIGINT );
675                          } else {
676                            // object must be put in another table - recursive call to this method
677                            long cnt_id = cls.fieldCntIDs[i];
678                            stmt.setLong( fldNr, cnt_id );
679                            insertObject( o, objectID, getClass(o.getClass()), cnt_id, 0 );
680                          }
681                          break;
682         // primitive array and object(mapped to primitive) array
683         case BOOLEAN_ARR:
684         case BYTE_ARR:
685         case SHORT_ARR:
686         case INT_ARR:
687         case LONG_ARR:
688         case FLOAT_ARR:
689         case DOUBLE_ARR:
690         case CHAR_ARR:
691         case FLOAT_OBJ_ARR:
692         case STRING_OBJ_ARR:
693         case DATE_OBJ_ARR:
694         case URL_OBJ_ARR:
695                          Object ob = field.get(obj);
696                          if ( ob == null ) {
697                            stmt.setNull( fldNr, Types.BIGINT );
698                            continue;
699                          } else {
700                            long cnt_id = cls.fieldCntIDs[i];
701                            stmt.setLong( fldNr, cnt_id );
702                            putPrimitiveArray( ob, objectID, cnt_id );
703                          }
704                          break;
705         // object(general) array
706         case OBJECT_ARR: Object[] obj_arr = (Object[])field.get(obj);
707                          if ( obj_arr == null ) {
708                            stmt.setNull( fldNr, Types.BIGINT );
709                            continue;
710                          } else {
711                            long cnt_id = cls.fieldCntIDs[i];
712                            stmt.setLong( fldNr, cnt_id );
713                            Class obj_arrClass = obj_arr.getClass().getComponentType();
714                            do {
715                              SQLClass sqlcls = getClass(obj_arrClass);
716                              for ( int j=0; j<obj_arr.length; j++ ) {
717                                insertObject( obj_arr[j], objectID, sqlcls, cnt_id, j );
718                                obj_arrClass = obj_arrClass.getSuperclass();
719                              }
720                            } while ( obj_arrClass != null );
721                          }
722                          break;
723       }
724       fldNr++;
725     }
726     stmt.executeUpdate();
727 
728   }
729 
730 
731   /**
732   Internal
733   */
734   protected void putPrimitiveArray( Object obj, long objectID, long cntID )
735                  throws Exception {
736     String type = obj.getClass().getComponentType().getName();
737 
738     stmtInsertPrim = conn.prepareStatement( SQL_INSERT_PRIM_1 + replacePoints(type) + SQL_INSERT_PRIM_2 );
739     stmtInsertPrim.setLong( 1, objectID );
740     stmtInsertPrim.setLong( 2, cntID );
741 
742     int length = ((Object[])obj).length;
743     for (int ind = 0; ind < length; ind++) {
744       stmtInsertPrim.setLong( 3, ind );
745       if ( type.equals("boolean") ) {
746         Boolean bool = new Boolean( Array.getBoolean(obj, ind) );
747         if ( bool.toString().equals("true") ) {
748            stmtInsertPrim.setByte( 4, (byte)1 );
749         } else {
750            stmtInsertPrim.setByte( 4, (byte)0 );
751         }
752       } else if ( type.equals("byte") )  {
753         stmtInsertPrim.setByte( 4, Array.getByte(obj, ind) );
754       } else if ( type.equals("short") )  {
755         stmtInsertPrim.setShort( 4, Array.getShort(obj, ind) );
756       } else if ( type.equals("int") )  {
757         stmtInsertPrim.setInt( 4, Array.getInt(obj, ind) );
758       } else if ( type.equals("long") )  {
759         stmtInsertPrim.setLong( 4, Array.getLong(obj, ind) );
760       } else if ( type.equals("float") )  {
761         stmtInsertPrim.setFloat( 4, Array.getFloat(obj, ind) );
762       } else if ( type.equals("double") )  {
763         stmtInsertPrim.setDouble( 4, Array.getDouble(obj, ind) );
764       } else if ( type.equals("char") ) {
765         stmtInsertPrim.setString( 4, String.valueOf(Array.getChar(obj, ind)) );
766       } else if ( type.equals("java.lang.Float") ) {
767         Float f = (Float)Array.get(obj, ind);
768         if ( f == null ) {
769           stmtInsertPrim.setNull( 4, Types.VARCHAR );
770         } else {
771           stmtInsertPrim.setFloat( 4, f.floatValue() );
772         }
773       } else if ( type.equals("java.lang.String") ) {
774         String s = (String)Array.get(obj, ind);
775         if ( s == null ) {
776           stmtInsertPrim.setNull( 4, Types.VARCHAR );
777         } else {
778           stmtInsertPrim.setString( 4, s );
779         }
780       } else if ( type.equals("java.net.URL") ) {
781         URL url = (URL)Array.get(obj, ind);
782         if ( url == null ) {
783           stmtInsertPrim.setNull( 4, Types.VARCHAR );
784         } else {
785           stmtInsertPrim.setString( 4, url.toString() );
786         }
787       } else if ( type.equals("java.util.Date") ) {
788         Date date = (Date)Array.get(obj, ind);
789         if ( date == null ) {
790           stmtInsertPrim.setNull( 4, Types.BIGINT );
791         } else {
792           stmtInsertPrim.setLong( 4, date.getTime() );
793         }
794       }
795       stmtInsertPrim.executeUpdate();
796     }
797 
798   }
799 
800 
801   /**
802   Retreives an object from the database
803   */
804   public Object get( Object obj ) throws Exception {
805     String className = obj.getClass().getName();
806     long db_id = obj.getClass().getField("db_id").getLong( obj );
807     return getObject( className, db_id, 0, 0 );
808   }
809 
810 
811   /**
812   Retreives an object from the database
813   */
814   public Object get( String className, long id ) throws Exception {
815     Class  objClass = Class.forName( className );
816     Object obj      = objClass.newInstance();
817     objClass.getField("db_id").setLong( obj, id );
818     return getObject( obj, id, 0, 0 );
819   }
820 
821 
822   /**
823   Retreives an object from the database, internal
824   */
825   protected Object getObject( Object obj, long id, long cntID, long arrID ) throws Exception {
826     Statement getStmt = conn.createStatement();
827 
828     Class objClass = obj.getClass();
829     boolean firstTime = true;
830 
831     while ( true ) {
832       if ( firstTime ) {
833         firstTime = false;
834       } else {
835         objClass = objClass.getSuperclass();
836         if ( objClass.getName().equals("java.lang.Object") ) {
837           break;
838         }
839       }
840       SQLClass sqlcls = getClass(objClass);
841       if ( sqlcls == null || sqlcls.fields.length == 0 ) {
842         continue;
843       }
844 
845       StringBuffer sqlText = new StringBuffer(255);
846       sqlText.append( SQL_GET_OBJECT_1 );
847       sqlText.append( replacePoints(sqlcls.className) );
848       sqlText.append( SQL_GET_OBJECT_2 );
849       sqlText.append( id );
850       sqlText.append( SQL_GET_OBJECT_3 );
851       sqlText.append( cntID );
852       sqlText.append( SQL_GET_OBJECT_4 );
853       sqlText.append( arrID );
854       ResultSet getRs = getStmt.executeQuery( sqlText.toString() );
855       if ( !getRs.next() ) {
856         continue;
857       }
858       if ( getRs.getByte("isNull") == 1) {
859         return null;
860       }
861 
862       for ( int i=0; i<sqlcls.fields.length; i++ ) {
863         int type = sqlcls.fieldTypes[i];
864         switch (type) {
865           case BOOLEAN:     if ( getRs.getByte(sqlcls.fieldNames[i]) == 1 ) {
866                               sqlcls.fields[i].setBoolean( obj, true );
867                             } else {
868                               sqlcls.fields[i].setBoolean( obj, false );
869                             }
870                             break;
871           case BYTE:        sqlcls.fields[i].setByte( obj, getRs.getByte(sqlcls.fieldNames[i]) );
872                             break;
873           case SHORT:       sqlcls.fields[i].setShort( obj, getRs.getShort(sqlcls.fieldNames[i]) );
874                             break;
875           case INT:         sqlcls.fields[i].setInt( obj, getRs.getInt(sqlcls.fieldNames[i]) );
876                             break;
877           case LONG:        sqlcls.fields[i].setLong( obj, getRs.getLong(sqlcls.fieldNames[i]) );
878                             break;
879           case FLOAT:       sqlcls.fields[i].setFloat( obj, getRs.getFloat(sqlcls.fieldNames[i]) );
880                             break;
881           case DOUBLE:      sqlcls.fields[i].setDouble( obj, getRs.getDouble(sqlcls.fieldNames[i]) );
882                             break;
883           case CHAR:        sqlcls.fields[i].setChar( obj, getRs.getString(sqlcls.fieldNames[i]).charAt(0) );
884                             break;
885           case STRING_OBJ:  sqlcls.fields[i].set( obj, getRs.getString(sqlcls.fieldNames[i]) );
886                             break;
887           case FLOAT_OBJ:   float f = getRs.getFloat( sqlcls.fieldNames[i] );
888                             if ( rs.wasNull() ) {
889                               sqlcls.fields[i].set( obj, null );
890                             } else {
891                               sqlcls.fields[i].set( obj, new Float(f) );
892                             }
893                             break;
894           case DATE_OBJ:    sqlcls.fields[i].set( obj, getRs.getDate(sqlcls.fieldNames[i]) );
895                             break;
896           case URL_OBJ:     URL url = new URL( getRs.getString(sqlcls.fieldNames[i]) );
897                             if ( rs.wasNull() ) {
898                               sqlcls.fields[i].set( obj, null );
899                             } else {
900                               sqlcls.fields[i].set( obj, url );
901                             }
902                             break;
903           case OBJECT:      long obj_cntID = getRs.getLong( sqlcls.fieldNames[i] );
904                             if ( rs.wasNull() ) {
905                               sqlcls.fields[i].set( obj, null );
906                             } else {
907                               String clsName = sqlcls.fields[i].getType().getName();
908                               Object o = getObject( clsName, id, obj_cntID, 0 );
909                               sqlcls.fields[i].set( obj, o );
910                             }
911                             break;
912           case BOOLEAN_ARR:
913           case BYTE_ARR:
914           case SHORT_ARR:
915           case INT_ARR:
916           case LONG_ARR:
917           case FLOAT_ARR:
918           case DOUBLE_ARR:
919           case CHAR_ARR:
920           case FLOAT_OBJ_ARR:
921           case STRING_OBJ_ARR:
922           case DATE_OBJ_ARR:
923           case URL_OBJ_ARR: long prim_arr_cntID = getRs.getLong( sqlcls.fieldNames[i] );
924                             if ( rs.wasNull() ) {
925                               sqlcls.fields[i].set( obj, null );
926                             } else {
927                               String clsPrimName = sqlcls.fields[i].getType().getComponentType().getName();
928                               sqlcls.fields[i].set( obj, getPrimitiveArray(clsPrimName, type, id, prim_arr_cntID) );
929                             }
930                             break;
931           case OBJECT_ARR:  long obj_arr_cntID = getRs.getLong( sqlcls.fieldNames[i] );
932                             if ( rs.wasNull() ) {
933                               sqlcls.fields[i].set( obj, null );
934                             } else {
935                               String clsArrName = sqlcls.fields[i].getType().getComponentType().getName();
936                               sqlcls.fields[i].set( obj, getObjectArray(clsArrName, id, obj_arr_cntID) );
937                             }
938                             break;
939         }
940       }
941     }
942 
943     return obj;
944   }
945 
946 
947   /**
948   Internal
949   */
950   protected Object getPrimitiveArray( String className, int type, long id, long cntID ) throws Exception {
951     StringBuffer sqlText = new StringBuffer(256);
952     sqlText.append( SQL_GET_ARR_1 );
953     sqlText.append( replacePoints(className) );
954     sqlText.append( SQL_GET_ARR_2 );
955     sqlText.append( id );
956     sqlText.append( SQL_GET_ARR_3 );
957     sqlText.append( cntID );
958     sqlText.append( SQL_GET_ARR_4 );
959     rs = query( sqlText.toString() );
960     rs.next();
961     Object obj = Array.newInstance( Class.forName(className), rs.getInt(1) );
962 
963     sqlText = new StringBuffer(256);
964     sqlText.append( SQL_GET_PRIM_ARR_1 );
965     sqlText.append( replacePoints(className) );
966     sqlText.append( SQL_GET_PRIM_ARR_2 );
967     sqlText.append( id );
968     sqlText.append( SQL_GET_PRIM_ARR_3 );
969     sqlText.append( cntID );
970     rs = query( sqlText.toString() );
971 
972     int nr = 0;
973     while ( rs.next() ) {
974       switch( type ) {
975         case BOOLEAN_ARR:    if ( rs.getByte(1) == 1 ) {
976                                Array.setBoolean( obj, nr, true );
977                              } else {
978                                Array.setBoolean( obj, nr, false );
979                              }
980                              break;
981         case BYTE_ARR:       Array.setByte( obj, nr, rs.getByte(1) );
982                              break;
983         case SHORT_ARR:      Array.setShort( obj, nr, rs.getShort(1) );
984                              break;
985         case INT_ARR:        Array.setInt( obj, nr, rs.getInt(1) );
986                              break;
987         case LONG_ARR:       Array.setLong( obj, nr, rs.getLong(1) );
988                              break;
989         case FLOAT_ARR:      Array.setFloat( obj, nr, rs.getFloat(1) );
990                              break;
991         case DOUBLE_ARR:     Array.setDouble( obj, nr, rs.getDouble(1) );
992                              break;
993         case CHAR_ARR:       Array.setChar( obj, nr, rs.getString(1).charAt(0) );
994                              break;
995         case STRING_OBJ_ARR: Array.set( obj, nr, rs.getString(1) );
996                              break;
997         case FLOAT_OBJ_ARR:  float f = rs.getFloat(1);
998                              if ( rs.wasNull() ) {
999                                Array.set( obj, nr, null );
1000                             } else {
1001                               Array.set( obj, nr, new Float(f) );
1002                             }
1003                             break;
1004        case DATE_OBJ_ARR:   Array.set( obj, nr, rs.getDate(1) );
1005                             break;
1006        case URL_OBJ_ARR:    URL url = new URL( rs.getString(1) );
1007                             if ( rs.wasNull() ) {
1008                               Array.set( obj, nr, null );
1009                             } else {
1010                               Array.set( obj, nr, url );
1011                             }
1012                             break;
1013      }
1014      nr++;
1015    }
1016
1017    return obj;
1018  }
1019
1020
1021  /**
1022  Internal
1023  */
1024  protected Object getObjectArray( String className, long id, long cntID ) throws Exception {
1025    StringBuffer sqlText = new StringBuffer(256);
1026    sqlText.append( SQL_GET_ARR_1 );
1027    sqlText.append( replacePoints(className) );
1028    sqlText.append( SQL_GET_ARR_2 );
1029    sqlText.append( id );
1030    sqlText.append( SQL_GET_ARR_3 );
1031    sqlText.append( cntID );
1032    sqlText.append( SQL_GET_ARR_4 );
1033    rs = query( sqlText.toString() );
1034    rs.next();
1035    int nr = rs.getInt(1);
1036
1037    Class objClass = Class.forName(className);
1038    Object obj = Array.newInstance( objClass, nr );
1039    for ( int i=0; i<nr; i++ ) {
1040      Array.set( obj, i, getObject(objClass.newInstance(), id, cntID, i) );
1041    }
1042
1043    return obj;
1044  }
1045
1046
1047  /**
1048  Get first object of class <B>className</B>, whose <B>field</B> field have value <B>value</B>
1049  */
1050  public Object get( String className, String field, Object value ) throws Exception {
1051    rs = getRangeDb_id( className, field, value );
1052    if ( rs == null ) {
1053      return null;
1054    }
1055    if ( rs.next() ) {
1056      return get(className, rs.getLong("db_id"));
1057    }
1058    return null;
1059  }
1060
1061
1062  /**
1063  Get all objects of class <B>className</B>, whose <B>field</B> field have value <B>value</B>
1064  */
1065  public Object[] getRange( String className, String field, Object value ) throws Exception {
1066    SQLClass sqlcls = (SQLClass)clsRepository.get( replacePoints(className) );
1067    int type = 0;
1068    for ( int i=0; i<sqlcls.fieldNames.length; i++ ) {
1069      if ( sqlcls.fieldNames[i].equals(field) ) {
1070        type = sqlcls.fieldTypes[i];
1071        break;
1072      }
1073    }
1074
1075    switch (type) {
1076      case BOOLEAN:
1077      case BYTE:
1078      case SHORT:
1079      case INT:
1080      case LONG:
1081      case FLOAT:
1082      case DOUBLE:
1083      case CHAR:
1084      case STRING_OBJ:
1085      case FLOAT_OBJ:
1086      case DATE_OBJ:
1087      case URL_OBJ:   StringBuffer sqlText = new StringBuffer(256);
1088                      sqlText.append( SQL_GET_RANGE_1 );
1089                      sqlText.append( replacePoints(className) );
1090                      sqlText.append( SQL_GET_RANGE_2 );
1091                      sqlText.append( field );
1092                      sqlText.append( " = " );
1093                      if ( value instanceof String ) {
1094                        sqlText.append( " '" );
1095                        sqlText.append( value );
1096                        sqlText.append( "' " );
1097                      } else {
1098                        sqlText.append( value );
1099                      }
1100                      sqlText.append( SQL_GET_RANGE_3 );
1101                      rs = query( sqlText.toString() );
1102                      ArrayList arr = new ArrayList();
1103                      while ( rs.next() ) {
1104                        arr.add( get(className, rs.getLong("db_id")) );
1105                      }
1106                      return arr.toArray();
1107
1108      case OBJECT:
1109
1110      case BOOLEAN_ARR:
1111      case BYTE_ARR:
1112      case SHORT_ARR:
1113      case INT_ARR:
1114      case LONG_ARR:
1115      case FLOAT_ARR:
1116      case DOUBLE_ARR:
1117      case CHAR_ARR:
1118      case STRING_OBJ_ARR:
1119      case FLOAT_OBJ_ARR:
1120      case DATE_OBJ_ARR:
1121      case URL_OBJ_ARR:
1122
1123      case OBJECT_ARR:
1124    }
1125
1126    return null;
1127  }
1128
1129
1130  /** unfinished, work only for primitive fields not objects
1131  Internal
1132  */
1133  protected ResultSet getRangeDb_id( String className, String field, Object value ) {
1134    SQLClass sqlcls = (SQLClass)clsRepository.get( replacePoints(className) );
1135    int type = 0;
1136    for ( int i=0; i<sqlcls.fieldNames.length; i++ ) {
1137      if ( sqlcls.fieldNames[i].equals(field) ) {
1138        type = sqlcls.fieldTypes[i];
1139        break;
1140      }
1141    }
1142
1143    switch (type) {
1144      case BOOLEAN:
1145      case BYTE:
1146      case SHORT:
1147      case INT:
1148      case LONG:
1149      case FLOAT:
1150      case DOUBLE:
1151      case CHAR:
1152      case STRING_OBJ:
1153      case FLOAT_OBJ:
1154      case DATE_OBJ:
1155      case URL_OBJ:   StringBuffer sqlText = new StringBuffer(256);
1156                      sqlText.append( SQL_GET_RANGE_1 );
1157                      sqlText.append( replacePoints(className) );
1158                      sqlText.append( SQL_GET_RANGE_2 );
1159                      sqlText.append( field );
1160                      sqlText.append( " = " );
1161                      if ( value instanceof String ) {
1162                        sqlText.append( " '" );
1163                        sqlText.append( value );
1164                        sqlText.append( "' " );
1165                      } else {
1166                        sqlText.append( value );
1167                      }
1168                      sqlText.append( SQL_GET_RANGE_3 );
1169                      return query( sqlText.toString() );
1170
1171      case OBJECT:
1172    }
1173
1174    return null;
1175  }
1176
1177
1178  /**
1179  Get all objects that are "between" object <B>o1</B> and <B>o2</B>.
1180  Object <B>o1</B> and <B>o2</B> must be of same class, and must have
1181  implement method compareTo(obj) (interface Comparable), else null is returned.
1182  */
1183  public Object[] getRange( Object o1, Object o2 ) throws Exception {
1184    String className = o1.getClass().getName();
1185    if ( !className.equals(o2.getClass().getName()) ) {
1186      return null;
1187    }
1188    Method compareTo = null;
1189    try {
1190      Class[] cls = new Class[1];
1191      cls[0] = Class.forName("java.lang.Object");
1192      compareTo = o1.getClass().getMethod("compareTo", cls);
1193    } catch (NoSuchMethodException e1) {
1194      return null;
1195    } catch (Exception e2) {
1196      return null;
1197    }
1198
1199    Object[] obj = getAll(className);
1200    Object[] o1_arr = new Object[1];
1201    o1_arr[0] = o1;
1202    Object[] o2_arr = new Object[1];
1203    o2_arr[0] = o2;
1204    ArrayList arr = new ArrayList();
1205    for ( int i=0; i<obj.length; i++ ) {
1206      int comp1 = ((Integer)compareTo.invoke(obj[i], o1_arr)).intValue();
1207      int comp2 = ((Integer)compareTo.invoke(obj[i], o2_arr)).intValue();
1208      if ( comp1 > 0  &&  comp2 < 0 ) {
1209        arr.add( obj[i] );
1210      }
1211    }
1212    return arr.toArray();
1213  }
1214
1215
1216  /**
1217  Get all objects of <B>className</B> from db
1218  */
1219  public Object[] getAll( String className ) throws Exception {
1220    StringBuffer sqlText = new StringBuffer(256);
1221    sqlText.append( SQL_GET_ALL );
1222    sqlText.append( replacePoints(className) );
1223    Statement getAllStmt = conn.createStatement();
1224    ResultSet getAllRs = getAllStmt.executeQuery( sqlText.toString() );
1225
1226    ArrayList arr = new ArrayList();
1227    while ( getAllRs.next() ) {
1228      arr.add( get(className, getAllRs.getLong("db_id")) );
1229    }
1230    return arr.toArray();
1231  }
1232
1233
1234  /**
1235  Update field in object. Field and object are encapsulated inside request object.
1236  */
1237  public void update( Request r ) {
1238    StringBuffer sqlText = new StringBuffer(256);
1239    sqlText.append( " UPDATE " );
1240    sqlText.append( replacePoints(r.getClassName()) );
1241    sqlText.append( " SET " );
1242    sqlText.append( r.getEventName() );
1243    sqlText.append( " = " );
1244    sqlText.append( r.getEventValue() );
1245    sqlText.append( " WHERE db_id = " );
1246    sqlText.append( r.object.db_id );
1247    sqlText.append( " AND cnt_id = 0 AND arr_id = 0" );
1248    try {
1249      stmt.executeUpdate( sqlText.toString() );
1250    } catch ( SQLException e ) {
1251      Logger.logError( "SQLDB: error while updating " + r.getEventName() + " in " +
1252                       r.getClassName() + " class!" );
1253    }
1254  }
1255
1256
1257  /**
1258  Delete object from database.
1259  This implementation works but is just temporary, needs complete rewrite
1260  */
1261  public void delete( Object obj ) throws Exception {
1262    long db_id = obj.getClass().getField("db_id").getLong( obj );
1263    int count = 0;
1264
1265    rs = query( SQL_SHOW_TABLES );
1266    while ( rs.next() ) {
1267      String table = rs.getString(1);
1268      if ( table.equals("classes") || table.equals("packages") ) {
1269        continue;
1270      }
1271      if ( table.equals("objects") ) {
1272        stmtDeleteObject.setLong( 1, db_id );
1273        count = stmtDeleteObject.executeUpdate();
1274      } else {
1275        stmtDelObject.setString( 1, table );
1276        stmtDelObject.setLong( 2, db_id );
1277        count = stmtDelObject.executeUpdate();
1278      }
1279      if ( count > 0 ) {
1280        Logger.logDebug("SQLDB: deleted from " + table + ": " + count + " records" );
1281      }
1282    }
1283  
1284  }
1285
1286
1287  /**
1288  Not implemented
1289  */
1290  public void commit() {
1291  }
1292
1293
1294  /**
1295  Close connection to the database
1296  */
129