1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.tools.ij.util |
4 | |
5 | Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.impl.tools.ij; |
22 | |
23 | import org.apache.derby.tools.JDBCDisplayUtil; |
24 | import org.apache.derby.iapi.tools.i18n.*; |
25 | |
26 | import java.io.BufferedInputStream; |
27 | import java.io.FileInputStream; |
28 | import java.io.FileNotFoundException; |
29 | import java.io.InputStream; |
30 | import java.io.IOException; |
31 | import java.lang.reflect.InvocationTargetException; |
32 | |
33 | import java.sql.Connection; |
34 | import java.sql.DriverManager; |
35 | import java.sql.SQLException; |
36 | import java.sql.SQLWarning; |
37 | import java.sql.Statement; |
38 | import java.sql.PreparedStatement; |
39 | import java.sql.ResultSet; |
40 | import java.sql.ResultSetMetaData; |
41 | import java.sql.Types; |
42 | |
43 | import java.util.Properties; |
44 | import java.util.Vector; |
45 | import java.util.Locale; |
46 | |
47 | /** |
48 | Methods used to control setup for apps as |
49 | well as display some internal ij structures. |
50 | |
51 | @see org.apache.derby.tools.JDBCDisplayUtil |
52 | @author ames |
53 | */ |
54 | public final class util implements java.security.PrivilegedAction { |
55 | |
56 | private static boolean HAVE_BIG_DECIMAL; |
57 | |
58 | { |
59 | boolean haveBigDecimal; |
60 | try { |
61 | Class.forName("java.math.BigDecimal"); |
62 | haveBigDecimal = true; |
63 | } catch (Throwable t) { |
64 | haveBigDecimal = false; |
65 | } |
66 | HAVE_BIG_DECIMAL = haveBigDecimal; |
67 | } |
68 | |
69 | private static final Class[] DS_GET_CONN_TYPES = {"".getClass(), "".getClass()}; |
70 | private util() {} |
71 | |
72 | //----------------------------------------------------------------- |
73 | // Methods for starting up JBMS |
74 | |
75 | /** |
76 | * Find the argument that follows the specified parameter. |
77 | * |
78 | * @param param the parameter (e.g. "-p") |
79 | * @param args the argument list to consider. |
80 | * |
81 | * @return the argument that follows the parameter, or null if not found |
82 | */ |
83 | static public String getArg(String param, String[] args) |
84 | { |
85 | int pLocn; |
86 | Properties p; |
87 | |
88 | if (args == null) return null; |
89 | |
90 | for (pLocn=0; pLocn<args.length; pLocn++) { |
91 | if (param.equals(args[pLocn])) break; |
92 | } |
93 | if (pLocn >= (args.length-1)) // not found or no file |
94 | return null; |
95 | |
96 | return args[pLocn+1]; |
97 | } |
98 | |
99 | /** |
100 | ij is started with "-p[r] file OtherArgs"; |
101 | the file contains properties to control the driver and database |
102 | used to run ij, and can provide additional system properties. |
103 | <p> |
104 | getPropertyArg will look at the args and take out a "-p <file>" pair, |
105 | reading the file into the system properties. |
106 | <p> |
107 | If there was a -p without a following <file>, no action is taken. |
108 | |
109 | @exception IOException thrown if file not found |
110 | |
111 | @param args the argument list to consider. |
112 | @return true if a property item was found and loaded. |
113 | */ |
114 | static public boolean getPropertyArg(String[] args) throws IOException { |
115 | String n; |
116 | InputStream in1; |
117 | Properties p; |
118 | |
119 | if ((n = getArg("-p", args))!= null){ |
120 | in1 = new FileInputStream(n); |
121 | in1 = new BufferedInputStream(in1); |
122 | } |
123 | else if ((n = getArg("-pr", args)) != null) { |
124 | in1 = getResourceAsStream(n); |
125 | if (in1 == null) throw ijException.resourceNotFound(); |
126 | } |
127 | else |
128 | return false; |
129 | |
130 | p = System.getProperties(); |
131 | |
132 | // Trim off excess whitespace in property file, if any, and |
133 | // then load those properties into 'p'. |
134 | util.loadWithTrimmedValues(in1, p); |
135 | |
136 | return true; |
137 | } |
138 | |
139 | /** |
140 | ij is started with "-ca[r] file OtherArgs"; |
141 | the file contains connection attibute properties |
142 | to pass to getConnection |
143 | <p> |
144 | getConnAttributeArg will look at the args and take out a |
145 | "-ca[r] <file>" pair and returning the Properties |
146 | <p> |
147 | |
148 | @exception IOException thrown if file not found |
149 | |
150 | @param args the argument list to consider. |
151 | @return properties in the file |
152 | */ |
153 | static public Properties getConnAttributeArg(String[] args) |
154 | throws IOException |
155 | { |
156 | String n; |
157 | InputStream in1; |
158 | Properties p = new Properties(); |
159 | |
160 | if ((n = getArg("-ca", args))!= null){ |
161 | in1 = new FileInputStream(n); |
162 | in1 = new BufferedInputStream(in1); |
163 | } |
164 | else if ((n = getArg("-car", args)) != null) { |
165 | in1 = getResourceAsStream(n); |
166 | if (in1 == null) throw ijException.resourceNotFound(); |
167 | } |
168 | else |
169 | return null; |
170 | |
171 | // Trim off excess whitespace in property file, if any, and |
172 | // then load those properties into 'p'. |
173 | util.loadWithTrimmedValues(in1, p); |
174 | |
175 | return p; |
176 | } |
177 | |
178 | |
179 | |
180 | /** |
181 | Convenience routine to qualify a resource name with "ij.defaultPackageName" |
182 | if it is not qualified (does not begin with a "/"). |
183 | |
184 | @param absolute true means return null if the name is not absolute and false |
185 | means return partial names. |
186 | */ |
187 | static String qualifyResourceName(String resourceName, boolean absolute) |
188 | { |
189 | resourceName=resourceName.trim(); |
190 | if (resourceName.startsWith("/")) |
191 | { |
192 | return resourceName; |
193 | } |
194 | else |
195 | { |
196 | String pName = util.getSystemProperty("ij.defaultResourcePackage").trim(); |
197 | if (pName == null) return null; |
198 | if ((pName).endsWith("/")) |
199 | resourceName = pName+resourceName; |
200 | else |
201 | resourceName = pName+"/"+resourceName; |
202 | if (absolute && !resourceName.startsWith("/")) |
203 | return null; |
204 | else |
205 | return resourceName; |
206 | } |
207 | } |
208 | /** |
209 | Convenience routine to get a resource as a BufferedInputStream. If the |
210 | resourceName is not absolute (does not begin with a "/") this qualifies |
211 | the name with the "ij.defaultResourcePackage" name. |
212 | |
213 | @param resourceName the name of the resource |
214 | @return a buffered stream for the resource if it exists and null otherwise. |
215 | */ |
216 | static public InputStream getResourceAsStream(String resourceName) |
217 | { |
218 | Class c= util.class; |
219 | resourceName = qualifyResourceName(resourceName,true); |
220 | if (resourceName == null) |
221 | return null; |
222 | InputStream is = c.getResourceAsStream(resourceName); |
223 | if (is != null) |
224 | is = new BufferedInputStream(is, utilMain.BUFFEREDFILESIZE); |
225 | return is; |
226 | } |
227 | |
228 | /** |
229 | Return the name of the ij command file or null if none is |
230 | specified. The command file may be proceeded with -f flag on |
231 | the command line. Alternatively, the command file may be |
232 | specified without a -f flag. In this case we assume the first |
233 | unknown argument is the command file. |
234 | |
235 | <P> |
236 | This should only be called after calling invalidArgs. |
237 | |
238 | <p> |
239 | If there is no such argument, a null is returned. |
240 | |
241 | @param args the argument list to consider. |
242 | @return the name of the first argument not preceded by "-p", |
243 | null if none found. |
244 | |
245 | @exception IOException thrown if file not found |
246 | */ |
247 | static public String getFileArg(String[] args) throws IOException { |
248 | String fileName; |
249 | int fLocn; |
250 | boolean foundP = false; |
251 | |
252 | if (args == null) return null; |
253 | if ((fileName=getArg("-f",args))!=null) return fileName; |
254 | // |
255 | //The first unknown arg is the file |
256 | for (int ix=0; ix < args.length; ix++) |
257 | if(args[ix].equals("-f") || |
258 | args[ix].equals("-fr") || |
259 | args[ix].equals("-ca") || |
260 | args[ix].equals("-car") || |
261 | args[ix].equals("-p") || |
262 | args[ix].equals("-pr")) |
263 | ix++; //skip the parameter to these args |
264 | else |
265 | return args[ix]; |
266 | return null; |
267 | } |
268 | |
269 | /** |
270 | Return the name of a resource containing input commands or |
271 | null iff none has been specified. |
272 | */ |
273 | static public String getInputResourceNameArg(String[] args) { |
274 | return getArg("-fr", args); |
275 | } |
276 | |
277 | /** |
278 | Verify the ij line arguments command arguments. Also used to detect --help. |
279 | @return true if the args are invalid |
280 | <UL> |
281 | <LI>Only legal argument provided. |
282 | <LI>Only specify a quantity once. |
283 | </UL> |
284 | */ |
285 | static public boolean invalidArgs(String[] args) { |
286 | int countSupported = 0; |
287 | boolean haveInput = false; |
288 | for (int ix=0; ix < args.length; ix++) |
289 | { |
290 | // |
291 | //If the arguemnt is a supported flag skip the flags argument |
292 | if(!haveInput && (args[ix].equals("-f") || args[ix].equals("-fr"))) |
293 | { |
294 | haveInput = true; |
295 | ix++; |
296 | if (ix >= args.length) return true; |
297 | } |
298 | |
299 | else if ((args[ix].equals("-p") || args[ix].equals("-pr") || |
300 | args[ix].equals("-ca") || args[ix].equals("-car") )) |
301 | { |
302 | // next arg is the file/resource name |
303 | ix++; |
304 | if (ix >= args.length) return true; |
305 | } else if (args[ix].equals("--help")) { return true; } |
306 | |
307 | // |
308 | //Assume the first unknown arg is a file name. |
309 | else if (!haveInput) |
310 | { |
311 | haveInput = true; |
312 | } |
313 | |
314 | else |
315 | { |
316 | return true; |
317 | } |
318 | } |
319 | return false; |
320 | } |
321 | |
322 | /** |
323 | * print a usage message for invocations of main(). |
324 | */ |
325 | static void Usage(LocalizedOutput out) { |
326 | out.println( |
327 | LocalizedResource.getMessage("IJ_UsageJavaComCloudToolsIjPPropeInput")); |
328 | out.flush(); |
329 | } |
330 | |
331 | |
332 | private static final Class[] STRING_P = { "".getClass() }; |
333 | private static final Class[] INT_P = { Integer.TYPE }; |
334 | |
335 | |
336 | /** |
337 | * Sets up a data source with values specified in ij.dataSource.* properties or |
338 | * passed as parameters of this method |
339 | * |
340 | * @param ds DataSource object |
341 | * @param dbName Database Name |
342 | * @param firstTime If firstTime is false, ij.dataSource.createDatabase and ij.dataSource.databaseName |
343 | * properties will not be used. The value in parameter dbName will be used instead of |
344 | * ij.dataSource.databaseName. |
345 | * |
346 | * @throws Exception |
347 | */ |
348 | static public void setupDataSource(Object ds,String dbName,boolean firstTime) throws Exception { |
349 | // Loop over set methods on Datasource object, if there is a property |
350 | // then call the method with corresponding value. Call setCreateDatabase based on |
351 | //parameter create. |
352 | java.lang.reflect.Method[] methods = ds.getClass().getMethods(); |
353 | for (int i = 0; i < methods.length; i++) { |
354 | java.lang.reflect.Method m = methods[i]; |
355 | String name = m.getName(); |
356 | |
357 | if (name.startsWith("set") && (name.length() > "set".length())) { |
358 | //Check if setCreateDatabase has to be called based on create parameter |
359 | if(name.equals("setCreateDatabase") && !firstTime) |
360 | continue; |
361 | |
362 | String property = name.substring("set".length()); // setXyyyZwww |
363 | property = "ij.dataSource."+property.substring(0,1).toLowerCase(java.util.Locale.ENGLISH)+ property.substring(1); // xyyyZwww |
364 | String value = util.getSystemProperty(property); |
365 | if(name.equals("setDatabaseName") && !firstTime) |
366 | value = dbName; |
367 | if (value != null) { |
368 | try { |
369 | // call string method |
370 | m.invoke(ds, new Object[] {value}); |
371 | } catch (Throwable ignore) { |
372 | // failed, assume it's an integer parameter |
373 | m.invoke(ds, new Object[] {Integer.valueOf(value)}); |
374 | } |
375 | } |
376 | } |
377 | } |
378 | } |
379 | |
380 | /** |
381 | * Returns a connection obtained using the DataSource. This method will be called when ij.dataSource |
382 | * property is set. It uses ij.dataSource.* properties to get details for the connection. |
383 | * |
384 | * @param dsName Data Source name |
385 | * @param user User name |
386 | * @param password Password |
387 | * @param dbName Database Name |
388 | * @param firstTime Indicates if the method is called first time. This is passed to setupDataSource |
389 | * method. |
390 | * |
391 | * @throws SQLException |
392 | */ |
393 | public static Connection getDataSourceConnection(String dsName,String user,String password, |
394 | String dbName,boolean firstTime) throws SQLException{ |
395 | // Get a new proxied connection through DataSource |
396 | Object ds = null; // really javax.sql.DataSource |
397 | try { |
398 | |
399 | Class dc = Class.forName(dsName); |
400 | ds = dc.newInstance(); |
401 | |
402 | // set datasource properties |
403 | setupDataSource(ds,dbName,firstTime); |
404 | |
405 | // Java method call "by hand" { con = ds.getConnection(); } |
406 | // or con = ds.getConnection(user, password) |
407 | |
408 | java.lang.reflect.Method m = |
409 | user == null ? dc.getMethod("getConnection", null) : |
410 | dc.getMethod("getConnection", DS_GET_CONN_TYPES); |
411 | |
412 | return (java.sql.Connection) m.invoke(ds, |
413 | user == null ? null : new String[] {user, password}); |
414 | } catch (InvocationTargetException ite) |
415 | { |
416 | if (ite.getTargetException() instanceof SQLException) |
417 | throw (SQLException) ite.getTargetException(); |
418 | ite.printStackTrace(System.out); |
419 | } catch (Exception e) |
420 | { |
421 | e.printStackTrace(System.out); |
422 | } |
423 | return null; |
424 | } |
425 | |
426 | /** |
427 | This will look for the System properties "ij.driver" and "ij.database" |
428 | and return a java.sql.Connection if it successfully connects. |
429 | The deprecated driver and database properties are examined first. |
430 | <p> |
431 | If no connection was possible, it will return a null. |
432 | <p> |
433 | Failure to load the driver class is quietly ignored. |
434 | |
435 | @param defaultDriver the driver to use if no property value found |
436 | @param defaultURL the database URL to use if no property value found |
437 | @param connInfo Connection attributes to pass to getConnection |
438 | @return a connection to the defaultURL if possible; null if not. |
439 | @exception SQLException on failure to connect. |
440 | @exception ClassNotFoundException on failure to load driver. |
441 | @exception InstantiationException on failure to load driver. |
442 | @exception IllegalAccessException on failure to load driver. |
443 | */ |
444 | static public Connection startJBMS(String defaultDriver, String defaultURL, |
445 | Properties connInfo) |
446 | throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException |
447 | { |
448 | Connection con = null; |
449 | String driverName; |
450 | String databaseURL; |
451 | |
452 | // deprecate the non-ij prefix. actually, we should defer to jdbc.drivers... |
453 | driverName = util.getSystemProperty("driver"); |
454 | if (driverName == null) driverName = util.getSystemProperty("ij.driver"); |
455 | if (driverName == null || driverName.length()==0) driverName = defaultDriver; |
456 | if (driverName != null) { |
457 | util.loadDriver(driverName); |
458 | } |
459 | |
460 | String jdbcProtocol = util.getSystemProperty("ij.protocol"); |
461 | if (jdbcProtocol != null) |
462 | util.loadDriverIfKnown(jdbcProtocol); |
463 | |
464 | String user = util.getSystemProperty("ij.user"); |
465 | String password = util.getSystemProperty("ij.password"); |
466 | |
467 | // deprecate the non-ij prefix name |
468 | databaseURL = util.getSystemProperty("database"); |
469 | if (databaseURL == null) databaseURL = util.getSystemProperty("ij.database"); |
470 | if (databaseURL == null || databaseURL.length()==0) databaseURL = defaultURL; |
471 | if (databaseURL != null) { |
472 | // add protocol if might help find driver. |
473 | // if have full URL, load driver for it |
474 | if (databaseURL.startsWith("jdbc:")) |
475 | util.loadDriverIfKnown(databaseURL); |
476 | if (!databaseURL.startsWith("jdbc:") && jdbcProtocol != null) |
477 | databaseURL = jdbcProtocol+databaseURL; |
478 | |
479 | // Update connInfo for ij system properties and |
480 | // framework network server |
481 | |
482 | connInfo = updateConnInfo(user, password,connInfo); |
483 | |
484 | // JDBC driver |
485 | String driver = util.getSystemProperty("driver"); |
486 | if (driver == null) { |
487 | driver = "org.apache.derby.jdbc.EmbeddedDriver"; |
488 | } |
489 | |
490 | loadDriver(driver); |
491 | con = DriverManager.getConnection(databaseURL,connInfo); |
492 | return con; |
493 | } |
494 | |
495 | // handle datasource property |
496 | String dsName = util.getSystemProperty("ij.dataSource"); |
497 | if (dsName == null) |
498 | return null; |
499 | |
500 | //First connection - pass firstTime=true, dbName=null. For database name, |
501 | //value in ij.dataSource.databaseName will be used. |
502 | con = getDataSourceConnection(dsName,user,password,null,true); |
503 | return con; |
504 | } |
505 | |
506 | |
507 | public static Properties updateConnInfo(String user, String password, Properties connInfo) |
508 | { |
509 | String ijGetMessages = util.getSystemProperty("ij.retrieveMessagesFromServerOnGetMessage"); |
510 | boolean retrieveMessages = false; |
511 | |
512 | |
513 | // For JCC make sure we set it to retrieve messages |
514 | if (isJCCFramework()) |
515 | retrieveMessages = true; |
516 | |
517 | if (ijGetMessages != null) |
518 | { |
519 | if (ijGetMessages.equals("false")) |
520 | retrieveMessages = false; |
521 | else |
522 | retrieveMessages = true; |
523 | |
524 | } |
525 | |
526 | if (connInfo == null) |
527 | connInfo = new Properties(); |
528 | |
529 | if (retrieveMessages == true) |
530 | { |
531 | connInfo.put("retrieveMessagesFromServerOnGetMessage", |
532 | "true"); |
533 | } |
534 | if (user != null) |
535 | connInfo.put("user",user); |
536 | if (password != null) |
537 | connInfo.put("password", password); |
538 | |
539 | return connInfo; |
540 | } |
541 | |
542 | /** |
543 | Utility interface that defaults driver and database to null. |
544 | |
545 | @return a connection to the defaultURL if possible; null if not. |
546 | @exception SQLException on failure to connect. |
547 | @exception ClassNotFoundException on failure to load driver. |
548 | @exception InstantiationException on failure to load driver. |
549 | @exception IllegalAccessException on failure to load driver. |
550 | */ |
551 | static public Connection startJBMS() throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException { |
552 | return startJBMS(null,null); |
553 | } |
554 | |
555 | /** |
556 | Utility interface that defaults connInfo to null |
557 | <p> |
558 | |
559 | |
560 | @param defaultDriver the driver to use if no property value found |
561 | @param defaultURL the database URL to use if no property value found |
562 | @return a connection to the defaultURL if possible; null if not. |
563 | @exception SQLException on failure to connect. |
564 | @exception ClassNotFoundException on failure to load driver. |
565 | @exception InstantiationException on failure to load driver. |
566 | @exception IllegalAccessException on failure to load driver. |
567 | */ |
568 | static public Connection startJBMS(String defaultDriver, String defaultURL) |
569 | throws SQLException, ClassNotFoundException, InstantiationException, |
570 | IllegalAccessException { |
571 | return startJBMS(defaultDriver,defaultURL,null); |
572 | |
573 | } |
574 | //----------------------------------------------------------------- |
575 | // Methods for displaying and checking results |
576 | // See org.apache.derby.tools.JDBCDisplayUtil for more general displays. |
577 | |
578 | |
579 | /** |
580 | Display a vector of strings to the out stream. |
581 | */ |
582 | public static void DisplayVector(LocalizedOutput out, Vector v) { |
583 | int l = v.size(); |
584 | for (int i=0;i<l;i++) |
585 | out.println(v.elementAt(i)); |
586 | } |
587 | |
588 | /** |
589 | Display a vector of statements to the out stream. |
590 | public static void DisplayVector(AppStreamWriter out, Vector v, Connection conn) throws SQLException { |
591 | int l = v.size(); |
592 | AppUI.out.println("SIZE="+l); |
593 | for (int i=0;i<l;i++) { |
594 | Object o = v.elementAt(i); |
595 | if (o instanceof Integer) { // update count |
596 | JDBCDisplayUtil.DisplayUpdateCount(out,((Integer)o).intValue()); |
597 | } else { // o instanceof ResultSet |
598 | JDBCDisplayUtil.DisplayResults(out,(ResultSet)o,conn); |
599 | ((ResultSet)o).close(); // release the result set |
600 | } |
601 | } |
602 | } |
603 | */ |
604 | |
605 | /** |
606 | Display a statement that takes parameters by |
607 | stuffing it with rows from the result set and |
608 | displaying each result each time through. |
609 | Deal with autocommit behavior along the way. |
610 | |
611 | @exception SQLException thrown on db error |
612 | @exception ijException thrown on ij error |
613 | */ |
614 | public static void DisplayMulti(LocalizedOutput out, PreparedStatement ps, |
615 | ResultSet rs, Connection conn) throws SQLException, ijException { |
616 | |
617 | boolean autoCommited = false; // mark if autocommit in place |
618 | boolean exec = false; // mark the first time through |
619 | boolean anotherUsingRow = false; // remember if there's another row |
620 | // from using. |
621 | ResultSetMetaData rsmd = rs.getMetaData(); |
622 | int numCols = rsmd.getColumnCount(); |
623 | |
624 | /* NOTE: We need to close the USING RS first |
625 | * so that RunTimeStatistic gets info from |
626 | * the user query. |
627 | */ |
628 | anotherUsingRow = rs.next(); |
629 | |
630 | while (! autoCommited && anotherUsingRow) { |
631 | // note the first time through |
632 | if (!exec) { |
633 | exec = true; |
634 | |
635 | // send a warning if additional results may be lost |
636 | if (conn.getAutoCommit()) { |
637 | out.println(LocalizedResource.getMessage("IJ_IjWarniAutocMayCloseUsingResulSet")); |
638 | autoCommited = true; |
639 | } |
640 | } |
641 | |
642 | // We need to make sure we pass along the scale, because |
643 | // setObject assumes a scale of zero (beetle 4365) |
644 | for (int c=1; c<=numCols; c++) { |
645 | int sqlType = rsmd.getColumnType(c); |
646 | |
647 | if (sqlType == Types.DECIMAL) |
648 | { |
649 | if (util.HAVE_BIG_DECIMAL) |
650 | { |
651 | ps.setObject(c,rs.getObject(c), |
652 | sqlType, |
653 | rsmd.getScale(c)); |
654 | } |
655 | else |
656 | { |
657 | // In J2ME there is no object that represents |
658 | // a DECIMAL value. By default use String to |
659 | // pass values around, but for integral types |
660 | // first convert to a integral type from the DECIMAL |
661 | // because strings like 3.4 are not convertible to |
662 | // an integral type. |
663 | switch (ps.getMetaData().getColumnType(c)) |
664 | { |
665 | case Types.BIGINT: |
666 | ps.setLong(c, rs.getLong(c)); |
667 | break; |
668 | case Types.INTEGER: |
669 | case Types.SMALLINT: |
670 | case Types.TINYINT: |
671 | ps.setInt(c, rs.getInt(c)); |
672 | break; |
673 | default: |
674 | ps.setString(c,rs.getString(c)); |
675 | break; |
676 | } |
677 | } |
678 | |
679 | } |
680 | else |
681 | { |
682 | ps.setObject(c,rs.getObject(c), |
683 | sqlType); |
684 | } |
685 | |
686 | |
687 | |
688 | } |
689 | |
690 | |
691 | // Advance in the USING RS |
692 | anotherUsingRow = rs.next(); |
693 | // Close the USING RS when exhausted and appropriate |
694 | // NOTE: Close before the user query |
695 | if (! anotherUsingRow || conn.getAutoCommit()) //if no more rows or if auto commit is on, close the resultset |
696 | { |
697 | rs.close(); |
698 | } |
699 | |
700 | /* |
701 | 4. execute the statement against those parameters |
702 | */ |
703 | |
704 | ps.execute(); |
705 | JDBCDisplayUtil.DisplayResults(out,ps,conn); |
706 | |
707 | /* |
708 | 5. clear the parameters |
709 | */ |
710 | ps.clearParameters(); |
711 | } |
712 | if (!exec) { |
713 | rs.close(); //this means, using clause didn't qualify any rows. Just close the resultset associated with using clause |
714 | throw ijException.noUsingResults(); |
715 | } |
716 | // REMIND: any way to look for more rsUsing rows if autoCommit? |
717 | // perhaps just document the behavior... |
718 | } |
719 | |
720 | static final String getSystemProperty(String propertyName) { |
721 | try |
722 | { |
723 | if (propertyName.startsWith("ij.") || propertyName.startsWith("derby.")) |
724 | { |
725 | util u = new util(); |
726 | u.key = propertyName; |
727 | return (String) java.security.AccessController.doPrivileged(u); |
728 | } |
729 | else |
730 | { |
731 | return System.getProperty(propertyName); |
732 | } |
733 | } catch (SecurityException se) { |
734 | return null; |
735 | } |
736 | } |
737 | |
738 | private String key; |
739 | |
740 | public final Object run() { |
741 | return System.getProperty(key); |
742 | } |
743 | /** |
744 | * Read a set of properties from the received input stream, strip |
745 | * off any excess white space that exists in those property values, |
746 | * and then add those newly-read properties to the received |
747 | * Properties object; not explicitly removing the whitespace here can |
748 | * lead to problems. |
749 | * |
750 | * This method exists because of the manner in which the jvm reads |
751 | * properties from file--extra spaces are ignored after a _key_, but |
752 | * if they exist at the _end_ of a property decl line (i.e. as part |
753 | * of a _value_), they are preserved, as outlined in the Java API: |
754 | * |
755 | * "Any whitespace after the key is skipped; if the first non- |
756 | * whitespace character after the key is = or :, then it is ignored |
757 | * and any whitespace characters after it are also skipped. All |
758 | * remaining characters on the line become part of the associated |
759 | * element string." |
760 | * |
761 | * Creates final properties set consisting of 'prop' plus all |
762 | * properties loaded from 'iStr' (with the extra whitespace (if any) |
763 | * removed from all values), will be returned via the parameter. |
764 | * |
765 | * @param iStr An input stream from which the new properties are to be |
766 | * loaded (should already be initialized). |
767 | * @param prop A set of properties to which the properties from |
768 | * iStr will be added (should already be initialized). |
769 | * |
770 | * Copied here to avoid dependency on an engine class. |
771 | **/ |
772 | private static void loadWithTrimmedValues(InputStream iStr, |
773 | Properties prop) throws IOException { |
774 | |
775 | // load the properties from the received input stream. |
776 | Properties p = new Properties(); |
777 | p.load(iStr); |
778 | |
779 | // Now, trim off any excess whitespace, if any, and then |
780 | // add the properties from file to the received Properties |
781 | // set. |
782 | for (java.util.Enumeration propKeys = p.propertyNames(); |
783 | propKeys.hasMoreElements();) { |
784 | // get the value, trim off the whitespace, then store it |
785 | // in the received properties object. |
786 | String tmpKey = (String)propKeys.nextElement(); |
787 | String tmpValue = p.getProperty(tmpKey); |
788 | tmpValue = tmpValue.trim(); |
789 | prop.put(tmpKey, tmpValue); |
790 | } |
791 | |
792 | return; |
793 | |
794 | } |
795 | |
796 | private static final String[][] protocolDrivers = |
797 | { |
798 | { "jdbc:derby:net:", "com.ibm.db2.jcc.DB2Driver"}, |
799 | { "jdbc:derby://", "org.apache.derby.jdbc.ClientDriver"}, |
800 | |
801 | { "jdbc:derby:", "org.apache.derby.jdbc.EmbeddedDriver" }, |
802 | }; |
803 | |
804 | /** |
805 | Find the appropriate driver and load it, given a JDBC URL. |
806 | No action if no driver known for a given URL. |
807 | |
808 | @param jdbcProtocol the protocol to try. |
809 | |
810 | @exception ClassNotFoundException if unable to |
811 | locate class for driver. |
812 | @exception InstantiationException if unable to |
813 | create an instance. |
814 | @exception IllegalAccessException if driver class constructor not visible. |
815 | */ |
816 | public static void loadDriverIfKnown(String jdbcProtocol) throws ClassNotFoundException, InstantiationException, IllegalAccessException { |
817 | for (int i=0; i < protocolDrivers.length; i++) { |
818 | if (jdbcProtocol.startsWith(protocolDrivers[i][0])) { |
819 | loadDriver(protocolDrivers[i][1]); |
820 | break; // only want the first one |
821 | } |
822 | } |
823 | } |
824 | |
825 | /** |
826 | Load a driver given a class name. |
827 | |
828 | @exception ClassNotFoundException if unable to |
829 | locate class for driver. |
830 | @exception InstantiationException if unable to |
831 | create an instance. |
832 | @exception IllegalAccessException if driver class constructor not visible. |
833 | */ |
834 | public static void loadDriver(String driverClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException { |
835 | Class.forName(driverClass).newInstance(); |
836 | } |
837 | |
838 | /** |
839 | * Used to determine if this is a JCC testing framework |
840 | * So that retrieveMessages can be sent. The plan is to have |
841 | * ij will retrieve messages by default and not look at the testing |
842 | * frameworks. So, ulitmately this function will look at the driver |
843 | * rather than the framework. |
844 | * |
845 | * @return true if the framework contains Net or JCC. |
846 | */ |
847 | private static boolean isJCCFramework() |
848 | { |
849 | String framework = util.getSystemProperty("framework"); |
850 | return ((framework != null) && |
851 | ((framework.toUpperCase(Locale.ENGLISH).equals("DERBYNET")) || |
852 | (framework.toUpperCase(Locale.ENGLISH).indexOf("JCC") != -1))); |
853 | } |
854 | |
855 | |
856 | } |
857 | |