1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SQLExecution.java,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 import java
.sql
.Connection
;
33 import java
.sql
.DriverManager
;
34 import java
.sql
.ResultSet
;
35 import java
.sql
.ResultSetMetaData
;
36 import java
.sql
.Statement
;
37 import java
.util
.Enumeration
;
38 import java
.util
.Hashtable
;
39 import java
.util
.StringTokenizer
;
40 import java
.util
.Vector
;
45 public class SQLExecution
{
47 protected Connection mConnection
= null;
48 protected Statement mStatement
= null;
49 protected String mJdbcClass
= null;
50 protected String mDbURL
= null;
51 protected String mUser
= null;
52 protected String mPassword
= null;
53 protected boolean m_bConnectionOpen
= false;
54 protected boolean m_bDebug
= false;
57 /** Creates a new instance of SQLExecution
58 * @param jdbcClass The jdbc class for the connection.
59 * @param dbUrl The url of the database.
60 * @param user The user for connecting the database.
61 * @param password The password of throws user.
63 public SQLExecution(String jdbcClass
, String dbUrl
, String user
, String password
) {
64 mJdbcClass
= jdbcClass
;
70 /** Creates a new instance of SQLExecution with additional debug output.
71 * @param jdbcClass The jdbc class for the connection.
72 * @param dbUrl The url of the database.
73 * @param user The user for connecting the database.
74 * @param password The password of throws user.
75 * @param debug Write debug information, if true.
77 public SQLExecution(String jdbcClass
, String dbUrl
, String user
, String password
, boolean debug
) {
78 mJdbcClass
= jdbcClass
;
86 * Open a connection to the DataBase
87 * @return True, if no error occured.
89 public boolean openConnection() {
90 if(m_bConnectionOpen
) return true;
92 Class
.forName(mJdbcClass
);
93 } catch (ClassNotFoundException e
) {
94 System
.err
.println("Couldn't find jdbc driver : " + e
.getMessage());
99 // establish database connection
100 mConnection
= DriverManager
.getConnection(
101 mDbURL
, mUser
, mPassword
);
102 mStatement
= mConnection
.createStatement();
104 catch(java
.sql
.SQLException e
) {
105 System
.err
.println("Couldn't establish a connection: " + e
.getMessage());
108 m_bConnectionOpen
= true;
113 * Close the connection to the DataBase
114 * @return True, if no error occured.
116 public boolean closeConnection() {
117 if (!m_bConnectionOpen
) return true;
119 // close database connection
123 catch(java
.sql
.SQLException e
) {
124 System
.err
.println("Couldn't close the connection: " + e
.getMessage());
127 m_bConnectionOpen
= false;
132 * Execute an sql command.
133 * @param command The command to execute.
134 * @param sqlInput Input values for the command.
135 * @param sqlOutput The results of the command are put in this Hashtable.
136 * @return True, if no error occured.
138 public boolean executeSQLCommand(String command
, Hashtable sqlInput
, Hashtable sqlOutput
)
139 throws IllegalArgumentException
{
140 return executeSQLCommand(command
, sqlInput
, sqlOutput
, false);
144 * Execute an sql command.
145 * @param command The command to execute.
146 * @param sqlInput Input values for the command.
147 * @param sqlOutput The results of the command are put in this Hashtable.
148 * @param mergeOutputIntoInput The output of the result is put into the
149 * sqlInput Hashtable.
150 * @return True, if no error occured.
152 public boolean executeSQLCommand(String command
, Hashtable sqlInput
, Hashtable sqlOutput
, boolean mergeOutputIntoInput
)
153 throws IllegalArgumentException
{
154 if (sqlOutput
== null) {
155 sqlOutput
= new Hashtable();
156 // this has to be true, so the user of this method gets a return
157 mergeOutputIntoInput
= true;
158 if (sqlInput
== null) {
159 System
.out
.println("sqlInput and sqlOutput are null: cannot return the results of the sql command.");
163 Vector sqlCommand
= new Vector();
165 boolean update
= false;
166 // synchronize all "$varname" occurences in the command string with
168 StringTokenizer token
= new StringTokenizer(command
, " ");
169 while (token
.hasMoreTokens()) {
170 String originalKey
= token
.nextToken();
171 // search for keys, beginning with "$"
172 int index
= originalKey
.indexOf('$');
176 pre
= originalKey
.substring(0,index
);
177 // generate key: remove "$"
178 String key
= originalKey
.substring(index
+1);
180 // remove any endings the key might have
181 while (key
.endsWith(",") || key
.endsWith("\'") ||
182 key
.endsWith(";") || key
.endsWith(")") ||
183 key
.endsWith("\"")) {
184 post
= key
.substring(key
.length()-1) + post
;
185 key
= key
.substring(0, key
.length()-1);
187 // look for key in the Hashtable
188 if (sqlInput
.containsKey(key
)) {
189 // is there a value for the key?
190 Object in
= sqlInput
.get(key
);
191 if (in
instanceof String
[]) {
192 // value is a String[]
193 String
[]vals
= (String
[])in
;
194 if (vals
.length
!= sqlCommand
.size() && sqlCommand
.size() > 1) {
195 // size of this array and previous array(s) does not match
196 throw new IllegalArgumentException("The key '" + key
+ "' in command \n'"
197 + command
+ "'\n has not the same value count as the keys before.");
199 // build up the commands
200 boolean addNewVals
= (sqlCommand
.size() == 1);
201 for (int i
=0; i
<vals
.length
; i
++) {
202 String value
= checkForQuotationMarks(vals
[i
]);
204 if (addNewVals
&& i
!=0) {
205 // all values until now were of type String, not String[], so now new values have to be added.
206 sqlCommand
.add(i
, (String
)sqlCommand
.get(0) + " " + pre
+ value
+ post
);
209 // we already have vals.length commands (or are at the first command), so just add.
210 sqlCommand
.set(i
, (String
)sqlCommand
.get(i
) + " " + pre
+ value
+ post
);
215 // value is a String: no other possibility
216 String value
= checkForQuotationMarks((String
)sqlInput
.get(key
));
217 for (int i
=0; i
<sqlCommand
.size(); i
++) {
218 sqlCommand
.set(i
, (String
)sqlCommand
.get(i
) + " " + pre
+ value
+ post
);
223 // no input value found
224 throw new IllegalArgumentException ("The key '" + key
+ "' in command \n'"
225 + command
+ "'\n does not exist in the input values.");
229 // token is not a key, just add it
230 for (int i
=0; i
<sqlCommand
.size(); i
++)
231 sqlCommand
.set(i
, (String
)sqlCommand
.get(i
) + " " + originalKey
);
232 if (originalKey
.equalsIgnoreCase("update") ||
233 originalKey
.equalsIgnoreCase("delete") ||
234 originalKey
.equalsIgnoreCase("insert")) {
240 for (int i
=0;i
<sqlCommand
.size(); i
++) {
241 execute((String
)sqlCommand
.get(i
), sqlOutput
, update
);
242 // merge output with input
243 if (!update
&& mergeOutputIntoInput
) {
244 Enumeration keys
= sqlOutput
.keys();
245 while(keys
.hasMoreElements()) {
246 String key
= (String
)keys
.nextElement();
247 String
[]val
= (String
[])sqlOutput
.get(key
);
248 if (val
!= null && val
.length
!= 0) {
250 sqlInput
.put(key
, val
[0]);
252 sqlInput
.put(key
, val
);
257 if (!update
&& sqlOutput
== null)
263 * Execute any SQL command.
264 * @param command The command.
265 * @param update If true, it is a update/alter command instead of an select
267 * @return A Hashtable with the result.
269 private void execute(String command
, Hashtable output
, boolean update
) {
271 System
.out
.println("Debug - SQLExecution - execute Command: " + command
);
275 mStatement
.executeUpdate(command
);
278 // make a select: collect the result
279 ResultSet sqlResult
= mStatement
.executeQuery(command
);
280 ResultSetMetaData sqlRSMeta
= sqlResult
.getMetaData();
281 int columnCount
= sqlRSMeta
.getColumnCount();
282 String
[] columnNames
= new String
[columnCount
];
284 boolean goThroughRowsTheFirstTime
= true;
285 for(int i
=1; i
<=columnCount
; i
++) {
286 columnNames
[i
-1] = sqlRSMeta
.getColumnName(i
);
288 Vector v
= new Vector();
290 sqlResult
.beforeFirst();
291 while (sqlResult
.next()) {
292 String value
= sqlResult
.getString(i
);
294 // the first time: count rows
295 if (goThroughRowsTheFirstTime
)
299 if (goThroughRowsTheFirstTime
)
300 goThroughRowsTheFirstTime
= false;
302 // put result in output Hashtable
303 String
[]s
= new String
[countRows
];
304 s
= (String
[])v
.toArray(s
);
305 output
.put(columnNames
[i
-1], s
);
308 System
.out
.print("Debug - SQLExecution - Command returns: ");
309 System
.out
.print("row: " + columnNames
[i
-1] + " vals: ");
311 for (int j
=0; j
<s
.length
; j
++)
312 System
.out
.print(s
[j
] + " ");
313 if (i
== columnCount
- 1)
314 System
.out
.println();
319 catch (java
.sql
.SQLException e
) {
325 * Replace <"> with <''> in the value Strings, or the command will fail.
326 * @param checkString The String that is checked: a part of the command
327 * @return The String, cleared of all quotation marks.
329 private String
checkForQuotationMarks(String checkString
) {
330 String returnString
= checkString
;
332 while ((quotIndex
= returnString
.indexOf('\"')) != -1) {
333 String firstHalf
= returnString
.substring(0, quotIndex
);
334 String secondHalf
= returnString
.substring(quotIndex
+1);
335 returnString
= firstHalf
+ "\'\'" + secondHalf
;