change sql LIMIT usage from LIMIT #,# to LIMIT # OFFSET #, this is makes us postgresq...
[mir.git] / source / mir / storage / Database.java
1 /*\r
2  * Copyright (C) 2001, 2002  The Mir-coders group\r
3  *\r
4  * This file is part of Mir.\r
5  *\r
6  * Mir is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Mir is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with Mir; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  *\r
20  * In addition, as a special exception, The Mir-coders gives permission to link\r
21  * the code of this program with the com.oreilly.servlet library, any library\r
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced\r
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of\r
24  * the above that use the same license as the above), and distribute linked\r
25  * combinations including the two.  You must obey the GNU General Public\r
26  * License in all respects for all of the code used other than the above\r
27  * mentioned libraries.  If you modify this file, you may extend this exception\r
28  * to your version of the file, but you are not obligated to do so.  If you do\r
29  * not wish to do so, delete this exception statement from your version.\r
30  */\r
31 \r
32 package mir.storage;\r
33 \r
34 import  java.sql.*;\r
35 import  java.lang.*;\r
36 import  java.io.*;\r
37 import  java.util.*;\r
38 import  java.text.SimpleDateFormat;\r
39 import  java.text.ParseException;\r
40 import  freemarker.template.*;\r
41 import  com.codestudio.sql.*;\r
42 import  com.codestudio.util.*;\r
43 \r
44 import  mir.storage.StorageObject;\r
45 import  mir.storage.store.*;\r
46 import  mir.entity.*;\r
47 import  mir.misc.*;\r
48 import  mir.util.*;\r
49 \r
50 \r
51 /**\r
52  * Diese Klasse implementiert die Zugriffsschicht auf die Datenbank.\r
53  * Alle Projektspezifischen Datenbankklassen erben von dieser Klasse.\r
54  * In den Unterklassen wird im Minimalfall nur die Tabelle angegeben.\r
55  * Im Konfigurationsfile findet sich eine Verweis auf den verwendeten\r
56  * Treiber, Host, User und Passwort, ueber den der Zugriff auf die\r
57  * Datenbank erfolgt.\r
58  *\r
59  * @version $Id: Database.java,v 1.30 2002/12/28 03:21:38 mh Exp $\r
60  * @author rk\r
61  *\r
62  */\r
63 public class Database implements StorageObject {\r
64 \r
65   protected String                    theTable;\r
66   protected String                    theCoreTable=null;\r
67   protected String                    thePKeyName="id";\r
68   protected int                       thePKeyType, thePKeyIndex;\r
69   protected boolean                   evaluatedMetaData=false;\r
70   protected ArrayList                 metadataFields,metadataLabels,\r
71   metadataNotNullFields;\r
72   protected int[]                     metadataTypes;\r
73   protected Class                     theEntityClass;\r
74   protected StorageObject             myselfDatabase;\r
75   protected SimpleList                popupCache=null;\r
76   protected boolean                   hasPopupCache = false;\r
77   protected SimpleHash                hashCache=null;\r
78   protected boolean                   hasTimestamp=true;\r
79   private String                      database_driver, database_url;\r
80   private int                         defaultLimit;\r
81   protected DatabaseAdaptor           theAdaptor;\r
82   protected Logfile                   theLog;\r
83   private static Class                GENERIC_ENTITY_CLASS=null,\r
84   STORABLE_OBJECT_ENTITY_CLASS=null;\r
85   private static SimpleHash           POPUP_EMTYLINE=new SimpleHash();\r
86   protected static final ObjectStore  o_store=ObjectStore.getInstance();\r
87   private SimpleDateFormat _dateFormatterOut =\r
88       new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
89   private SimpleDateFormat _dateFormatterIn =\r
90       new SimpleDateFormat("yyyy-MM-dd HH:mm");\r
91   private Calendar _cal = new GregorianCalendar();\r
92 \r
93   private static final int _millisPerHour = 60 * 60 * 1000;\r
94   private static final int _millisPerMinute = 60 * 1000;\r
95 \r
96   static {\r
97     // always same object saves a little space\r
98     POPUP_EMTYLINE.put("key", ""); POPUP_EMTYLINE.put("value", "--");\r
99     try {\r
100       GENERIC_ENTITY_CLASS = Class.forName("mir.entity.StorableObjectEntity");\r
101       STORABLE_OBJECT_ENTITY_CLASS = Class.forName("mir.entity.StorableObjectEntity");\r
102     }\r
103     catch (Exception e) {\r
104       System.err.println("FATAL: Database.java could not initialize" + e.getMessage());\r
105     }\r
106   }\r
107 \r
108 \r
109   /**\r
110    * Kontruktor bekommt den Filenamen des Konfigurationsfiles übergeben.\r
111    * Aus diesem file werden <code>Database.Logfile</code>,\r
112    * <code>Database.Username</code>,<code>Database.Password</code>,\r
113    * <code>Database.Host</code> und <code>Database.Adaptor</code>\r
114    * ausgelesen und ein Broker für die Verbindugen zur Datenbank\r
115    * erzeugt.\r
116    *\r
117    * @param   String confFilename Dateiname der Konfigurationsdatei\r
118    */\r
119   public Database() throws StorageObjectException {\r
120     theLog = Logfile.getInstance(MirConfig.getProp("Home")+\r
121                                  MirConfig.getProp("Database.Logfile"));\r
122     String theAdaptorName=MirConfig.getProp("Database.Adaptor");\r
123     defaultLimit = Integer.parseInt(MirConfig.getProp("Database.Limit"));\r
124     try {\r
125       theEntityClass = GENERIC_ENTITY_CLASS;\r
126       theAdaptor = (DatabaseAdaptor)Class.forName(theAdaptorName).newInstance();\r
127     } catch (Exception e){\r
128       theLog.printError("Error in Database() constructor with "+\r
129                         theAdaptorName + " -- " +e.getMessage());\r
130       throw new StorageObjectException("Error in Database() constructor with "\r
131                                        +e.getMessage());\r
132     }\r
133   }\r
134 \r
135   /**\r
136    * Liefert die Entity-Klasse zurück, in der eine Datenbankzeile gewrappt\r
137    * wird. Wird die Entity-Klasse durch die erbende Klasse nicht überschrieben,\r
138    * wird eine mir.entity.GenericEntity erzeugt.\r
139    *\r
140    * @return Class-Objekt der Entity\r
141    */\r
142   public java.lang.Class getEntityClass () {\r
143     return  theEntityClass;\r
144   }\r
145 \r
146   /**\r
147    * Liefert die Standardbeschränkung von select-Statements zurück, also\r
148    * wieviel Datensätze per Default selektiert werden.\r
149    *\r
150    * @return Standard-Anzahl der Datensätze\r
151    */\r
152   public int getLimit () {\r
153     return  defaultLimit;\r
154   }\r
155 \r
156   /**\r
157    * Liefert den Namen des Primary-Keys zurück. Wird die Variable nicht von\r
158    * der erbenden Klasse überschrieben, so ist der Wert <code>PKEY</code>\r
159    * @return Name des Primary-Keys\r
160    */\r
161   public String getIdName () {\r
162     return  thePKeyName;\r
163   }\r
164 \r
165   /**\r
166    * Liefert den Namen der Tabelle, auf das sich das Datenbankobjekt bezieht.\r
167    *\r
168    * @return Name der Tabelle\r
169    */\r
170   public String getTableName () {\r
171     return  theTable;\r
172   }\r
173 \r
174       /*\r
175   *   Dient dazu vererbte Tabellen bei objectrelationalen DBMS\r
176   *   zu speichern, wenn die id einer Tabelle in der parenttabelle verwaltet\r
177   *   wird.\r
178   *   @return liefert theCoreTabel als String zurueck, wenn gesetzt, sonst\r
179   *    the Table\r
180        */\r
181 \r
182   public String getCoreTable(){\r
183     if (theCoreTable!=null) return theCoreTable;\r
184     else return theTable;\r
185   }\r
186 \r
187   /**\r
188    * Liefert Feldtypen der Felder der Tabelle zurueck (s.a. java.sql.Types)\r
189    * @return int-Array mit den Typen der Felder\r
190    * @exception StorageObjectException\r
191    */\r
192   public int[] getTypes () throws StorageObjectException {\r
193     if (metadataTypes == null)\r
194       get_meta_data();\r
195     return  metadataTypes;\r
196   }\r
197 \r
198   /**\r
199    * Liefert eine Liste der Labels der Tabellenfelder\r
200    * @return ArrayListe mit Labeln\r
201    * @exception StorageObjectException\r
202    */\r
203   public ArrayList getLabels () throws StorageObjectException {\r
204     if (metadataLabels == null)\r
205       get_meta_data();\r
206     return  metadataLabels;\r
207   }\r
208 \r
209   /**\r
210    * Liefert eine Liste der Felder der Tabelle\r
211    * @return ArrayList mit Feldern\r
212    * @exception StorageObjectException\r
213    */\r
214   public ArrayList getFields () throws StorageObjectException {\r
215     if (metadataFields == null)\r
216       get_meta_data();\r
217     return  metadataFields;\r
218   }\r
219 \r
220 \r
221       /*\r
222   *   Gets value out of ResultSet according to type and converts to String\r
223   *   @param inValue  Wert aus ResultSet.\r
224   *   @param aType  Datenbanktyp.\r
225   *   @return liefert den Wert als String zurueck. Wenn keine Umwandlung moeglich\r
226   *           dann /unsupported value/\r
227        */\r
228   private String getValueAsString (ResultSet rs, int valueIndex, int aType) throws StorageObjectException {\r
229     String outValue = null;\r
230     if (rs != null) {\r
231       try {\r
232         switch (aType) {\r
233           case java.sql.Types.BIT:\r
234             outValue = (rs.getBoolean(valueIndex) == true) ? "1" : "0";\r
235             break;\r
236           case java.sql.Types.INTEGER:case java.sql.Types.SMALLINT:case java.sql.Types.TINYINT:case java.sql.Types.BIGINT:\r
237             int out = rs.getInt(valueIndex);\r
238             if (!rs.wasNull())\r
239               outValue = new Integer(out).toString();\r
240             break;\r
241           case java.sql.Types.NUMERIC:\r
242             /** @todo Numeric can be float or double depending upon\r
243              *  metadata.getScale() / especially with oracle */\r
244             long outl = rs.getLong(valueIndex);\r
245             if (!rs.wasNull())\r
246               outValue = new Long(outl).toString();\r
247             break;\r
248           case java.sql.Types.REAL:\r
249             float tempf = rs.getFloat(valueIndex);\r
250             if (!rs.wasNull()) {\r
251               tempf *= 10;\r
252               tempf += 0.5;\r
253               int tempf_int = (int)tempf;\r
254               tempf = (float)tempf_int;\r
255               tempf /= 10;\r
256               outValue = "" + tempf;\r
257               outValue = outValue.replace('.', ',');\r
258             }\r
259             break;\r
260           case java.sql.Types.DOUBLE:\r
261             double tempd = rs.getDouble(valueIndex);\r
262             if (!rs.wasNull()) {\r
263               tempd *= 10;\r
264               tempd += 0.5;\r
265               int tempd_int = (int)tempd;\r
266               tempd = (double)tempd_int;\r
267               tempd /= 10;\r
268               outValue = "" + tempd;\r
269               outValue = outValue.replace('.', ',');\r
270             }\r
271             break;\r
272           case java.sql.Types.CHAR:case java.sql.Types.VARCHAR:case java.sql.Types.LONGVARCHAR:\r
273             outValue = rs.getString(valueIndex);\r
274             break;\r
275           case java.sql.Types.LONGVARBINARY:\r
276             outValue = rs.getString(valueIndex);\r
277             break;\r
278           case java.sql.Types.TIMESTAMP:\r
279             // it's important to use Timestamp here as getting it\r
280             // as a string is undefined and is only there for debugging\r
281             // according to the API. we can make it a string through formatting.\r
282             // -mh\r
283             Timestamp timestamp = (rs.getTimestamp(valueIndex));\r
284             if(!rs.wasNull()) {\r
285               java.util.Date date = new java.util.Date(timestamp.getTime());\r
286               outValue = _dateFormatterOut.format(date);\r
287               _cal.setTime(date);\r
288               int offset = _cal.get(Calendar.ZONE_OFFSET)+\r
289                            _cal.get(Calendar.DST_OFFSET);\r
290               String tzOffset = StringUtil.zeroPaddingNumber(\r
291                   offset/_millisPerHour,2,2);\r
292               outValue = outValue+"+"+tzOffset;\r
293             }\r
294             break;\r
295           default:\r
296             outValue = "<unsupported value>";\r
297           theLog.printWarning("Unsupported Datatype: at " + valueIndex +\r
298                               " (" + aType + ")");\r
299         }\r
300       } catch (SQLException e) {\r
301         throw  new StorageObjectException("Could not get Value out of Resultset -- "\r
302             + e.getMessage());\r
303       }\r
304     }\r
305     return  outValue;\r
306   }\r
307 \r
308       /*\r
309   *   select-Operator um einen Datensatz zu bekommen.\r
310   *   @param id Primaerschluessel des Datensatzes.\r
311   *   @return liefert EntityObject des gefundenen Datensatzes oder null.\r
312        */\r
313   public Entity selectById(String id)   throws StorageObjectException\r
314   {\r
315     if (id==null||id.equals(""))\r
316       throw new StorageObjectException("id war null");\r
317 \r
318     // ask object store for object\r
319     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {\r
320       String uniqueId = id;\r
321       if ( theEntityClass.equals(StorableObjectEntity.class) )\r
322         uniqueId+="@"+theTable;\r
323       StoreIdentifier search_sid = new StoreIdentifier(theEntityClass, uniqueId);\r
324       theLog.printDebugInfo("CACHE: (dbg) looking for sid " + search_sid.toString());\r
325       Entity hit = (Entity)o_store.use(search_sid);\r
326       if ( hit!=null ) return hit;\r
327     }\r
328 \r
329     Statement stmt=null;Connection con=getPooledCon();\r
330     Entity returnEntity=null;\r
331     try {\r
332       ResultSet rs;\r
333       /** @todo better prepared statement */\r
334       String selectSql = "select * from " + theTable + " where " + thePKeyName + "=" + id;\r
335       stmt = con.createStatement();\r
336       rs = executeSql(stmt, selectSql);\r
337       if (rs != null) {\r
338         if (evaluatedMetaData==false) evalMetaData(rs.getMetaData());\r
339         if (rs.next())\r
340           returnEntity = makeEntityFromResultSet(rs);\r
341         else theLog.printDebugInfo("Keine daten fuer id: " + id + "in Tabelle" + theTable);\r
342         rs.close();\r
343       }\r
344       else {\r
345         theLog.printDebugInfo("No Data for Id " + id + " in Table " + theTable);\r
346       }\r
347     }\r
348     catch (SQLException sqe){\r
349       throwSQLException(sqe,"selectById"); return null;\r
350     }\r
351     catch (NumberFormatException e) {\r
352       theLog.printError("ID ist keine Zahl: " + id);\r
353     }\r
354     finally { freeConnection(con,stmt); }\r
355 \r
356     /** @todo OS: Entity should be saved in ostore */\r
357     return returnEntity;\r
358   }\r
359 \r
360 \r
361   /**\r
362    *   select-Operator um Datensaetze zu bekommen, die key = value erfuellen.\r
363    *   @param key  Datenbankfeld der Bedingung.\r
364    *   @param value  Wert die der key anehmen muss.\r
365    *   @return EntityList mit den gematchten Entities\r
366    */\r
367   public EntityList selectByFieldValue(String aField, String aValue)\r
368       throws StorageObjectException\r
369   {\r
370     return selectByFieldValue(aField, aValue, 0);\r
371   }\r
372 \r
373   /**\r
374    *   select-Operator um Datensaetze zu bekommen, die key = value erfuellen.\r
375    *   @param key  Datenbankfeld der Bedingung.\r
376    *   @param value  Wert die der key anehmen muss.\r
377    *   @param offset  Gibt an ab welchem Datensatz angezeigt werden soll.\r
378    *   @return EntityList mit den gematchten Entities\r
379    */\r
380   public EntityList selectByFieldValue(String aField, String aValue, int offset)\r
381       throws StorageObjectException\r
382   {\r
383     return selectByWhereClause(aField + "=" + aValue, offset);\r
384   }\r
385 \r
386 \r
387   /**\r
388    * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.\r
389    * Also offset wird der erste Datensatz genommen.\r
390    *\r
391    * @param wc where-Clause\r
392    * @return EntityList mit den gematchten Entities\r
393    * @exception StorageObjectException\r
394    */\r
395   public EntityList selectByWhereClause(String where)\r
396       throws StorageObjectException\r
397   {\r
398     return selectByWhereClause(where, 0);\r
399   }\r
400 \r
401 \r
402   /**\r
403    * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.\r
404    * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.\r
405    *\r
406    * @param wc where-Clause\r
407    * @param offset ab welchem Datensatz.\r
408    * @return EntityList mit den gematchten Entities\r
409    * @exception StorageObjectException\r
410    */\r
411   public EntityList selectByWhereClause(String whereClause, int offset)\r
412       throws StorageObjectException\r
413   {\r
414     return selectByWhereClause(whereClause, null, offset);\r
415   }\r
416 \r
417 \r
418   /**\r
419    * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.\r
420    * Also offset wird der erste Datensatz genommen.\r
421    * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.\r
422    *\r
423    * @param wc where-Clause\r
424    * @param ob orderBy-Clause\r
425    * @return EntityList mit den gematchten Entities\r
426    * @exception StorageObjectException\r
427    */\r
428 \r
429   public EntityList selectByWhereClause(String where, String order)\r
430       throws StorageObjectException {\r
431     return selectByWhereClause(where, order, 0);\r
432   }\r
433 \r
434 \r
435   /**\r
436    * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.\r
437    * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.\r
438    *\r
439    * @param wc where-Clause\r
440    * @param ob orderBy-Clause\r
441    * @param offset ab welchem Datensatz\r
442    * @return EntityList mit den gematchten Entities\r
443    * @exception StorageObjectException\r
444    */\r
445 \r
446   public EntityList selectByWhereClause(String whereClause, String orderBy, int offset)\r
447       throws StorageObjectException {\r
448     return selectByWhereClause(whereClause, orderBy, offset, defaultLimit);\r
449   }\r
450 \r
451 \r
452   /**\r
453    * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.\r
454    * @param wc where-Clause\r
455    * @param ob orderBy-Clause\r
456    * @param offset ab welchem Datensatz\r
457    * @param limit wieviele Datensätze\r
458    * @return EntityList mit den gematchten Entities\r
459    * @exception StorageObjectException\r
460    */\r
461 \r
462   public EntityList selectByWhereClause(String wc, String ob, int offset,\r
463                                         int limit) throws\r
464       StorageObjectException {\r
465 \r
466     // check o_store for entitylist\r
467     if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
468       StoreIdentifier search_sid =\r
469           new StoreIdentifier(theEntityClass,\r
470                               StoreContainerType.STOC_TYPE_ENTITYLIST,\r
471                               StoreUtil.getEntityListUniqueIdentifierFor(\r
472           theTable, wc, ob, offset, limit));\r
473       EntityList hit = (EntityList) o_store.use(search_sid);\r
474       if (hit != null) {\r
475         theLog.printDebugInfo("CACHE (hit): " + search_sid.toString());\r
476         return hit;\r
477       }\r
478     }\r
479 \r
480     // local\r
481     EntityList theReturnList = null;\r
482     Connection con = null;\r
483     Statement stmt = null;\r
484     ResultSet rs;\r
485     int offsetCount = 0, count = 0;\r
486 \r
487     // build sql-statement\r
488 \r
489     /** @todo count sql string should only be assembled if we really count\r
490      *  see below at the end of method //rk */\r
491 \r
492     if (wc != null && wc.length() == 0) {\r
493       wc = null;\r
494     }\r
495     StringBuffer countSql = new StringBuffer("select count(*) from ").append(\r
496         theTable);\r
497     StringBuffer selectSql = new StringBuffer("select * from ").append(theTable);\r
498     if (wc != null) {\r
499       selectSql.append(" where ").append(wc);\r
500       countSql.append(" where ").append(wc);\r
501     }\r
502     if (ob != null && ! (ob.length() == 0)) {\r
503       selectSql.append(" order by ").append(ob);\r
504     }\r
505     if (theAdaptor.hasLimit()) {\r
506       if (limit > -1 && offset > -1) {\r
507         selectSql.append(" LIMIT ").append(limit).append(" OFFSET ").append(offset);\r
508       }\r
509     }\r
510 \r
511     // execute sql\r
512     try {\r
513       con = getPooledCon();\r
514       stmt = con.createStatement();\r
515 \r
516       // selecting...\r
517       rs = executeSql(stmt, selectSql.toString());\r
518       if (rs != null) {\r
519         if (!evaluatedMetaData)\r
520           evalMetaData(rs.getMetaData());\r
521 \r
522         theReturnList = new EntityList();\r
523         Entity theResultEntity;\r
524         while (rs.next()) {\r
525           theResultEntity = makeEntityFromResultSet(rs);\r
526           theReturnList.add(theResultEntity);\r
527           offsetCount++;\r
528         }\r
529         rs.close();\r
530       }\r
531 \r
532       // making entitylist infos\r
533       if (! (theAdaptor.hasLimit()))\r
534         count = offsetCount;\r
535 \r
536       if (theReturnList != null) {\r
537         // now we decide if we have to know an overall count...\r
538         count = offsetCount;\r
539         if (limit > -1 && offset > -1) {\r
540           if (offsetCount == limit) {\r
541             /** @todo counting should be deffered to entitylist\r
542              *  getSize() should be used */\r
543             rs = executeSql(stmt, countSql.toString());\r
544             if (rs != null) {\r
545               if (rs.next())\r
546                 count = rs.getInt(1);\r
547               rs.close();\r
548             }\r
549             else\r
550               theLog.printError("Could not count: " + countSql);\r
551           }\r
552         }\r
553         theReturnList.setCount(count);\r
554         theReturnList.setOffset(offset);\r
555         theReturnList.setWhere(wc);\r
556         theReturnList.setOrder(ob);\r
557         theReturnList.setStorage(this);\r
558         theReturnList.setLimit(limit);\r
559         if (offset >= limit)\r
560           theReturnList.setPrevBatch(offset - limit);\r
561         if (offset + offsetCount < count)\r
562           theReturnList.setNextBatch(offset + limit);\r
563         if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
564           StoreIdentifier sid = theReturnList.getStoreIdentifier();\r
565           theLog.printDebugInfo("CACHE (add): " + sid.toString());\r
566           o_store.add(sid);\r
567         }\r
568       }\r
569     }\r
570     catch (SQLException sqe) {\r
571       throwSQLException(sqe, "selectByWhereClause");\r
572     }\r
573     finally {\r
574       try {\r
575         if (con != null)\r
576           freeConnection(con, stmt);\r
577       }\r
578       catch (Throwable t) {\r
579       }\r
580 \r
581     }\r
582 \r
583     return theReturnList;\r
584   }\r
585 \r
586 \r
587   /**\r
588    *  Bastelt aus einer Zeile der Datenbank ein EntityObjekt.\r
589    *\r
590    *  @param rs Das ResultSetObjekt.\r
591    *  @return Entity Die Entity.\r
592    */\r
593   private Entity makeEntityFromResultSet (ResultSet rs)\r
594       throws StorageObjectException\r
595   {\r
596     /** @todo OS: get Pkey from ResultSet and consult ObjectStore */\r
597     HashMap theResultHash = new HashMap();\r
598     String theResult = null;\r
599     int theType;\r
600     Entity returnEntity = null;\r
601     try {\r
602       int size = metadataFields.size();\r
603       for (int i = 0; i < size; i++) {\r
604         // alle durchlaufen bis nix mehr da\r
605 \r
606         theType = metadataTypes[i];\r
607         if (theType == java.sql.Types.LONGVARBINARY) {\r
608           InputStreamReader is = (InputStreamReader)rs.getCharacterStream(i + 1);\r
609           if (is != null) {\r
610             char[] data = new char[32768];\r
611             StringBuffer theResultString = new StringBuffer();\r
612             int len;\r
613             while ((len = is.read(data)) > 0) {\r
614               theResultString.append(data, 0, len);\r
615             }\r
616             is.close();\r
617             theResult = theResultString.toString();\r
618           }\r
619           else {\r
620             theResult = null;\r
621           }\r
622         }\r
623         else {\r
624           theResult = getValueAsString(rs, (i + 1), theType);\r
625         }\r
626         if (theResult != null) {\r
627           theResultHash.put(metadataFields.get(i), theResult);\r
628         }\r
629       }\r
630       if (theEntityClass != null) {\r
631         returnEntity = (Entity)theEntityClass.newInstance();\r
632         returnEntity.setValues(theResultHash);\r
633         returnEntity.setStorage(myselfDatabase);\r
634         if ( returnEntity instanceof StorableObject ) {\r
635           theLog.printDebugInfo("CACHE: ( in) " + returnEntity.getId() + " :"+theTable);\r
636           o_store.add(((StorableObject)returnEntity).getStoreIdentifier());\r
637         }\r
638       } else {\r
639         throwStorageObjectException("Internal Error: theEntityClass not set!");\r
640       }\r
641     }\r
642     catch (IllegalAccessException e) {\r
643       throwStorageObjectException("No access! -- " + e.getMessage());\r
644     }\r
645     catch (IOException e) {\r
646       throwStorageObjectException("IOException! -- " + e.getMessage());\r
647     }\r
648     catch (InstantiationException e) {\r
649       throwStorageObjectException("No Instatiation! -- " + e.getMessage());\r
650     }\r
651     catch (SQLException sqe) {\r
652       throwSQLException(sqe, "makeEntityFromResultSet");\r
653       return  null;\r
654     }\r
655     return  returnEntity;\r
656   }\r
657 \r
658   /**\r
659    * insert-Operator: fügt eine Entity in die Tabelle ein. Eine Spalte WEBDB_CREATE\r
660    * wird automatisch mit dem aktuellen Datum gefuellt.\r
661    *\r
662    * @param theEntity\r
663    * @return der Wert des Primary-keys der eingefügten Entity\r
664    */\r
665   public String insert (Entity theEntity) throws StorageObjectException {\r
666     //cache\r
667     invalidatePopupCache();\r
668 \r
669     // invalidating all EntityLists corresponding with theEntityClass\r
670     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {\r
671       StoreContainerType stoc_type =\r
672           StoreContainerType.valueOf( theEntityClass,\r
673           StoreContainerType.STOC_TYPE_ENTITYLIST);\r
674       o_store.invalidate(stoc_type);\r
675     }\r
676 \r
677     String returnId = null;\r
678     Connection con = null; PreparedStatement pstmt = null;\r
679 \r
680     try {\r
681       ArrayList streamedInput = theEntity.streamedInput();\r
682       StringBuffer f = new StringBuffer();\r
683       StringBuffer v = new StringBuffer();\r
684       String aField, aValue;\r
685       boolean firstField = true;\r
686       // make sql-string\r
687       for (int i = 0; i < getFields().size(); i++) {\r
688         aField = (String)getFields().get(i);\r
689         if (!aField.equals(thePKeyName)) {\r
690           aValue = null;\r
691           // sonderfaelle\r
692           if (aField.equals("webdb_create") ||\r
693               aField.equals("webdb_lastchange")) {\r
694             aValue = "NOW()";\r
695           }\r
696           else {\r
697             if (streamedInput != null && streamedInput.contains(aField)) {\r
698               aValue = "?";\r
699             }\r
700             else {\r
701               if (theEntity.hasValueForField(aField)) {\r
702                 aValue = "'" + JDBCStringRoutines.escapeStringLiteral((String)theEntity.getValue(aField)) + "'";\r
703               }\r
704             }\r
705           }\r
706           // wenn Wert gegeben, dann einbauen\r
707           if (aValue != null) {\r
708             if (firstField == false) {\r
709               f.append(",");\r
710               v.append(",");\r
711             }\r
712             else {\r
713               firstField = false;\r
714             }\r
715             f.append(aField);\r
716             v.append(aValue);\r
717           }\r
718         }\r
719       }         // end for\r
720       // insert into db\r
721       StringBuffer sqlBuf = new StringBuffer("insert into ").append(theTable).append("(").append(f).append(") values (").append(v).append(")");\r
722       String sql = sqlBuf.toString();\r
723       //theLog.printInfo("INSERT: " + sql);\r
724       con = getPooledCon();\r
725       con.setAutoCommit(false);\r
726       pstmt = con.prepareStatement(sql);\r
727       if (streamedInput != null) {\r
728         for (int i = 0; i < streamedInput.size(); i++) {\r
729           String inputString = (String)theEntity.getValue((String)streamedInput.get(i));\r
730           pstmt.setBytes(i + 1, inputString.getBytes());\r
731         }\r
732       }\r
733       int ret = pstmt.executeUpdate();\r
734       if(ret == 0){\r
735         //insert failed\r
736         return null;\r
737       }\r
738       pstmt = con.prepareStatement(theAdaptor.getLastInsertSQL((Database)myselfDatabase));\r
739       ResultSet rs = pstmt.executeQuery();\r
740       rs.next();\r
741       returnId = rs.getString(1);\r
742       theEntity.setId(returnId);\r
743     } catch (SQLException sqe) {\r
744       throwSQLException(sqe, "insert");\r
745     } finally {\r
746       try {\r
747         con.setAutoCommit(true);\r
748       } catch (Exception e) {\r
749         ;\r
750       }\r
751       freeConnection(con, pstmt);\r
752     }\r
753     /** @todo store entity in o_store */\r
754     return  returnId;\r
755   }\r
756 \r
757   /**\r
758    * update-Operator: aktualisiert eine Entity. Eine Spalte WEBDB_LASTCHANGE\r
759    * wird automatisch mit dem aktuellen Datum gefuellt.\r
760    *\r
761    * @param theEntity\r
762    */\r
763   public void update (Entity theEntity) throws StorageObjectException\r
764   {\r
765     Connection con = null; PreparedStatement pstmt = null;\r
766     /** @todo this is stupid: why do we prepare statement, when we\r
767      *  throw it away afterwards. should be regular statement\r
768      *  update/insert could better be one routine called save()\r
769      *  that chooses to either insert or update depending if we\r
770      *  have a primary key in the entity. i don't know if we\r
771      *  still need the streamed input fields. // rk  */\r
772 \r
773     /** @todo extension: check if Entity did change, otherwise we don't need\r
774      *  the roundtrip to the database */\r
775 \r
776     /** invalidating corresponding entitylists in o_store*/\r
777     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {\r
778       StoreContainerType stoc_type =\r
779           StoreContainerType.valueOf( theEntityClass,\r
780           StoreContainerType.STOC_TYPE_ENTITYLIST);\r
781       o_store.invalidate(stoc_type);\r
782     }\r
783 \r
784     ArrayList streamedInput = theEntity.streamedInput();\r
785     String id = theEntity.getId();\r
786     String aField;\r
787     StringBuffer fv = new StringBuffer();\r
788     boolean firstField = true;\r
789     //cache\r
790     invalidatePopupCache();\r
791     // build sql statement\r
792     for (int i = 0; i < getFields().size(); i++) {\r
793       aField = (String)metadataFields.get(i);\r
794       // only normal cases\r
795       if (!(aField.equals(thePKeyName) || aField.equals("webdb_create") ||\r
796             aField.equals("webdb_lastchange") || (streamedInput != null && streamedInput.contains(aField)))) {\r
797         if (theEntity.hasValueForField(aField)) {\r
798           if (firstField == false) {\r
799             fv.append(", ");\r
800           }\r
801           else {\r
802             firstField = false;\r
803           }\r
804           fv.append(aField).append("='").append(JDBCStringRoutines.escapeStringLiteral((String) theEntity.getValue(aField))).append("'");\r
805 \r
806 //              fv.append(aField).append("='").append(StringUtil.quote((String)theEntity.getValue(aField))).append("'");\r
807         }\r
808       }\r
809     }\r
810     StringBuffer sql = new StringBuffer("update ").append(theTable).append(" set ").append(fv);\r
811     // exceptions\r
812     if (metadataFields.contains("webdb_lastchange")) {\r
813       sql.append(",webdb_lastchange=NOW()");\r
814     }\r
815     // special case: the webdb_create requires the field in yyyy-mm-dd HH:mm\r
816     // format so anything extra will be ignored. -mh\r
817     if (metadataFields.contains("webdb_create") &&\r
818         theEntity.hasValueForField("webdb_create")) {\r
819       // minimum of 10 (yyyy-mm-dd)...\r
820       if (theEntity.getValue("webdb_create").length() >= 10) {\r
821         String dateString = theEntity.getValue("webdb_create");\r
822         // if only 10, then add 00:00 so it doesn't throw a ParseException\r
823         if (dateString.length() == 10)\r
824           dateString=dateString+" 00:00";\r
825 \r
826         // TimeStamp stuff\r
827         try {\r
828           java.util.Date d = _dateFormatterIn.parse(dateString);\r
829           Timestamp tStamp = new Timestamp(d.getTime());\r
830           sql.append(",webdb_create='"+tStamp.toString()+"'");\r
831         } catch (ParseException e) {\r
832           throw new StorageObjectException(e.getMessage());\r
833         }\r
834       }\r
835     }\r
836     if (streamedInput != null) {\r
837       for (int i = 0; i < streamedInput.size(); i++) {\r
838         sql.append(",").append(streamedInput.get(i)).append("=?");\r
839       }\r
840     }\r
841     sql.append(" where id=").append(id);\r
842     //theLog.printInfo("UPDATE: " + sql);\r
843     // execute sql\r
844     try {\r
845       con = getPooledCon();\r
846       con.setAutoCommit(false);\r
847       pstmt = con.prepareStatement(sql.toString());\r
848       if (streamedInput != null) {\r
849         for (int i = 0; i < streamedInput.size(); i++) {\r
850           String inputString = theEntity.getValue((String)streamedInput.get(i));\r
851           pstmt.setBytes(i + 1, inputString.getBytes());\r
852         }\r
853       }\r
854       pstmt.executeUpdate();\r
855     }\r
856     catch (SQLException sqe) {\r
857       throwSQLException(sqe, "update");\r
858     }\r
859     finally {\r
860       try {\r
861         con.setAutoCommit(true);\r
862       } catch (Exception e) {\r
863         ;\r
864       }\r
865       freeConnection(con, pstmt);\r
866     }\r
867   }\r
868 \r
869       /*\r
870   *   delete-Operator\r
871   *   @param id des zu loeschenden Datensatzes\r
872   *   @return boolean liefert true zurueck, wenn loeschen erfolgreich war.\r
873        */\r
874   public boolean delete (String id) throws StorageObjectException {\r
875 \r
876     invalidatePopupCache();\r
877     // ostore send notification\r
878     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {\r
879       String uniqueId = id;\r
880       if ( theEntityClass.equals(StorableObjectEntity.class) )\r
881         uniqueId+="@"+theTable;\r
882       theLog.printInfo("CACHE: (del) " + id);\r
883       StoreIdentifier search_sid =\r
884           new StoreIdentifier(theEntityClass, StoreContainerType.STOC_TYPE_ENTITY, uniqueId);\r
885       o_store.invalidate(search_sid);\r
886     }\r
887 \r
888     /** @todo could be prepared Statement */\r
889     Statement stmt = null; Connection con = null;\r
890     int res = 0;\r
891     String sql="delete from "+theTable+" where "+thePKeyName+"='"+id+"'";\r
892     //theLog.printInfo("DELETE " + sql);\r
893     try {\r
894       con = getPooledCon(); stmt = con.createStatement();\r
895       res = stmt.executeUpdate(sql);\r
896     }\r
897     catch (SQLException sqe) { throwSQLException(sqe, "delete"); }\r
898     finally { freeConnection(con, stmt); }\r
899 \r
900     return  (res > 0) ? true : false;\r
901   }\r
902 \r
903       /* noch nicht implementiert.\r
904   * @return immer false\r
905        */\r
906   public boolean delete (EntityList theEntityList) {\r
907     invalidatePopupCache();\r
908     return  false;\r
909   }\r
910 \r
911   /**\r
912    * Diese Methode sollte ueberschrieben werden, wenn fuer die abgeleitete Database-Klasse\r
913    * eine SimpleList mit Standard-Popupdaten erzeugt werden koennen soll.\r
914    * @return null\r
915    */\r
916   public SimpleList getPopupData () throws StorageObjectException {\r
917     return  null;\r
918   }\r
919 \r
920   /**\r
921    *  Holt Daten fuer Popups.\r
922    *  @param name  Name des Feldes.\r
923    *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.\r
924    *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.\r
925    */\r
926   public SimpleList getPopupData (String name, boolean hasNullValue)\r
927       throws StorageObjectException {\r
928     return  getPopupData(name, hasNullValue, null);\r
929   }\r
930 \r
931   /**\r
932    *  Holt Daten fuer Popups.\r
933    *  @param name  Name des Feldes.\r
934    *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.\r
935    *  @param where  Schraenkt die Selektion der Datensaetze ein.\r
936    *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.\r
937    */\r
938   public SimpleList getPopupData (String name, boolean hasNullValue, String where) throws StorageObjectException {\r
939     return  getPopupData(name, hasNullValue, where, null);\r
940   }\r
941 \r
942   /**\r
943    *  Holt Daten fuer Popups.\r
944    *  @param name  Name des Feldes.\r
945    *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.\r
946    *  @param where  Schraenkt die Selektion der Datensaetze ein.\r
947    *  @param order  Gibt ein Feld als Sortierkriterium an.\r
948    *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.\r
949    */\r
950   public SimpleList getPopupData (String name, boolean hasNullValue, String where, String order) throws StorageObjectException {\r
951     // caching\r
952     if (hasPopupCache && popupCache != null)\r
953       return  popupCache;\r
954     SimpleList simpleList = null;\r
955     Connection con = null;\r
956     Statement stmt = null;\r
957     // build sql\r
958     StringBuffer sql = new StringBuffer("select ").append(thePKeyName)\r
959                      .append(",").append(name).append(" from ")\r
960                      .append(theTable);\r
961     if (where != null && !(where.length() == 0))\r
962       sql.append(" where ").append(where);\r
963     sql.append(" order by ");\r
964     if (order != null && !(order.length() == 0))\r
965       sql.append(order);\r
966     else\r
967       sql.append(name);\r
968     // execute sql\r
969     try {\r
970       con = getPooledCon();\r
971     }\r
972     catch (Exception e) {\r
973       throw new StorageObjectException(e.getMessage());\r
974     }\r
975     try {\r
976       stmt = con.createStatement();\r
977       ResultSet rs = executeSql(stmt, sql.toString());\r
978 \r
979       if (rs != null) {\r
980         if (!evaluatedMetaData) get_meta_data();\r
981         simpleList = new SimpleList();\r
982         // if popup has null-selector\r
983         if (hasNullValue) simpleList.add(POPUP_EMTYLINE);\r
984 \r
985         SimpleHash popupDict;\r
986         while (rs.next()) {\r
987           popupDict = new SimpleHash();\r
988           popupDict.put("key", getValueAsString(rs, 1, thePKeyType));\r
989           popupDict.put("value", rs.getString(2));\r
990           simpleList.add(popupDict);\r
991         }\r
992         rs.close();\r
993       }\r
994     }\r
995     catch (Exception e) {\r
996       theLog.printError("getPopupData: "+e.getMessage());\r
997       throw new StorageObjectException(e.toString());\r
998     }\r
999     finally {\r
1000       freeConnection(con, stmt);\r
1001     }\r
1002 \r
1003     if (hasPopupCache) popupCache = simpleList;\r
1004     return  simpleList;\r
1005   }\r
1006 \r
1007   /**\r
1008    * Liefert alle Daten der Tabelle als SimpleHash zurueck. Dies wird verwandt,\r
1009    * wenn in den Templates ein Lookup-Table benoetigt wird. Sollte nur bei kleinen\r
1010    * Tabellen Verwendung finden.\r
1011    * @return SimpleHash mit den Tabellezeilen.\r
1012    */\r
1013   public SimpleHash getHashData () {\r
1014     /** @todo dangerous! this should have a flag to be enabled, otherwise\r
1015      *  very big Hashes could be returned */\r
1016     if (hashCache == null) {\r
1017       try {\r
1018         hashCache = HTMLTemplateProcessor.makeSimpleHash(selectByWhereClause("",\r
1019             -1));\r
1020       }\r
1021       catch (StorageObjectException e) {\r
1022         theLog.printDebugInfo(e.getMessage());\r
1023       }\r
1024     }\r
1025     return  hashCache;\r
1026   }\r
1027 \r
1028       /* invalidates the popupCache\r
1029        */\r
1030   protected void invalidatePopupCache () {\r
1031     /** @todo  invalidates toooo much */\r
1032     popupCache = null;\r
1033     hashCache = null;\r
1034   }\r
1035 \r
1036   /**\r
1037    * Diese Methode fuehrt den Sqlstring <i>sql</i> aus und timed im Logfile.\r
1038    * @param stmt Statemnt\r
1039    * @param sql Sql-String\r
1040    * @return ResultSet\r
1041    * @exception StorageObjectException\r
1042    */\r
1043   public ResultSet executeSql (Statement stmt, String sql)\r
1044       throws StorageObjectException, SQLException\r
1045   {\r
1046     long startTime = System.currentTimeMillis();\r
1047     ResultSet rs;\r
1048     try {\r
1049       rs = stmt.executeQuery(sql);\r
1050       //theLog.printInfo((System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
1051     }\r
1052     catch (SQLException e)\r
1053     {\r
1054       theLog.printDebugInfo("Failed: " + (System.currentTimeMillis() - startTime) + "ms. for: "+ sql);\r
1055       throw e;\r
1056     }\r
1057 \r
1058     return  rs;\r
1059   }\r
1060 \r
1061   /**\r
1062    * Fuehrt Statement stmt aus und liefert Resultset zurueck. Das SQL-Statment wird\r
1063    * getimed und geloggt.\r
1064    * @param stmt PreparedStatement mit der SQL-Anweisung\r
1065    * @return Liefert ResultSet des Statements zurueck.\r
1066    * @exception StorageObjectException, SQLException\r
1067    */\r
1068   public ResultSet executeSql (PreparedStatement stmt)\r
1069       throws StorageObjectException, SQLException {\r
1070 \r
1071     long startTime = (new java.util.Date()).getTime();\r
1072     ResultSet rs = stmt.executeQuery();\r
1073     theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms.");\r
1074     return  rs;\r
1075   }\r
1076 \r
1077   /**\r
1078    * returns the number of rows in the table\r
1079    */\r
1080   public int getSize(String where)\r
1081       throws SQLException,StorageObjectException\r
1082   {\r
1083     long  startTime = System.currentTimeMillis();\r
1084     String sql = "SELECT Count(*) FROM "+ theTable;\r
1085     if (where != null && !(where.length() == 0))\r
1086       sql = sql + " where " + where;\r
1087     Connection con = null;\r
1088     Statement stmt = null;\r
1089     int result = 0;\r
1090 \r
1091     try {\r
1092       con = getPooledCon();\r
1093       stmt = con.createStatement();\r
1094       ResultSet rs = executeSql(stmt,sql);\r
1095       while(rs.next()){\r
1096         result = rs.getInt(1);\r
1097       }\r
1098     }\r
1099     catch (SQLException e) {\r
1100       theLog.printError(e.getMessage());\r
1101     }\r
1102     finally {\r
1103       freeConnection(con,stmt);\r
1104     }\r
1105     //theLog.printInfo(theTable + " has "+ result +" rows where " + where);\r
1106     //theLog.printInfo((System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
1107     return result;\r
1108   }\r
1109 \r
1110   public int executeUpdate(Statement stmt, String sql)\r
1111       throws StorageObjectException, SQLException\r
1112   {\r
1113     int rs;\r
1114     long  startTime = (new java.util.Date()).getTime();\r
1115     try\r
1116     {\r
1117       rs = stmt.executeUpdate(sql);\r
1118       //theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms. for: " + sql);\r
1119     }\r
1120     catch (SQLException e)\r
1121     {\r
1122       theLog.printDebugInfo("Failed: " + (new java.util.Date().getTime()\r
1123           - startTime) + "ms. for: "+ sql);\r
1124       throw e;\r
1125     }\r
1126     return rs;\r
1127   }\r
1128 \r
1129   public int executeUpdate(String sql) throws StorageObjectException, SQLException\r
1130   {\r
1131     int result=-1;\r
1132     long  startTime = (new java.util.Date()).getTime();\r
1133     Connection con=null;\r
1134     PreparedStatement pstmt=null;\r
1135     try {\r
1136       con=getPooledCon();\r
1137       pstmt = con.prepareStatement(sql);\r
1138       result = pstmt.executeUpdate();\r
1139     }\r
1140     catch (Exception e) {\r
1141       theLog.printDebugInfo("executeUpdate failed: "+e.getMessage());\r
1142       throw new StorageObjectException("executeUpdate failed: "+e.getMessage());\r
1143     }\r
1144     finally {\r
1145       freeConnection(con,pstmt);\r
1146     }\r
1147     //theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms. for: " + sql);\r
1148     return result;\r
1149   }\r
1150 \r
1151   /**\r
1152    * Wertet ResultSetMetaData aus und setzt interne Daten entsprechend\r
1153    * @param md ResultSetMetaData\r
1154    * @exception StorageObjectException\r
1155    */\r
1156   private void evalMetaData (ResultSetMetaData md)\r
1157       throws StorageObjectException {\r
1158 \r
1159     this.evaluatedMetaData = true;\r
1160     this.metadataFields = new ArrayList();\r
1161     this.metadataLabels = new ArrayList();\r
1162     this.metadataNotNullFields = new ArrayList();\r
1163     try {\r
1164       int numFields = md.getColumnCount();\r
1165       this.metadataTypes = new int[numFields];\r
1166       String aField;\r
1167       int aType;\r
1168       for (int i = 1; i <= numFields; i++) {\r
1169         aField = md.getColumnName(i);\r
1170         metadataFields.add(aField);\r
1171         metadataLabels.add(md.getColumnLabel(i));\r
1172         aType = md.getColumnType(i);\r
1173         metadataTypes[i - 1] = aType;\r
1174         if (aField.equals(thePKeyName)) {\r
1175           thePKeyType = aType; thePKeyIndex = i;\r
1176         }\r
1177         if (md.isNullable(i) == md.columnNullable) {\r
1178           metadataNotNullFields.add(aField);\r
1179         }\r
1180       }\r
1181     } catch (SQLException e) {\r
1182       throwSQLException(e, "evalMetaData");\r
1183     }\r
1184   }\r
1185 \r
1186   /**\r
1187    *  Wertet die Metadaten eines Resultsets fuer eine Tabelle aus,\r
1188    *  um die alle Columns und Typen einer Tabelle zu ermitteln.\r
1189    */\r
1190   private void get_meta_data () throws StorageObjectException {\r
1191     Connection con = null;\r
1192     PreparedStatement pstmt = null;\r
1193     String sql = "select * from " + theTable + " where 0=1";\r
1194     try {\r
1195       con = getPooledCon();\r
1196       pstmt = con.prepareStatement(sql);\r
1197       //theLog.printInfo("METADATA: " + sql);\r
1198       ResultSet rs = pstmt.executeQuery();\r
1199       evalMetaData(rs.getMetaData());\r
1200       rs.close();\r
1201     } catch (SQLException e) {\r
1202       throwSQLException(e, "get_meta_data");\r
1203     } finally {\r
1204       freeConnection(con, pstmt);\r
1205     }\r
1206   }\r
1207 \r
1208 \r
1209   public Connection getPooledCon() throws StorageObjectException {\r
1210               /* @todo , doublecheck but I'm pretty sure that this is unnecessary. -mh\r
1211                       try{\r
1212                       Class.forName("com.codestudio.sql.PoolMan").newInstance();\r
1213               } catch (Exception e){\r
1214                       throw new StorageObjectException("Could not find the PoolMan Driver"\r
1215                           +e.toString());\r
1216               }*/\r
1217     Connection con = null;\r
1218 \r
1219     try{\r
1220       con = SQLManager.getInstance().requestConnection();\r
1221     }\r
1222     catch(SQLException e){\r
1223       theLog.printError("could not connect to the database "+e.getMessage());\r
1224       System.err.println("could not connect to the database "+e.getMessage());\r
1225       throw new StorageObjectException("Could not connect to the database"+ e.getMessage());\r
1226     }\r
1227 \r
1228     return con;\r
1229   }\r
1230 \r
1231   public void freeConnection (Connection con, Statement stmt) throws StorageObjectException {\r
1232     SQLManager.getInstance().closeStatement(stmt);\r
1233     SQLManager.getInstance().returnConnection(con);\r
1234   }\r
1235 \r
1236   /**\r
1237    * Wertet SQLException aus und wirft dannach eine StorageObjectException\r
1238    * @param sqe SQLException\r
1239    * @param wo Funktonsname, in der die SQLException geworfen wurde\r
1240    * @exception StorageObjectException\r
1241    */\r
1242   protected void throwSQLException (SQLException sqe, String wo) throws StorageObjectException {\r
1243     String state = "";\r
1244     String message = "";\r
1245     int vendor = 0;\r
1246     if (sqe != null) {\r
1247       state = sqe.getSQLState();\r
1248       message = sqe.getMessage();\r
1249       vendor = sqe.getErrorCode();\r
1250     }\r
1251     theLog.printError(state + ": " + vendor + " : " + message + " Funktion: "\r
1252                       + wo);\r
1253     throw new StorageObjectException((sqe == null) ? "undefined sql exception" :\r
1254                                       sqe.getMessage());\r
1255   }\r
1256 \r
1257   protected void _throwStorageObjectException (Exception e, String wo)\r
1258       throws StorageObjectException {\r
1259 \r
1260     if (e != null) {\r
1261       theLog.printError(e.getMessage()+ wo);\r
1262       throw  new StorageObjectException(wo + e.getMessage());\r
1263     }\r
1264     else {\r
1265       theLog.printError(wo);\r
1266       throw  new StorageObjectException(wo);\r
1267     }\r
1268 \r
1269   }\r
1270 \r
1271   /**\r
1272    * Loggt Fehlermeldung mit dem Parameter Message und wirft dannach\r
1273    * eine StorageObjectException\r
1274    * @param message Nachricht mit dem Fehler\r
1275    * @exception StorageObjectException\r
1276    */\r
1277   void throwStorageObjectException (String message)\r
1278       throws StorageObjectException {\r
1279     _throwStorageObjectException(null, message);\r
1280   }\r
1281 \r
1282 }\r
1283 \r
1284 \r
1285 \r