1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include "Connection.hxx" 21 #include "PreparedStatement.hxx" 22 #include "ResultSet.hxx" 23 #include "ResultSetMetaData.hxx" 24 #include "Util.hxx" 25 26 #include <comphelper/sequence.hxx> 27 #include <connectivity/dbexception.hxx> 28 #include <cppuhelper/typeprovider.hxx> 29 #include <osl/diagnose.h> 30 #include <propertyids.hxx> 31 #include <time.h> 32 #include <connectivity/dbtools.hxx> 33 34 #include <com/sun/star/sdbc/DataType.hpp> 35 #include <com/sun/star/lang/DisposedException.hpp> 36 37 using namespace connectivity::firebird; 38 39 using namespace ::comphelper; 40 using namespace ::osl; 41 42 using namespace com::sun::star; 43 using namespace com::sun::star::uno; 44 using namespace com::sun::star::lang; 45 using namespace com::sun::star::beans; 46 using namespace com::sun::star::sdbc; 47 using namespace com::sun::star::container; 48 using namespace com::sun::star::io; 49 using namespace com::sun::star::util; 50 51 IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.firebird.PreparedStatement","com.sun.star.sdbc.PreparedStatement"); 52 53 54 OPreparedStatement::OPreparedStatement( Connection* _pConnection, 55 const OUString& sql) 56 :OStatementCommonBase(_pConnection) 57 ,m_sSqlStatement(sql) 58 ,m_pOutSqlda(nullptr) 59 ,m_pInSqlda(nullptr) 60 ,m_sTableName() 61 { 62 SAL_INFO("connectivity.firebird", "OPreparedStatement(). " 63 "sql: " << sql); 64 } 65 66 void OPreparedStatement::ensurePrepared() 67 throw (SQLException, RuntimeException) 68 { 69 MutexGuard aGuard(m_aMutex); 70 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 71 72 if (m_aStatementHandle) 73 return; 74 75 ISC_STATUS aErr = 0; 76 77 if (!m_pInSqlda) 78 { 79 m_pInSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(10))); 80 m_pInSqlda->version = SQLDA_VERSION1; 81 m_pInSqlda->sqln = 10; 82 } 83 84 prepareAndDescribeStatement(m_sSqlStatement, 85 m_pOutSqlda, 86 m_pInSqlda); 87 88 OStringVector vec; 89 tokenizeSQL( OUStringToOString(m_sSqlStatement, RTL_TEXTENCODING_UTF8), vec ); 90 m_sTableName = 91 OStringToOUString( 92 extractSingleTableFromSelect( vec ), RTL_TEXTENCODING_UTF8); 93 94 aErr = isc_dsql_describe_bind(m_statusVector, 95 &m_aStatementHandle, 96 1, 97 m_pInSqlda); 98 99 if (aErr) 100 { 101 SAL_WARN("connectivity.firebird", "isc_dsql_describe_bind failed"); 102 } 103 else if (m_pInSqlda->sqld > m_pInSqlda->sqln) // Not large enough 104 { 105 short nItems = m_pInSqlda->sqld; 106 free(m_pInSqlda); 107 m_pInSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(nItems))); 108 m_pInSqlda->version = SQLDA_VERSION1; 109 m_pInSqlda->sqln = nItems; 110 aErr = isc_dsql_describe_bind(m_statusVector, 111 &m_aStatementHandle, 112 1, 113 m_pInSqlda); 114 SAL_WARN_IF(aErr, "connectivity.firebird", "isc_dsql_describe_bind failed"); 115 } 116 117 if (!aErr) 118 mallocSQLVAR(m_pInSqlda); 119 else 120 evaluateStatusVector(m_statusVector, m_sSqlStatement, *this); 121 } 122 123 OPreparedStatement::~OPreparedStatement() 124 { 125 } 126 127 void SAL_CALL OPreparedStatement::acquire() throw() 128 { 129 OStatementCommonBase::acquire(); 130 } 131 132 void SAL_CALL OPreparedStatement::release() throw() 133 { 134 OStatementCommonBase::release(); 135 } 136 137 Any SAL_CALL OPreparedStatement::queryInterface(const Type& rType) 138 throw(RuntimeException, std::exception) 139 { 140 Any aRet = OStatementCommonBase::queryInterface(rType); 141 if(!aRet.hasValue()) 142 aRet = OPreparedStatement_Base::queryInterface(rType); 143 return aRet; 144 } 145 146 uno::Sequence< Type > SAL_CALL OPreparedStatement::getTypes() 147 throw(RuntimeException, std::exception) 148 { 149 return concatSequences(OPreparedStatement_Base::getTypes(), 150 OStatementCommonBase::getTypes()); 151 } 152 153 Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData() 154 throw(SQLException, RuntimeException, std::exception) 155 { 156 ::osl::MutexGuard aGuard( m_aMutex ); 157 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 158 ensurePrepared(); 159 160 if(!m_xMetaData.is()) 161 m_xMetaData = new OResultSetMetaData(m_pConnection.get() 162 , m_pOutSqlda 163 , m_sTableName); 164 165 return m_xMetaData; 166 } 167 168 void SAL_CALL OPreparedStatement::close() throw(SQLException, RuntimeException, std::exception) 169 { 170 MutexGuard aGuard( m_aMutex ); 171 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 172 173 OStatementCommonBase::close(); 174 if (m_pInSqlda) 175 { 176 freeSQLVAR(m_pInSqlda); 177 free(m_pInSqlda); 178 m_pInSqlda = nullptr; 179 } 180 if (m_pOutSqlda) 181 { 182 freeSQLVAR(m_pOutSqlda); 183 free(m_pOutSqlda); 184 m_pOutSqlda = nullptr; 185 } 186 } 187 188 void SAL_CALL OPreparedStatement::disposing() 189 { 190 close(); 191 } 192 193 void SAL_CALL OPreparedStatement::setString(sal_Int32 nParameterIndex, 194 const OUString& x) 195 throw(SQLException, RuntimeException, std::exception) 196 { 197 SAL_INFO("connectivity.firebird", 198 "setString(" << nParameterIndex << " , " << x << ")"); 199 200 MutexGuard aGuard( m_aMutex ); 201 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 202 ensurePrepared(); 203 204 checkParameterIndex(nParameterIndex); 205 setParameterNull(nParameterIndex, false); 206 207 OString str = OUStringToOString(x , RTL_TEXTENCODING_UTF8 ); 208 209 XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1); 210 211 int dtype = (pVar->sqltype & ~1); // drop flag bit for now 212 213 if (str.getLength() > pVar->sqllen) 214 str = str.copy(0, pVar->sqllen); 215 216 switch (dtype) { 217 case SQL_VARYING: 218 { 219 const sal_Int32 max_varchar_len = 0xFFFF; 220 // First 2 bytes indicate string size 221 if (str.getLength() > max_varchar_len) 222 { 223 str = str.copy(0, max_varchar_len); 224 } 225 const short nLength = str.getLength(); 226 memcpy(pVar->sqldata, &nLength, 2); 227 // Actual data 228 memcpy(pVar->sqldata + 2, str.getStr(), str.getLength()); 229 break; 230 } 231 case SQL_TEXT: 232 memcpy(pVar->sqldata, str.getStr(), str.getLength()); 233 // Fill remainder with spaces 234 memset(pVar->sqldata + str.getLength(), ' ', pVar->sqllen - str.getLength()); 235 break; 236 default: 237 ::dbtools::throwSQLException( 238 "Incorrect type for setString", 239 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, 240 *this); 241 } 242 } 243 244 Reference< XConnection > SAL_CALL OPreparedStatement::getConnection() 245 throw(SQLException, RuntimeException, std::exception) 246 { 247 MutexGuard aGuard( m_aMutex ); 248 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 249 250 return Reference<XConnection>(m_pConnection.get()); 251 } 252 253 sal_Bool SAL_CALL OPreparedStatement::execute() 254 throw(SQLException, RuntimeException, std::exception) 255 { 256 SAL_INFO("connectivity.firebird", "executeQuery(). " 257 "Got called with sql: " << m_sSqlStatement); 258 259 MutexGuard aGuard( m_aMutex ); 260 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 261 262 ensurePrepared(); 263 264 ISC_STATUS aErr; 265 266 if (m_xResultSet.is()) // Checks whether we have already run the statement. 267 { 268 disposeResultSet(); 269 // Closes the cursor from the last run. 270 // This doesn't actually free the statement -- using DSQL_close closes 271 // the cursor and keeps the statement, using DSQL_drop frees the statement 272 // (and associated cursors). 273 aErr = isc_dsql_free_statement(m_statusVector, 274 &m_aStatementHandle, 275 DSQL_close); 276 if (aErr) 277 evaluateStatusVector(m_statusVector, 278 "isc_dsql_free_statement: close cursor", 279 *this); 280 } 281 282 aErr = isc_dsql_execute(m_statusVector, 283 &m_pConnection->getTransaction(), 284 &m_aStatementHandle, 285 1, 286 m_pInSqlda); 287 if (aErr) 288 { 289 SAL_WARN("connectivity.firebird", "isc_dsql_execute failed" ); 290 evaluateStatusVector(m_statusVector, "isc_dsql_execute", *this); 291 } 292 293 m_xResultSet = new OResultSet(m_pConnection.get(), 294 m_aMutex, 295 uno::Reference< XInterface >(*this), 296 m_aStatementHandle, 297 m_pOutSqlda, 298 m_sTableName); 299 300 if (getStatementChangeCount() > 0) 301 m_pConnection->notifyDatabaseModified(); 302 303 return m_xResultSet.is(); 304 // TODO: implement handling of multiple ResultSets. 305 } 306 307 sal_Int32 SAL_CALL OPreparedStatement::executeUpdate() 308 throw(SQLException, RuntimeException, std::exception) 309 { 310 execute(); 311 return getStatementChangeCount(); 312 } 313 314 Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery() 315 throw(SQLException, RuntimeException, std::exception) 316 { 317 execute(); 318 return m_xResultSet; 319 } 320 321 namespace { 322 323 /** 324 * Take out the number part of a fix point decimal without 325 * the information of where is the fracional part from a 326 * string representation of a number. (e.g. 54.654 -> 54654) 327 */ 328 sal_Int64 toNumericWithoutDecimalPlace(const OUString& sSource) 329 { 330 OUString sNumber(sSource); 331 332 // cut off leading 0 eventually ( eg. 0.567 -> .567) 333 (void)sSource.startsWith("0", &sNumber); 334 335 sal_Int32 nDotIndex = sNumber.indexOf((sal_Unicode)'.'); 336 337 if( nDotIndex < 0) 338 { 339 return sNumber.toInt64(); // no dot -> it's an integer 340 } 341 else 342 { 343 // remove dot 344 OUStringBuffer sBuffer(15); 345 if(nDotIndex > 0) 346 { 347 sBuffer.append(sNumber.copy(0, nDotIndex)); 348 } 349 sBuffer.append(sNumber.copy(nDotIndex + 1)); 350 return sBuffer.makeStringAndClear().toInt64(); 351 } 352 } 353 354 } 355 356 //----- XParameters ----------------------------------------------------------- 357 void SAL_CALL OPreparedStatement::setNull(sal_Int32 nIndex, sal_Int32 /*nSqlType*/) 358 throw(SQLException, RuntimeException, std::exception) 359 { 360 MutexGuard aGuard( m_aMutex ); 361 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 362 ensurePrepared(); 363 364 setParameterNull(nIndex); 365 } 366 367 void SAL_CALL OPreparedStatement::setBoolean(sal_Int32 /*nIndex*/, sal_Bool /*bValue*/) 368 throw(SQLException, RuntimeException, std::exception) 369 { 370 // FIREBIRD3: will need to be implemented. 371 ::dbtools::throwFunctionNotSupportedSQLException("XParameters::setBoolean", *this); 372 } 373 374 template <typename T> 375 void OPreparedStatement::setValue(sal_Int32 nIndex, T& nValue, ISC_SHORT nType) 376 throw(SQLException, RuntimeException) 377 { 378 MutexGuard aGuard( m_aMutex ); 379 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 380 ensurePrepared(); 381 382 checkParameterIndex(nIndex); 383 setParameterNull(nIndex, false); 384 385 XSQLVAR* pVar = m_pInSqlda->sqlvar + (nIndex - 1); 386 387 if ((pVar->sqltype & ~1) != nType) 388 { 389 ::dbtools::throwSQLException( 390 "Incorrect type for setString", 391 ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, 392 *this); 393 } 394 395 memcpy(pVar->sqldata, &nValue, sizeof(nValue)); 396 } 397 398 void SAL_CALL OPreparedStatement::setByte(sal_Int32 /*nIndex*/, sal_Int8 /*nValue*/) 399 throw(SQLException, RuntimeException, std::exception) 400 { 401 ::dbtools::throwFunctionNotSupportedSQLException("XParameters::setByte", *this); 402 } 403 404 void SAL_CALL OPreparedStatement::setShort(sal_Int32 nIndex, sal_Int16 nValue) 405 throw(SQLException, RuntimeException, std::exception) 406 { 407 setValue< sal_Int16 >(nIndex, nValue, SQL_SHORT); 408 } 409 410 void SAL_CALL OPreparedStatement::setInt(sal_Int32 nIndex, sal_Int32 nValue) 411 throw(SQLException, RuntimeException, std::exception) 412 { 413 setValue< sal_Int32 >(nIndex, nValue, SQL_LONG); 414 } 415 416 void SAL_CALL OPreparedStatement::setLong(sal_Int32 nIndex, sal_Int64 nValue) 417 throw(SQLException, RuntimeException, std::exception) 418 { 419 setValue< sal_Int64 >(nIndex, nValue, SQL_INT64); 420 } 421 422 void SAL_CALL OPreparedStatement::setFloat(sal_Int32 nIndex, float nValue) 423 throw(SQLException, RuntimeException, std::exception) 424 { 425 setValue< float >(nIndex, nValue, SQL_FLOAT); 426 } 427 428 void SAL_CALL OPreparedStatement::setDouble(sal_Int32 nIndex, double nValue) 429 throw(SQLException, RuntimeException, std::exception) 430 { 431 setValue< double >(nIndex, nValue, SQL_DOUBLE); // TODO: SQL_D_FLOAT? 432 } 433 434 void SAL_CALL OPreparedStatement::setDate(sal_Int32 nIndex, const Date& rDate) 435 throw(SQLException, RuntimeException, std::exception) 436 { 437 struct tm aCTime; 438 aCTime.tm_mday = rDate.Day; 439 aCTime.tm_mon = rDate.Month -1; 440 aCTime.tm_year = rDate.Year -1900; 441 442 ISC_DATE aISCDate; 443 isc_encode_sql_date(&aCTime, &aISCDate); 444 445 setValue< ISC_DATE >(nIndex, aISCDate, SQL_TYPE_DATE); 446 } 447 448 void SAL_CALL OPreparedStatement::setTime( sal_Int32 nIndex, const css::util::Time& rTime) 449 throw(SQLException, RuntimeException, std::exception) 450 { 451 struct tm aCTime; 452 aCTime.tm_sec = rTime.Seconds; 453 aCTime.tm_min = rTime.Minutes; 454 aCTime.tm_hour = rTime.Hours; 455 456 ISC_TIME aISCTime; 457 isc_encode_sql_time(&aCTime, &aISCTime); 458 459 setValue< ISC_TIME >(nIndex, aISCTime, SQL_TYPE_TIME); 460 } 461 462 void SAL_CALL OPreparedStatement::setTimestamp(sal_Int32 nIndex, const DateTime& rTimestamp) 463 throw(SQLException, RuntimeException, std::exception) 464 { 465 struct tm aCTime; 466 aCTime.tm_sec = rTimestamp.Seconds; 467 aCTime.tm_min = rTimestamp.Minutes; 468 aCTime.tm_hour = rTimestamp.Hours; 469 aCTime.tm_mday = rTimestamp.Day; 470 aCTime.tm_mon = rTimestamp.Month - 1; 471 aCTime.tm_year = rTimestamp.Year - 1900; 472 473 ISC_TIMESTAMP aISCTimestamp; 474 isc_encode_timestamp(&aCTime, &aISCTimestamp); 475 476 setValue< ISC_TIMESTAMP >(nIndex, aISCTimestamp, SQL_TIMESTAMP); 477 } 478 479 480 // void OPreaparedStatement::set 481 void OPreparedStatement::openBlobForWriting(isc_blob_handle& rBlobHandle, ISC_QUAD& rBlobId) 482 { 483 ISC_STATUS aErr; 484 485 aErr = isc_create_blob2(m_statusVector, 486 &m_pConnection->getDBHandle(), 487 &m_pConnection->getTransaction(), 488 &rBlobHandle, 489 &rBlobId, 490 0, // Blob parameter buffer length 491 nullptr); // Blob parameter buffer handle 492 493 if (aErr) 494 { 495 evaluateStatusVector(m_statusVector, 496 "setBlob failed on " + m_sSqlStatement, 497 *this); 498 assert(false); 499 } 500 } 501 502 void OPreparedStatement::closeBlobAfterWriting(isc_blob_handle& rBlobHandle) 503 { 504 ISC_STATUS aErr; 505 506 aErr = isc_close_blob(m_statusVector, 507 &rBlobHandle); 508 if (aErr) 509 { 510 evaluateStatusVector(m_statusVector, 511 "isc_close_blob failed", 512 *this); 513 assert(false); 514 } 515 } 516 517 void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x ) throw(SQLException, RuntimeException, std::exception) 518 { 519 (void) parameterIndex; 520 (void) x; 521 ::osl::MutexGuard aGuard( m_aMutex ); 522 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 523 524 } 525 526 void SAL_CALL OPreparedStatement::setBlob(sal_Int32 nParameterIndex, 527 const Reference< XBlob >& xBlob) 528 throw (SQLException, RuntimeException, std::exception) 529 { 530 ::osl::MutexGuard aGuard(m_aMutex); 531 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 532 533 #if SAL_TYPES_SIZEOFPOINTER == 8 534 isc_blob_handle aBlobHandle = 0; 535 #else 536 isc_blob_handle aBlobHandle = nullptr; 537 #endif 538 ISC_QUAD aBlobId; 539 540 openBlobForWriting(aBlobHandle, aBlobId); 541 542 // Max segment size is 2^16 == SAL_MAX_UINT16 543 // LEM TODO: SAL_MAX_UINT16 is 2^16-1; this mixup is probably innocuous; to be checked 544 sal_uInt64 nDataWritten = 0; 545 ISC_STATUS aErr = 0; 546 while (xBlob->length() - nDataWritten > 0) 547 { 548 sal_uInt64 nDataRemaining = xBlob->length() - nDataWritten; 549 sal_uInt16 nWriteSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining; 550 aErr = isc_put_segment(m_statusVector, 551 &aBlobHandle, 552 nWriteSize, 553 reinterpret_cast<const char*>(xBlob->getBytes(nDataWritten, nWriteSize).getConstArray())); 554 nDataWritten += nWriteSize; 555 556 557 if (aErr) 558 break; 559 560 } 561 562 // We need to make sure we close the Blob even if their are errors, hence evaluate 563 // errors after closing. 564 closeBlobAfterWriting(aBlobHandle); 565 566 if (aErr) 567 { 568 evaluateStatusVector(m_statusVector, 569 "isc_put_segment failed", 570 *this); 571 assert(false); 572 } 573 574 setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB); 575 } 576 577 578 void SAL_CALL OPreparedStatement::setArray( sal_Int32 parameterIndex, const Reference< XArray >& x ) throw(SQLException, RuntimeException, std::exception) 579 { 580 (void) parameterIndex; 581 (void) x; 582 ::osl::MutexGuard aGuard( m_aMutex ); 583 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 584 585 } 586 587 588 void SAL_CALL OPreparedStatement::setRef( sal_Int32 parameterIndex, const Reference< XRef >& x ) throw(SQLException, RuntimeException, std::exception) 589 { 590 (void) parameterIndex; 591 (void) x; 592 ::osl::MutexGuard aGuard( m_aMutex ); 593 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 594 595 } 596 597 598 void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) throw(SQLException, RuntimeException, std::exception) 599 { 600 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 601 ::osl::MutexGuard aGuard( m_aMutex ); 602 603 XSQLVAR* pVar = m_pInSqlda->sqlvar + (parameterIndex - 1); 604 int dType = (pVar->sqltype & ~1); // drop null flag 605 606 if(sqlType == DataType::DECIMAL || sqlType == DataType::NUMERIC) 607 { 608 double myDouble=0.0; 609 OUString myString; 610 if( x >>= myDouble ) 611 { 612 myString = OUString::number( myDouble ); 613 } 614 else 615 { 616 x >>= myString; 617 } 618 619 // fill in the number with nulls in fractional part. 620 // We need this because e.g. 0.450 != 0.045 despite 621 // their scale is equal 622 OUStringBuffer sBuffer(15); 623 sBuffer.append(myString); 624 if(myString.indexOf('.') != -1) // there is a dot 625 { 626 for(sal_Int32 i=myString.copy(myString.indexOf('.')+1).getLength(); i<scale;i++) 627 { 628 sBuffer.append('0'); 629 } 630 } 631 else 632 { 633 for (sal_Int32 i=0; i<scale; i++) 634 { 635 sBuffer.append('0'); 636 } 637 } 638 myString = sBuffer.makeStringAndClear(); 639 // set value depending on type 640 sal_Int16 n16Value = 0; 641 sal_Int32 n32Value = 0; 642 sal_Int64 n64Value = 0; 643 switch(dType) 644 { 645 case SQL_SHORT: 646 n16Value = (sal_Int16) toNumericWithoutDecimalPlace(myString); 647 setValue< sal_Int16 >(parameterIndex, 648 n16Value, 649 dType); 650 break; 651 case SQL_LONG: 652 case SQL_DOUBLE: // TODO FIXME 32 bits 653 n32Value = (sal_Int32) toNumericWithoutDecimalPlace(myString); 654 setValue< sal_Int32 >(parameterIndex, 655 n32Value, 656 dType); 657 break; 658 case SQL_INT64: 659 n64Value = (sal_Int64) toNumericWithoutDecimalPlace(myString); 660 setValue< sal_Int64 >(parameterIndex, 661 n64Value, 662 dType); 663 break; 664 default: 665 SAL_WARN("connectivity.firebird", 666 "No Firebird sql type found for numeric or decimal types"); 667 ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); 668 } 669 } 670 else 671 { 672 ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); 673 } 674 675 } 676 677 678 void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const ::rtl::OUString& typeName ) throw(SQLException, RuntimeException, std::exception) 679 { 680 (void) parameterIndex; 681 (void) sqlType; 682 (void) typeName; 683 ::osl::MutexGuard aGuard( m_aMutex ); 684 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 685 686 } 687 688 689 void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) throw(SQLException, RuntimeException, std::exception) 690 { 691 (void) parameterIndex; 692 (void) x; 693 ::osl::MutexGuard aGuard( m_aMutex ); 694 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 695 696 } 697 698 void SAL_CALL OPreparedStatement::setBytes(sal_Int32 nParameterIndex, 699 const Sequence< sal_Int8 >& xBytes) 700 throw (SQLException, RuntimeException, std::exception) 701 { 702 ::osl::MutexGuard aGuard(m_aMutex); 703 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 704 705 #if SAL_TYPES_SIZEOFPOINTER == 8 706 isc_blob_handle aBlobHandle = 0; 707 #else 708 isc_blob_handle aBlobHandle = nullptr; 709 #endif 710 ISC_QUAD aBlobId; 711 712 openBlobForWriting(aBlobHandle, aBlobId); 713 714 // Max segment size is 2^16 == SAL_MAX_UINT16 715 sal_uInt64 nDataWritten = 0; 716 ISC_STATUS aErr = 0; 717 while (xBytes.getLength() - nDataWritten > 0) 718 { 719 sal_uInt64 nDataRemaining = xBytes.getLength() - nDataWritten; 720 sal_uInt16 nWriteSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining; 721 aErr = isc_put_segment(m_statusVector, 722 &aBlobHandle, 723 nWriteSize, 724 reinterpret_cast<const char*>(xBytes.getConstArray()) + nDataWritten); 725 nDataWritten += nWriteSize; 726 727 if (aErr) 728 break; 729 } 730 731 // We need to make sure we close the Blob even if their are errors, hence evaluate 732 // errors after closing. 733 closeBlobAfterWriting(aBlobHandle); 734 735 if (aErr) 736 { 737 evaluateStatusVector(m_statusVector, 738 "isc_put_segment failed", 739 *this); 740 assert(false); 741 } 742 743 setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB); 744 } 745 746 747 void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException, std::exception) 748 { 749 (void) parameterIndex; 750 (void) x; 751 (void) length; 752 ::osl::MutexGuard aGuard( m_aMutex ); 753 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 754 755 } 756 757 758 void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException, std::exception) 759 { 760 (void) parameterIndex; 761 (void) x; 762 (void) length; 763 ::osl::MutexGuard aGuard( m_aMutex ); 764 checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); 765 766 } 767 768 769 void SAL_CALL OPreparedStatement::clearParameters( ) throw(SQLException, RuntimeException, std::exception) 770 { 771 } 772 773 // ---- Batch methods -- unsupported ----------------------------------------- 774 void SAL_CALL OPreparedStatement::clearBatch() 775 throw(SQLException, RuntimeException, std::exception) 776 { 777 // Unsupported 778 } 779 780 void SAL_CALL OPreparedStatement::addBatch() 781 throw(SQLException, RuntimeException, std::exception) 782 { 783 // Unsupported by firebird 784 } 785 786 Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch() 787 throw(SQLException, RuntimeException, std::exception) 788 { 789 // Unsupported by firebird 790 return Sequence< sal_Int32 >(); 791 } 792 793 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) throw (Exception, std::exception) 794 { 795 switch(nHandle) 796 { 797 case PROPERTY_ID_RESULTSETCONCURRENCY: 798 break; 799 case PROPERTY_ID_RESULTSETTYPE: 800 break; 801 case PROPERTY_ID_FETCHDIRECTION: 802 break; 803 case PROPERTY_ID_USEBOOKMARKS: 804 break; 805 default: 806 OStatementCommonBase::setFastPropertyValue_NoBroadcast(nHandle,rValue); 807 } 808 } 809 810 void OPreparedStatement::checkParameterIndex(sal_Int32 nParameterIndex) 811 throw(SQLException, RuntimeException) 812 { 813 ensurePrepared(); 814 if ((nParameterIndex == 0) || (nParameterIndex > m_pInSqlda->sqld)) 815 { 816 ::dbtools::throwSQLException( 817 "No column " + OUString::number(nParameterIndex), 818 ::dbtools::StandardSQLState::COLUMN_NOT_FOUND, 819 *this); 820 } 821 } 822 823 void OPreparedStatement::setParameterNull(sal_Int32 nParameterIndex, 824 bool bSetNull) 825 { 826 XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1); 827 if (bSetNull) 828 { 829 pVar->sqltype |= 1; 830 *pVar->sqlind = -1; 831 } 832 else 833 *pVar->sqlind = 0; 834 } 835 836 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 837
