1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. 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, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 package com.sun.star.comp.sdbc; 22 23 import java.io.ByteArrayInputStream; 24 import java.io.InputStreamReader; 25 import java.io.UnsupportedEncodingException; 26 import java.math.BigDecimal; 27 28 import org.apache.openoffice.comp.sdbc.dbtools.util.DBTypeConversion; 29 import org.apache.openoffice.comp.sdbc.dbtools.util.DbTools; 30 import org.apache.openoffice.comp.sdbc.dbtools.util.ORowSetValue; 31 import org.apache.openoffice.comp.sdbc.dbtools.util.Resources; 32 import org.apache.openoffice.comp.sdbc.dbtools.util.SharedResources; 33 import org.apache.openoffice.comp.sdbc.dbtools.util.StandardSQLState; 34 35 import com.sun.star.io.IOException; 36 import com.sun.star.io.XInputStream; 37 import com.sun.star.lang.IllegalArgumentException; 38 import com.sun.star.lang.XServiceInfo; 39 import com.sun.star.logging.LogLevel; 40 import com.sun.star.sdbc.DataType; 41 import com.sun.star.sdbc.SQLException; 42 import com.sun.star.sdbc.XArray; 43 import com.sun.star.sdbc.XBlob; 44 import com.sun.star.sdbc.XClob; 45 import com.sun.star.sdbc.XConnection; 46 import com.sun.star.sdbc.XParameters; 47 import com.sun.star.sdbc.XPreparedBatchExecution; 48 import com.sun.star.sdbc.XPreparedStatement; 49 import com.sun.star.sdbc.XRef; 50 import com.sun.star.sdbc.XResultSet; 51 import com.sun.star.sdbc.XResultSetMetaData; 52 import com.sun.star.sdbc.XResultSetMetaDataSupplier; 53 import com.sun.star.uno.Any; 54 import com.sun.star.uno.AnyConverter; 55 import com.sun.star.util.Date; 56 import com.sun.star.util.DateTime; 57 import com.sun.star.util.Time; 58 59 public class JavaSQLPreparedStatement extends JavaSQLStatementBase 60 implements XPreparedStatement, XResultSetMetaDataSupplier, XParameters, XPreparedBatchExecution, XServiceInfo { 61 62 private static final String[] services = { 63 "com.sun.star.sdbc.PreparedStatement" 64 }; 65 JavaSQLPreparedStatement(JavaSQLConnection connection, String sqlStatement)66 public JavaSQLPreparedStatement(JavaSQLConnection connection, String sqlStatement) { 67 super(connection); 68 this.sqlStatement = sqlStatement; 69 } 70 71 @Override createStatement()72 protected void createStatement() throws SQLException { 73 checkDisposed(); 74 if (jdbcStatement == null) { 75 try { 76 try { 77 jdbcStatement = connection.getJDBCConnection().prepareStatement( 78 sqlStatement, resultSetType, resultSetConcurrency); 79 } catch (NoSuchMethodError noSuchMethodError) { 80 jdbcStatement = connection.getJDBCConnection().prepareStatement(sqlStatement); 81 } 82 } catch (java.sql.SQLException sqlException) { 83 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 84 } 85 } 86 } 87 88 // XServiceInfo 89 90 @Override getImplementationName()91 public String getImplementationName() { 92 return "com.sun.star.sdbcx.JPreparedStatement"; 93 } 94 95 @Override getSupportedServiceNames()96 public String[] getSupportedServiceNames() { 97 return services.clone(); 98 } 99 100 @Override supportsService(String serviceName)101 public boolean supportsService(String serviceName) { 102 for (String service : services) { 103 if (service.equals(serviceName)) { 104 return true; 105 } 106 } 107 return false; 108 } 109 110 // XPreparedStatement 111 112 @Override execute()113 public synchronized boolean execute() throws SQLException { 114 createStatement(); 115 logger.log(LogLevel.FINE, Resources.STR_LOG_EXECUTING_PREPARED); 116 try { 117 return ((java.sql.PreparedStatement)jdbcStatement).execute(); 118 } catch (java.sql.SQLException sqlException) { 119 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 120 } 121 } 122 123 @Override executeUpdate()124 public synchronized int executeUpdate() throws SQLException { 125 createStatement(); 126 logger.log(LogLevel.FINE, Resources.STR_LOG_EXECUTING_PREPARED_UPDATE); 127 try { 128 return ((java.sql.PreparedStatement)jdbcStatement).executeUpdate(); 129 } catch (java.sql.SQLException sqlException) { 130 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 131 } 132 } 133 134 @Override executeQuery()135 public synchronized XResultSet executeQuery() throws SQLException { 136 createStatement(); 137 logger.log(LogLevel.FINE, Resources.STR_LOG_EXECUTING_PREPARED_QUERY); 138 try { 139 java.sql.ResultSet jdbcResults = ((java.sql.PreparedStatement)jdbcStatement).executeQuery(); 140 if (jdbcResults != null) { 141 return new JavaSQLResultSet(jdbcResults, connection); 142 } 143 return null; 144 } catch (java.sql.SQLException sqlException) { 145 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 146 } 147 } 148 149 @Override getConnection()150 public XConnection getConnection() throws SQLException { 151 return connection; 152 } 153 154 // XParameters 155 156 @Override setArray(int index, XArray x)157 public synchronized void setArray(int index, XArray x) throws SQLException { 158 String error = SharedResources.getInstance().getResourceStringWithSubstitution( 159 Resources.STR_UNSUPPORTED_FEATURE, "$featurename$", "XParameters::setArray"); 160 throw new SQLException(error, this, StandardSQLState.SQL_FEATURE_NOT_IMPLEMENTED.text(), 0, Any.VOID); 161 } 162 163 @Override setBinaryStream(int index, XInputStream x, int length)164 public synchronized void setBinaryStream(int index, XInputStream x, int length) throws SQLException { 165 logger.log(LogLevel.FINER, Resources.STR_LOG_BINARYSTREAM_PARAMETER, index); 166 createStatement(); 167 try { 168 // FIXME: why did the C++ implementation copy the stream here? It's a huge waste of memory. 169 byte[][] bytesReference = new byte[1][0]; 170 int bytesRead = x.readBytes(bytesReference, length); 171 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytesReference[0], 0, bytesRead); 172 ((java.sql.PreparedStatement)jdbcStatement).setBinaryStream(index, byteArrayInputStream, bytesRead); 173 } catch (java.sql.SQLException | IOException exception) { 174 throw Tools.toUnoExceptionLogged(this, logger, exception); 175 } 176 } 177 178 @Override setBlob(int index, XBlob x)179 public synchronized void setBlob(int index, XBlob x) throws SQLException { 180 String error = SharedResources.getInstance().getResourceStringWithSubstitution( 181 Resources.STR_UNSUPPORTED_FEATURE, "$featurename$", "XParameters::setBlob"); 182 throw new SQLException(error, this, StandardSQLState.SQL_FEATURE_NOT_IMPLEMENTED.text(), 0, Any.VOID); 183 } 184 185 @Override setBoolean(int index, boolean x)186 public synchronized void setBoolean(int index, boolean x) throws SQLException { 187 createStatement(); 188 logger.log(LogLevel.FINE, Resources.STR_LOG_BOOLEAN_PARAMETER, index, x); 189 try { 190 ((java.sql.PreparedStatement)jdbcStatement).setBoolean(index, x); 191 } catch (java.sql.SQLException sqlException) { 192 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 193 } 194 } 195 196 @Override setByte(int index, byte x)197 public synchronized void setByte(int index, byte x) throws SQLException { 198 createStatement(); 199 logger.log(LogLevel.FINE, Resources.STR_LOG_BYTE_PARAMETER, index, x); 200 try { 201 ((java.sql.PreparedStatement)jdbcStatement).setByte(index, x); 202 } catch (java.sql.SQLException sqlException) { 203 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 204 } 205 } 206 207 @Override setBytes(int index, byte[] x)208 public synchronized void setBytes(int index, byte[] x) throws SQLException { 209 createStatement(); 210 logger.log(LogLevel.FINE, Resources.STR_LOG_BYTES_PARAMETER, index); 211 try { 212 ((java.sql.PreparedStatement)jdbcStatement).setBytes(index, x.clone()); 213 } catch (java.sql.SQLException sqlException) { 214 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 215 } 216 } 217 218 @Override setCharacterStream(int index, XInputStream x, int length)219 public synchronized void setCharacterStream(int index, XInputStream x, int length) throws SQLException { 220 createStatement(); 221 logger.log(LogLevel.FINER, Resources.STR_LOG_CHARSTREAM_PARAMETER, index); 222 try { 223 // FIXME: why did the C++ implementation copy the stream here? It's a huge waste of memory. 224 byte[][] bytesReference = new byte[1][0]; 225 int bytesRead = x.readBytes(bytesReference, length); 226 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytesReference[0], 0, bytesRead); 227 InputStreamReader inputStreamReader = new InputStreamReader(byteArrayInputStream, "UTF-16LE"); 228 ((java.sql.PreparedStatement)jdbcStatement).setCharacterStream(index, inputStreamReader, length); 229 } catch (java.sql.SQLException | IOException | UnsupportedEncodingException exception) { 230 throw Tools.toUnoExceptionLogged(this, logger, exception); 231 } 232 } 233 234 @Override setClob(int index, XClob x)235 public synchronized void setClob(int index, XClob x) throws SQLException { 236 String error = SharedResources.getInstance().getResourceStringWithSubstitution( 237 Resources.STR_UNSUPPORTED_FEATURE, "$featurename$", "XParameters::setClob"); 238 throw new SQLException(error, this, StandardSQLState.SQL_FEATURE_NOT_IMPLEMENTED.text(), 0, Any.VOID); 239 } 240 241 @Override setDate(int index, Date x)242 public synchronized void setDate(int index, Date x) throws SQLException { 243 createStatement(); 244 logger.log(LogLevel.FINE, Resources.STR_LOG_DATE_PARAMETER, index, x); 245 try { 246 ((java.sql.PreparedStatement)jdbcStatement).setDate( 247 index, java.sql.Date.valueOf(DBTypeConversion.toDateString(x))); 248 } catch (java.sql.SQLException sqlException) { 249 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 250 } 251 } 252 253 @Override setDouble(int index, double x)254 public synchronized void setDouble(int index, double x) throws SQLException { 255 createStatement(); 256 logger.log(LogLevel.FINE, Resources.STR_LOG_DOUBLE_PARAMETER, index, x); 257 try { 258 ((java.sql.PreparedStatement)jdbcStatement).setDouble(index, x); 259 } catch (java.sql.SQLException sqlException) { 260 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 261 } 262 } 263 264 @Override setFloat(int index, float x)265 public synchronized void setFloat(int index, float x) throws SQLException { 266 createStatement(); 267 logger.log(LogLevel.FINE, Resources.STR_LOG_FLOAT_PARAMETER, index, x); 268 try { 269 ((java.sql.PreparedStatement)jdbcStatement).setFloat(index, x); 270 } catch (java.sql.SQLException sqlException) { 271 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 272 } 273 } 274 275 @Override setInt(int index, int x)276 public synchronized void setInt(int index, int x) throws SQLException { 277 createStatement(); 278 logger.log(LogLevel.FINE, Resources.STR_LOG_INT_PARAMETER, index, x); 279 try { 280 ((java.sql.PreparedStatement)jdbcStatement).setInt(index, x); 281 } catch (java.sql.SQLException sqlException) { 282 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 283 } 284 } 285 286 @Override setLong(int index, long x)287 public synchronized void setLong(int index, long x) throws SQLException { 288 createStatement(); 289 logger.log(LogLevel.FINE, Resources.STR_LOG_LONG_PARAMETER, index, x); 290 try { 291 ((java.sql.PreparedStatement)jdbcStatement).setLong(index, x); 292 } catch (java.sql.SQLException sqlException) { 293 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 294 } 295 } 296 297 @Override setNull(int index, int sqlType)298 public synchronized void setNull(int index, int sqlType) throws SQLException { 299 createStatement(); 300 logger.log(LogLevel.FINE, Resources.STR_LOG_NULL_PARAMETER, index, sqlType); 301 try { 302 ((java.sql.PreparedStatement)jdbcStatement).setNull(index, sqlType); 303 } catch (java.sql.SQLException sqlException) { 304 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 305 } 306 } 307 308 @Override setObject(int index, Object x)309 public void setObject(int index, Object x) throws SQLException { 310 if (!DbTools.setObject(this, index, x)) { 311 String error = SharedResources.getInstance().getResourceStringWithSubstitution( 312 Resources.STR_UNKNOWN_PARA_TYPE, "$position$", Integer.toString(index)); 313 throw new SQLException(error, this, StandardSQLState.SQL_GENERAL_ERROR.text(), 0, Any.VOID); 314 } 315 } 316 317 @Override setObjectNull(int index, int sqlType, String typeName)318 public synchronized void setObjectNull(int index, int sqlType, String typeName) throws SQLException { 319 createStatement(); 320 logger.log(LogLevel.FINER, Resources.STR_LOG_OBJECT_NULL_PARAMETER, index); 321 try { 322 ((java.sql.PreparedStatement)jdbcStatement).setObject(index, null); 323 } catch (java.sql.SQLException sqlException) { 324 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 325 } 326 } 327 328 @Override setObjectWithInfo(int index, Object x, int targetSqlType, int scale)329 public synchronized void setObjectWithInfo(int index, Object x, int targetSqlType, int scale) throws SQLException { 330 createStatement(); 331 logger.log(LogLevel.FINER, Resources.STR_LOG_OBJECT_NULL_PARAMETER, index); 332 try { 333 if (targetSqlType == DataType.DECIMAL || targetSqlType == DataType.NUMERIC) { 334 BigDecimal bigDecimal; 335 if (AnyConverter.isDouble(x)) { 336 bigDecimal = new BigDecimal(AnyConverter.toDouble(x)); 337 } else { 338 ORowSetValue rowSetValue = new ORowSetValue(); 339 rowSetValue.fill(x); 340 String value = rowSetValue.toString(); 341 if (value.isEmpty()) { 342 bigDecimal = new BigDecimal(0.0); 343 } else { 344 bigDecimal = new BigDecimal(value); 345 } 346 } 347 ((java.sql.PreparedStatement)jdbcStatement).setObject(index, bigDecimal, targetSqlType, scale); 348 } else { 349 ((java.sql.PreparedStatement)jdbcStatement).setObject(index, AnyConverter.toString(x), targetSqlType, scale); 350 } 351 } catch (java.sql.SQLException | IllegalArgumentException exception) { 352 throw Tools.toUnoExceptionLogged(this, logger, exception); 353 } 354 } 355 356 @Override setRef(int index, XRef x)357 public void setRef(int index, XRef x) throws SQLException { 358 String error = SharedResources.getInstance().getResourceStringWithSubstitution( 359 Resources.STR_UNSUPPORTED_FEATURE, "$featurename$", "XParameters::setRef"); 360 throw new SQLException(error, this, StandardSQLState.SQL_FEATURE_NOT_IMPLEMENTED.text(), 0, Any.VOID); 361 } 362 363 @Override setShort(int index, short x)364 public synchronized void setShort(int index, short x) throws SQLException { 365 createStatement(); 366 logger.log(LogLevel.FINE, Resources.STR_LOG_SHORT_PARAMETER, index, x); 367 try { 368 ((java.sql.PreparedStatement)jdbcStatement).setShort(index, x); 369 } catch (java.sql.SQLException sqlException) { 370 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 371 } 372 } 373 374 @Override setString(int index, String x)375 public synchronized void setString(int index, String x) throws SQLException { 376 createStatement(); 377 logger.log(LogLevel.FINE, Resources.STR_LOG_STRING_PARAMETER, index, x); 378 try { 379 ((java.sql.PreparedStatement)jdbcStatement).setString(index, x); 380 } catch (java.sql.SQLException sqlException) { 381 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 382 } 383 } 384 385 @Override setTime(int index, Time x)386 public synchronized void setTime(int index, Time x) throws SQLException { 387 createStatement(); 388 logger.log(LogLevel.FINE, Resources.STR_LOG_TIME_PARAMETER, index, x); 389 try { 390 ((java.sql.PreparedStatement)jdbcStatement).setTime( 391 index, java.sql.Time.valueOf(DBTypeConversion.toTimeString(x))); 392 } catch (java.sql.SQLException sqlException) { 393 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 394 } 395 } 396 397 @Override setTimestamp(int index, DateTime x)398 public synchronized void setTimestamp(int index, DateTime x) throws SQLException { 399 createStatement(); 400 logger.log(LogLevel.FINE, Resources.STR_LOG_TIMESTAMP_PARAMETER, index, x); 401 try { 402 ((java.sql.PreparedStatement)jdbcStatement).setTimestamp( 403 index, java.sql.Timestamp.valueOf(DBTypeConversion.toDateTimeString(x))); 404 } catch (java.sql.SQLException sqlException) { 405 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 406 } 407 } 408 409 @Override clearParameters()410 public synchronized void clearParameters() throws SQLException { 411 createStatement(); 412 logger.log(LogLevel.FINE, Resources.STR_LOG_CLEAR_PARAMETERS); 413 try { 414 ((java.sql.PreparedStatement)jdbcStatement).clearParameters(); 415 } catch (java.sql.SQLException sqlException) { 416 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 417 } 418 } 419 420 // XPreparedBatchExecution 421 422 @Override clearBatch()423 public synchronized void clearBatch() throws SQLException { 424 createStatement(); 425 try { 426 ((java.sql.PreparedStatement)jdbcStatement).clearBatch(); 427 } catch (java.sql.SQLException sqlException) { 428 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 429 } 430 } 431 432 @Override addBatch()433 public synchronized void addBatch() throws SQLException { 434 createStatement(); 435 try { 436 ((java.sql.PreparedStatement)jdbcStatement).addBatch(); 437 } catch (java.sql.SQLException sqlException) { 438 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 439 } 440 } 441 442 @Override executeBatch()443 public synchronized int[] executeBatch() throws SQLException { 444 createStatement(); 445 try { 446 return ((java.sql.PreparedStatement)jdbcStatement).executeBatch(); 447 } catch (java.sql.SQLException sqlException) { 448 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 449 } 450 } 451 452 // XResultSetMetaDataSupplier 453 454 @Override getMetaData()455 public synchronized XResultSetMetaData getMetaData() throws SQLException { 456 createStatement(); 457 try { 458 java.sql.ResultSetMetaData jdbcMetadata = ((java.sql.PreparedStatement)jdbcStatement).getMetaData(); 459 if (jdbcMetadata != null) { 460 return new JavaSQLResultSetMetaData(connection, jdbcMetadata); 461 } else { 462 return null; 463 } 464 } catch (java.sql.SQLException sqlException) { 465 throw Tools.toUnoExceptionLogged(this, logger, sqlException); 466 } 467 } 468 } 469