1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 package stats; 28 29 import java.sql.Connection; 30 import java.sql.DriverManager; 31 import java.sql.ResultSet; 32 import java.sql.ResultSetMetaData; 33 import java.sql.Statement; 34 import java.util.Enumeration; 35 import java.util.Hashtable; 36 import java.util.StringTokenizer; 37 import java.util.Vector; 38 39 /** 40 * 41 */ 42 public class SQLExecution { 43 44 protected Connection mConnection = null; 45 protected Statement mStatement = null; 46 protected String mJdbcClass = null; 47 protected String mDbURL = null; 48 protected String mUser = null; 49 protected String mPassword = null; 50 protected boolean m_bConnectionOpen = false; 51 protected boolean m_bDebug = false; 52 53 54 /** Creates a new instance of SQLExecution 55 * @param jdbcClass The jdbc class for the connection. 56 * @param dbUrl The url of the database. 57 * @param user The user for connecting the database. 58 * @param password The password of throws user. 59 */ 60 public SQLExecution(String jdbcClass, String dbUrl, String user, String password) { 61 mJdbcClass = jdbcClass; 62 mUser = user; 63 mPassword = password; 64 mDbURL = dbUrl; 65 } 66 67 /** Creates a new instance of SQLExecution with additional debug output. 68 * @param jdbcClass The jdbc class for the connection. 69 * @param dbUrl The url of the database. 70 * @param user The user for connecting the database. 71 * @param password The password of throws user. 72 * @param debug Write debug information, if true. 73 */ 74 public SQLExecution(String jdbcClass, String dbUrl, String user, String password, boolean debug) { 75 mJdbcClass = jdbcClass; 76 mUser = user; 77 mPassword = password; 78 mDbURL = dbUrl; 79 m_bDebug = debug; 80 } 81 82 /** 83 * Open a connection to the DataBase 84 * @return True, if no error occured. 85 */ 86 public boolean openConnection() { 87 if(m_bConnectionOpen) return true; 88 try { 89 Class.forName(mJdbcClass); 90 } catch (ClassNotFoundException e) { 91 System.err.println("Couldn't find jdbc driver : " + e.getMessage()); 92 return false; 93 } 94 95 try { 96 // establish database connection 97 mConnection = DriverManager.getConnection( 98 mDbURL, mUser, mPassword); 99 mStatement = mConnection.createStatement(); 100 } 101 catch(java.sql.SQLException e) { 102 System.err.println("Couldn't establish a connection: " + e.getMessage()); 103 return false; 104 } 105 m_bConnectionOpen = true; 106 return true; 107 } 108 109 /** 110 * Close the connection to the DataBase 111 * @return True, if no error occured. 112 */ 113 public boolean closeConnection() { 114 if (!m_bConnectionOpen) return true; 115 try { 116 // close database connection 117 mStatement.close(); 118 mConnection.close(); 119 } 120 catch(java.sql.SQLException e) { 121 System.err.println("Couldn't close the connection: " + e.getMessage()); 122 return false; 123 } 124 m_bConnectionOpen = false; 125 return true; 126 } 127 128 /** 129 * Execute an sql command. 130 * @param command The command to execute. 131 * @param sqlInput Input values for the command. 132 * @param sqlOutput The results of the command are put in this Hashtable. 133 * @return True, if no error occured. 134 */ 135 public boolean executeSQLCommand(String command, Hashtable sqlInput, Hashtable sqlOutput) 136 throws IllegalArgumentException { 137 return executeSQLCommand(command, sqlInput, sqlOutput, false); 138 } 139 140 /** 141 * Execute an sql command. 142 * @param command The command to execute. 143 * @param sqlInput Input values for the command. 144 * @param sqlOutput The results of the command are put in this Hashtable. 145 * @param mergeOutputIntoInput The output of the result is put into the 146 * sqlInput Hashtable. 147 * @return True, if no error occured. 148 */ 149 public boolean executeSQLCommand(String command, Hashtable sqlInput, Hashtable sqlOutput, boolean mergeOutputIntoInput) 150 throws IllegalArgumentException { 151 if (sqlOutput == null) { 152 sqlOutput = new Hashtable(); 153 // this has to be true, so the user of this method gets a return 154 mergeOutputIntoInput = true; 155 if (sqlInput == null) { 156 System.out.println("sqlInput and sqlOutput are null: cannot return the results of the sql command."); 157 return false; 158 } 159 } 160 Vector sqlCommand = new Vector(); 161 sqlCommand.add(""); 162 boolean update = false; 163 // synchronize all "$varname" occurences in the command string with 164 // values from input 165 StringTokenizer token = new StringTokenizer(command, " "); 166 while (token.hasMoreTokens()) { 167 String originalKey = token.nextToken(); 168 // search for keys, beginning with "$" 169 int index = originalKey.indexOf('$'); 170 if (index != -1) { 171 // found key 172 String pre = ""; 173 pre = originalKey.substring(0,index); 174 // generate key: remove "$" 175 String key = originalKey.substring(index+1); 176 String post = ""; 177 // remove any endings the key might have 178 while (key.endsWith(",") || key.endsWith("\'") || 179 key.endsWith(";") || key.endsWith(")") || 180 key.endsWith("\"")) { 181 post = key.substring(key.length()-1) + post; 182 key = key.substring(0, key.length()-1); 183 } 184 // look for key in the Hashtable 185 if (sqlInput.containsKey(key)) { 186 // is there a value for the key? 187 Object in = sqlInput.get(key); 188 if (in instanceof String[]) { 189 // value is a String[] 190 String[]vals = (String[])in; 191 if (vals.length != sqlCommand.size() && sqlCommand.size() > 1) { 192 // size of this array and previous array(s) does not match 193 throw new IllegalArgumentException("The key '" + key + "' in command \n'" 194 + command + "'\n has not the same value count as the keys before."); 195 } 196 // build up the commands 197 boolean addNewVals = (sqlCommand.size() == 1); 198 for (int i=0; i<vals.length; i++) { 199 String value = checkForQuotationMarks(vals[i]); 200 // add the values 201 if (addNewVals && i!=0) { 202 // all values until now were of type String, not String[], so now new values have to be added. 203 sqlCommand.add(i, (String)sqlCommand.get(0) + " " + pre + value + post); 204 } 205 else { 206 // we already have vals.length commands (or are at the first command), so just add. 207 sqlCommand.set(i, (String)sqlCommand.get(i) + " " + pre + value + post); 208 } 209 } 210 } 211 else { 212 // value is a String: no other possibility 213 String value = checkForQuotationMarks((String)sqlInput.get(key)); 214 for (int i=0; i<sqlCommand.size(); i++) { 215 sqlCommand.set(i, (String)sqlCommand.get(i) + " " + pre + value + post); 216 } 217 } 218 } 219 else { 220 // no input value found 221 throw new IllegalArgumentException ("The key '" + key + "' in command \n'" 222 + command + "'\n does not exist in the input values."); 223 } 224 } 225 else { 226 // token is not a key, just add it 227 for (int i=0; i<sqlCommand.size(); i++) 228 sqlCommand.set(i, (String)sqlCommand.get(i) + " " + originalKey); 229 if (originalKey.equalsIgnoreCase("update") || 230 originalKey.equalsIgnoreCase("delete") || 231 originalKey.equalsIgnoreCase("insert")) { 232 update = true; 233 } 234 235 } 236 } 237 for (int i=0;i<sqlCommand.size(); i++) { 238 execute((String)sqlCommand.get(i), sqlOutput, update); 239 // merge output with input 240 if (!update && mergeOutputIntoInput) { 241 Enumeration keys = sqlOutput.keys(); 242 while(keys.hasMoreElements()) { 243 String key = (String)keys.nextElement(); 244 String[]val = (String[])sqlOutput.get(key); 245 if (val != null && val.length != 0) { 246 if (val.length == 1) 247 sqlInput.put(key, val[0]); 248 else 249 sqlInput.put(key, val); 250 } 251 } 252 } 253 } 254 if (!update && sqlOutput == null) 255 return false; 256 return true; 257 } 258 259 /** 260 * Execute any SQL command. 261 * @param command The command. 262 * @param update If true, it is a update/alter command instead of an select 263 * command 264 * @return A Hashtable with the result. 265 */ 266 private void execute(String command, Hashtable output, boolean update) { 267 if (m_bDebug) 268 System.out.println("Debug - SQLExecution - execute Command: " + command); 269 try { 270 if (update) { 271 // make an update 272 mStatement.executeUpdate(command); 273 } 274 else { 275 // make a select: collect the result 276 ResultSet sqlResult = mStatement.executeQuery(command); 277 ResultSetMetaData sqlRSMeta = sqlResult.getMetaData(); 278 int columnCount = sqlRSMeta.getColumnCount(); 279 String[] columnNames = new String[columnCount]; 280 int countRows = 0; 281 boolean goThroughRowsTheFirstTime = true; 282 for(int i=1; i<=columnCount; i++) { 283 columnNames[i-1] = sqlRSMeta.getColumnName(i); 284 // initialize output 285 Vector v = new Vector(); 286 287 sqlResult.beforeFirst(); 288 while (sqlResult.next()) { 289 String value = sqlResult.getString(i); 290 v.add(value); 291 // the first time: count rows 292 if (goThroughRowsTheFirstTime) 293 countRows++; 294 } 295 // rows are counted 296 if (goThroughRowsTheFirstTime) 297 goThroughRowsTheFirstTime = false; 298 299 // put result in output Hashtable 300 String[]s = new String[countRows]; 301 s = (String[])v.toArray(s); 302 output.put(columnNames[i-1], s); 303 if (m_bDebug) { 304 if (i == 1) { 305 System.out.print("Debug - SQLExecution - Command returns: "); 306 System.out.print("row: " + columnNames[i-1] + " vals: "); 307 } 308 for (int j=0; j<s.length; j++) 309 System.out.print(s[j] + " "); 310 if (i == columnCount - 1) 311 System.out.println(); 312 } 313 } 314 } 315 } 316 catch (java.sql.SQLException e) { 317 e.printStackTrace(); 318 } 319 } 320 321 /** 322 * Replace <"> with <''> in the value Strings, or the command will fail. 323 * @param checkString The String that is checked: a part of the command 324 * @return The String, cleared of all quotation marks. 325 */ 326 private String checkForQuotationMarks(String checkString) { 327 String returnString = checkString; 328 int quotIndex = 0; 329 while ((quotIndex = returnString.indexOf('\"')) != -1) { 330 String firstHalf = returnString.substring(0, quotIndex); 331 String secondHalf = returnString.substring(quotIndex+1); 332 returnString = firstHalf + "\'\'" + secondHalf; 333 } 334 return returnString; 335 } 336 337 } 338