001    /***************************************************************************************************
002    *               MODULE DESCRIPTION
003    ****************************************************************************************************
004    *
005    *               NAME:           SimpleDb.java
006    *               LANGUAGE:       Java2
007    *               DATE:           2.12.2002
008    *               AUTHOR:         Miika Nurminen, Jyväskylän yliopisto
009    *
010    ****************************************************************************************************
011    *               COPYRIGHT (C) Kiuru-Group
012    *               Limited rights granted. Please refer to license
013    ****************************************************************************************************
014     
015    ****************************************************************************************************
016    *               UPDATES
017    ****************************************************************************************************
018    *
019    *   2.12.2002 - Initial version
020    *
021    ****************************************************************************************************/
022    package kiurubeans;
023    import java.util.*;
024    import java.beans.*;
025    import kotkabeans.*;
026    
027    /**
028     * Facilitates executing simple ad hoc queries using kotkabeans.DB.
029     * @author  Miika Nurminen
030     */
031    public class SimpleDb extends Object {
032      
033      /** Creates new SimpleDb */
034      public SimpleDb() {
035      }
036      
037      
038      /** Converts given column in RS2 to string array
039       * @return <CODE>String[]</CODE>-array containing all values from column
040       * <CODE>colname</CODE>.
041       * @param rs RS2 containing records
042       * @param colname Column name where we fetch values from
043       * @throws Exception Something went wrong when handling RS2
044       */
045      public static String[] RS2toArray(RS2 rs,String colname) throws java.lang.Exception {
046        if (rs==null) return null;
047        String[] s = new String[rs.count()];
048        rs.beforeFirst();
049        int i=0;
050        while (rs.next()) {
051          s[i]=rs.getString(colname);
052          i++;
053        }
054        return s;
055      }
056      
057      /** Executes simple database query.
058       * @param logstring Information for logging purposes.
059       * @param querystring Actual query.
060       * @throws Exception Database query couldn't made successfully.
061       * @return RS2 typed ResultSet containing results for the query.
062       */  
063      public static RS2 simpleQuery(String logstring,String querystring) throws Exception {
064        RS2 rs=null;
065        DB db=new DB(logstring);
066        db.connect();
067        try {
068          rs = new RS2(db.executeQuery(querystring));
069        }
070        finally {
071          db.disconnect();
072        }
073        return rs;
074      }
075      
076      /** Executes simple database update.
077       * @param logstring Information for logging purposes.
078       * @param updatestring Actual update sql clause.
079       * @throws Exception Database query couldn't made successfully.
080       * @return Returns amount of updated rows.
081       */  
082      public static int simpleUpdate(String logstring,String updatestring) throws Exception {
083        int updatedfields = 0;
084        DB db=new DB(logstring);
085        db.connect();
086        try {
087          updatedfields = db.executeUpdate(updatestring);
088        }
089        finally {
090          db.disconnect();
091        }
092        return updatedfields;
093      }
094      
095      /** Checks if record exists of the given table.
096       *
097       *  Returns true even if there are deleted records.
098       *  Assumes that db is valid and open! Caller is responsible for closing db!
099       * @param db Open database connection
100       * @param table Name of the table we are looking at.
101       * @param idname Column name of the primary key.
102       * @param idvalue Value of the primary key.
103       * @throws Exception Something illegal happened during database query.
104       * @return True if record with given id exists in given table.
105       */
106      public static boolean recordExists(DB db,String table,String idname,int idvalue) throws Exception {
107        RS2 rs = new RS2(db.executeQuery("select "+idname+" from "+table+" where "+idname+"="+Integer.toString(idvalue)));
108        return (rs.count()>0);
109      }
110      
111     
112      /** Checks if record exists of the given table. (like recordExists(db,table,idname,value, but multiple id/value pairs)
113       *
114       * Assumes that db is valid and open! Caller is responsible for closing db!
115       * @param db Open database connection
116       * @param table Name of the table we are looking at.
117       * @param values array of StringPair containing column names and values 
118       * @throws Exception Something illegal happened during database query.
119       * @return True if record with given id exists in given table.
120       */
121      public static boolean recordExists(DB db,String table, StringPair[] values) throws Exception {
122        StringBuffer s = new StringBuffer("select ");
123        for (int i=0; i<values.length; i++) {
124          if (i>0) s.append(",");
125          s.append(values[i].getKey());
126        }
127        s.append(" from "+table+" where ");
128        for (int i=0; i<values.length; i++) {
129          if (i>0) s.append(" and ");
130          s.append(values[i].getKey()+"="+values[i].getValue());
131        }
132        RS2 rs = new RS2(db.executeQuery(s.toString()));
133        return rs.next();
134      }
135    
136      /** Like ExecuteTransaction(Statementcontainer[],String), but takes list
137       * instead of array. Assumes arraylist contains only StatementContainers
138       * @param a Arraylist containing StatementContainers.
139       * @param dbLog Log string
140       * @return Returns true, if transaction was successful.
141       */
142      public static boolean executeTransaction(ArrayList a,String dbLog) {
143        if (a.size()==0) return false;
144        StatementContainer[] sc = new StatementContainer[a.size()];
145        for (int i=0; i<a.size(); i++) {
146          sc[i]=(StatementContainer)a.get(i);
147        }
148        return executeTransaction(sc,dbLog);
149      }
150      
151      /** Executes array of prepared statements in a transaction. Returns true on success
152       * @param sc StatementContainer containing database statements
153       * @param dbLog Log string
154       * @return Returns true, if transaction was successful.
155       */
156      public static boolean executeTransaction(StatementContainer[] sc,String dbLog) {
157        boolean result=false;
158        DB db = new DB(dbLog);
159        try {
160          db.connect();
161          result = executeTransaction(sc,dbLog,db);
162        }
163        catch (Exception e) {
164          Log.log("",e);
165        }
166        finally {
167          db.disconnect();
168        }
169        return result;
170      }
171      
172      /** Executes array of prepared statements in a transaction. Returns true on success
173       * @param sc StatementContainer containing database statements
174       * @param dbLog Log string
175       * @param db Open database connection
176       * @return Returns true, if transaction was successful.
177       */  
178      public static boolean executeTransaction(StatementContainer[] sc,String dbLog, DB db) {
179        boolean result=false;
180        try {
181          db.beginTransaction();
182          try {
183            for (int i=0; i<sc.length; i++) {
184              sc[i].prepare(db);
185              sc[i].getStatement().executeUpdate();
186            }
187            
188            db.endTransaction();
189            result=true;
190          }
191          catch (Exception e) {
192            db.abortTransaction();
193            Log.log("",e);
194          }
195          finally {
196            for (int i=0; i<sc.length; i++) 
197              if (sc[i].getStatement()!=null)
198               sc[i].getStatement().close();
199          }
200        }
201        catch (Exception DBe) {
202          Log.log("",DBe);
203        }
204        return result;
205      }
206      
207      /** Checks if user can edit current record & moves RS cursor to first record
208       *
209       * This should be called after every query before properties are assigned
210       * to bean.
211       * @return true if properties can be assigned, false is RS2 is empty of record is deleted
212       * @param rs RS2
213       * @throws Exception Something illegal happened during database operations.
214       */
215      public static boolean checkIfEditable(RS2 rs) throws java.lang.Exception {
216        return ((rs.next()) && (!rs.getBoolean("deleted")));
217      }
218      
219      /** Filters off 'null' result strings from RS2.getString
220       * @return Returns value of the <CODE>column</CODE> or '-' if it is null
221       * @param rs RS2 containing results
222       * @param column Which column we are interested in
223       * @throws Exception Something illegal happened during database operations
224       */
225      public static String getString(RS2 rs,String column) throws java.lang.Exception {
226        String result = rs.getString(column);
227        if (rs.wasNull()) return "-"; // wasnull must be called after getString
228        return result;
229      }
230      
231      /** Returns value of a timestamp field in compact notation.
232       * @param rs current resultset
233       * @param column column in resultset (should be of type timestamp)
234       * @throws Exception Something illegal happened during database operations.
235       * @return field value
236       */
237      public static String getDateTimeString(RS2 rs,String column) throws Exception {
238        String result = rs.getString(column);
239        if (rs.wasNull()) return "";
240        return time.timestampToOutFormat(result);
241      }
242      
243      /** Filters off 'null' result strings from RS2.getString and combines them with space as delimiter
244       * @param rs RS2 containing results
245       * @param column Column names of the columns we are interested in.
246       * @throws Exception Something illegal happened during database operations.
247       * @return Values of the columns separated with spaces. <CODE>Null</CODE>s are replaced
248       * with <CODE>'-'</CODE>s.
249       */
250      public static String getString(RS2 rs,String[] column) throws Exception {
251        StringBuffer result = new StringBuffer(column.length*2);
252        for (int i=0; i<column.length; i++) {
253          if (result.length()>0) result.append(" ");
254          String s = rs.getString(column[i]);
255          if (!rs.wasNull()) result.append(s);
256        }
257        if (result.length()==0) result.append("-");
258        return result.toString();
259      }
260      
261      /** Formats SQL search string from user's input. Assumes searchStr is not null.
262       * Result can be appended to SQL clause.
263       * @param fieldName Field name the user is searching.
264       * @param searchStr Search string
265       * @return Returns string that can be inserted in sql query clause.
266       */  
267      public static String formatSearchString(String fieldName,String searchStr) {
268        return formatSearchString(fieldName,searchStr,true);
269      }
270      
271      /** Formats SQL search string from user's input. Assumes searchStr is not null.
272       * Result can be appended to SQL clause.
273       * @param fieldName Field name the user is searching.
274       * @param searchStr Search string
275       * @param beginAnd Do we begin our search string with 'and'
276       * @return Returns string that can be inserted in sql query clause.
277       */
278      public static String formatSearchString(String fieldName,String searchStr,boolean beginAnd) {
279        String c=null;
280        if (searchStr.trim().equals("")) c="%"; else c=searchStr;
281    //    String s = Tools.parseSearch(c,fieldName);
282        String s = SqlSearchParser.search(c, fieldName); // new search logic! 16.4./mn
283        String t =" ("+s+") ";  
284        if (beginAnd==true) t=" and"+t;
285        return t;
286      }
287      
288      /** Formats SQL search string from array of id numbers. Result can be appended to SQL clause.
289       * @return " ( t1.field='2' or t1.field='7' or t1.field='10' ... ) "
290       * @param fieldname The name of the column we are searching
291       * @param ids ids of the records we are looking for.
292       */
293      public static String formatOrSet(String fieldname,String[] ids) {
294        if ((null==ids) || (0==ids.length))
295          return "";
296        StringBuffer sb = new StringBuffer(20);
297        sb.append(" ( ");
298        for (int i=0; i<ids.length; i++) {
299          if (i>0) sb.append(" or ");
300          sb.append(fieldname);
301          sb.append("=");
302          sb.append(KiuruString.sqlQuote(ids[i]));
303        }
304        sb.append(" ) ");
305        return sb.toString();
306      }
307      
308      /**
309       * returns "from" part of SQL
310       * @param tables table names (and aliases) in stringpair array. assumes key is alias, content tablename
311       * @return "from table1 as t1, table2 as t2 ..."
312       */
313      public static String addSqlFrom(StringPair[] tables) {
314        if ((tables==null) || (tables.length==0))
315          return "";
316        StringBuffer result = new StringBuffer(50);
317        result.append(" from ");
318        for (int i=0; i<tables.length; i++) {
319          if (i>0) result.append(", ");
320          result.append(tables[i].getValue());
321          result.append(" as ");
322          result.append(tables[i].getKey());
323        }
324        result.append(" ");
325        return result.toString();
326      }
327      
328      /**
329       * Returns "deleted" part in where clause. Assumes clause may start with and
330       * @param tables table names (and aliases) in stringpair array. key is used in clause
331       * @return "and t1.deleted=false and t2.deleted=false ..."
332       */
333      public static String addSqlDeleted(StringPair[] tables) {
334        if ((tables==null) || (tables.length==0))
335          return "";
336        StringBuffer result = new StringBuffer(50);
337        for (int i=0; i<tables.length; i++) {
338          result.append(" and ");
339          result.append(tables[i].getKey());
340          result.append(".deleted=false");
341        }
342        result.append(" ");
343        return result.toString();
344      }
345      
346      /** Tests if rs2 is NULL or empty.
347       * @return true if rs2 is NULL or empty. (eg. returns false if rs2 has content)
348       * @param rs RS2 we are testing
349       */
350      public static boolean isEmpty(RS2 rs) {
351        return ((rs==null) || (rs.count()==0));
352      }
353    }