mozStorageBindingParams.cpp (18714B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <limits.h> 8 9 #include "mozilla/UniquePtrExtensions.h" 10 #include "nsString.h" 11 12 #include "mozStorageError.h" 13 #include "mozStoragePrivateHelpers.h" 14 #include "mozStorageBindingParams.h" 15 #include "Variant.h" 16 #include "sqlite3_static_ext.h" 17 18 namespace mozilla::storage { 19 20 //////////////////////////////////////////////////////////////////////////////// 21 //// Local Helper Objects 22 23 namespace { 24 25 struct BindingColumnData { 26 BindingColumnData(sqlite3_stmt* aStmt, int aColumn) 27 : stmt(aStmt), column(aColumn) {} 28 sqlite3_stmt* stmt; 29 int column; 30 }; 31 32 //////////////////////////////////////////////////////////////////////////////// 33 //// Variant Specialization Functions (variantToSQLiteT) 34 35 int sqlite3_T_int(BindingColumnData aData, int aValue) { 36 return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue); 37 } 38 39 int sqlite3_T_int64(BindingColumnData aData, sqlite3_int64 aValue) { 40 return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue); 41 } 42 43 int sqlite3_T_double(BindingColumnData aData, double aValue) { 44 return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue); 45 } 46 47 int sqlite3_T_text(BindingColumnData aData, const nsCString& aValue) { 48 return ::sqlite3_bind_text(aData.stmt, aData.column + 1, aValue.get(), 49 aValue.Length(), SQLITE_TRANSIENT); 50 } 51 52 int sqlite3_T_text16(BindingColumnData aData, const nsString& aValue) { 53 return ::sqlite3_bind_text16( 54 aData.stmt, aData.column + 1, aValue.get(), 55 aValue.Length() * sizeof(char16_t), // Length in bytes! 56 SQLITE_TRANSIENT); 57 } 58 59 int sqlite3_T_null(BindingColumnData aData) { 60 return ::sqlite3_bind_null(aData.stmt, aData.column + 1); 61 } 62 63 int sqlite3_T_blob(BindingColumnData aData, const void* aBlob, int aSize) { 64 return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize, free); 65 } 66 67 int sqlite3_T_array(BindingColumnData aData, void* aArray, int aSize, 68 int aType) { 69 // In debug builds ensure that the statement includes at least one `carray()`. 70 MOZ_ASSERT( 71 ::strstr(::sqlite3_sql(aData.stmt), "carray("), 72 "Binding arrays to SQL statements requires using the carray() function."); 73 74 if (aType == CARRAY_TEXT) { 75 // We don't manage the string buffers lifecycle, thus let SQLite make its 76 // own copy. 77 int srv = ::sqlite3_carray_bind(aData.stmt, aData.column + 1, aArray, aSize, 78 aType, SQLITE_TRANSIENT); 79 free(aArray); 80 return srv; 81 } 82 return ::sqlite3_carray_bind(aData.stmt, aData.column + 1, aArray, aSize, 83 aType, free); 84 } 85 86 #include "variantToSQLiteT_impl.h" 87 88 } // namespace 89 90 //////////////////////////////////////////////////////////////////////////////// 91 //// BindingParams 92 93 BindingParams::BindingParams(mozIStorageBindingParamsArray* aOwningArray, 94 Statement* aOwningStatement) 95 : mLocked(false), 96 mOwningArray(aOwningArray), 97 mOwningStatement(aOwningStatement), 98 mParamCount(0) { 99 (void)mOwningStatement->GetParameterCount(&mParamCount); 100 mParameters.SetCapacity(mParamCount); 101 } 102 103 BindingParams::BindingParams(mozIStorageBindingParamsArray* aOwningArray) 104 : mLocked(false), 105 mOwningArray(aOwningArray), 106 mOwningStatement(nullptr), 107 mParamCount(0) {} 108 109 AsyncBindingParams::AsyncBindingParams( 110 mozIStorageBindingParamsArray* aOwningArray) 111 : BindingParams(aOwningArray) {} 112 113 void BindingParams::lock() { 114 NS_ASSERTION(mLocked == false, "Parameters have already been locked!"); 115 mLocked = true; 116 117 // We no longer need to hold a reference to our statement or our owning array. 118 // The array owns us at this point, and it will own a reference to the 119 // statement. 120 mOwningStatement = nullptr; 121 mOwningArray = nullptr; 122 } 123 124 void BindingParams::unlock(Statement* aOwningStatement) { 125 NS_ASSERTION(mLocked == true, "Parameters were not yet locked!"); 126 mLocked = false; 127 mOwningStatement = aOwningStatement; 128 } 129 130 const mozIStorageBindingParamsArray* BindingParams::getOwner() const { 131 return mOwningArray; 132 } 133 134 //////////////////////////////////////////////////////////////////////////////// 135 //// nsISupports 136 137 NS_IMPL_ISUPPORTS(BindingParams, mozIStorageBindingParams, 138 IStorageBindingParamsInternal) 139 140 //////////////////////////////////////////////////////////////////////////////// 141 //// IStorageBindingParamsInternal 142 143 already_AddRefed<mozIStorageError> BindingParams::bind( 144 sqlite3_stmt* aStatement) { 145 // Iterate through all of our stored data, and bind it. 146 for (size_t i = 0; i < mParameters.Length(); i++) { 147 int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]); 148 if (rc != SQLITE_OK) { 149 // We had an error while trying to bind. Now we need to create an error 150 // object with the right message. Note that we special case 151 // SQLITE_MISMATCH, but otherwise get the message from SQLite. 152 const char* msg = "Could not covert nsIVariant to SQLite type."; 153 if (rc != SQLITE_MISMATCH) { 154 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement)); 155 } 156 157 nsCOMPtr<mozIStorageError> err(new Error(rc, msg)); 158 return err.forget(); 159 } 160 } 161 162 return nullptr; 163 } 164 165 already_AddRefed<mozIStorageError> AsyncBindingParams::bind( 166 sqlite3_stmt* aStatement) { 167 nsCOMPtr<mozIStorageError> err; 168 169 for (const auto& entry : mNamedParameters) { 170 const nsACString& key = entry.GetKey(); 171 172 // We do not accept any forms of names other than ":name", but we need to 173 // add the colon for SQLite. 174 nsAutoCString name(":"); 175 name.Append(key); 176 int oneIdx = ::sqlite3_bind_parameter_index(aStatement, name.get()); 177 178 if (oneIdx == 0) { 179 nsAutoCString errMsg(key); 180 errMsg.AppendLiteral(" is not a valid named parameter."); 181 err = new Error(SQLITE_RANGE, errMsg.get()); 182 return err.forget(); 183 } 184 185 if (mParameters.Length() <= static_cast<uint32_t>(oneIdx - 1)) { 186 mParameters.SetLength(oneIdx - 1); 187 mParameters.AppendElement(entry.GetWeak()); 188 } else { 189 mParameters.ReplaceElementAt(oneIdx - 1, entry.GetWeak()); 190 } 191 } 192 193 // Now bind using the super class. 194 return BindingParams::bind(aStatement); 195 } 196 197 /////////////////////////////////////////////////////////////////////////////// 198 //// mozIStorageBindingParams 199 200 NS_IMETHODIMP 201 BindingParams::BindByName(const nsACString& aName, nsIVariant* aValue) { 202 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); 203 204 // Get the column index that we need to store this at. 205 uint32_t index; 206 nsresult rv = mOwningStatement->GetParameterIndex(aName, &index); 207 NS_ENSURE_SUCCESS(rv, rv); 208 209 return BindByIndex(index, aValue); 210 } 211 212 NS_IMETHODIMP 213 AsyncBindingParams::BindByName(const nsACString& aName, nsIVariant* aValue) { 214 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); 215 216 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue); 217 if (!variant) return NS_ERROR_UNEXPECTED; 218 mNamedParameters.InsertOrUpdate(aName, std::move(variant)); 219 return NS_OK; 220 } 221 222 NS_IMETHODIMP 223 BindingParams::BindUTF8StringByName(const nsACString& aName, 224 const nsACString& aValue) { 225 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue)); 226 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 227 228 return BindByName(aName, value); 229 } 230 231 NS_IMETHODIMP 232 BindingParams::BindStringByName(const nsACString& aName, 233 const nsAString& aValue) { 234 nsCOMPtr<nsIVariant> value(new TextVariant(aValue)); 235 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 236 237 return BindByName(aName, value); 238 } 239 240 NS_IMETHODIMP 241 BindingParams::BindDoubleByName(const nsACString& aName, double aValue) { 242 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue)); 243 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 244 245 return BindByName(aName, value); 246 } 247 248 NS_IMETHODIMP 249 BindingParams::BindInt32ByName(const nsACString& aName, int32_t aValue) { 250 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue)); 251 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 252 253 return BindByName(aName, value); 254 } 255 256 NS_IMETHODIMP 257 BindingParams::BindInt64ByName(const nsACString& aName, int64_t aValue) { 258 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue)); 259 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 260 261 return BindByName(aName, value); 262 } 263 264 NS_IMETHODIMP 265 BindingParams::BindNullByName(const nsACString& aName) { 266 nsCOMPtr<nsIVariant> value(new NullVariant()); 267 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 268 269 return BindByName(aName, value); 270 } 271 272 NS_IMETHODIMP 273 BindingParams::BindBlobByName(const nsACString& aName, const uint8_t* aValue, 274 uint32_t aValueSize) { 275 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); 276 std::pair<const void*, int> data(static_cast<const void*>(aValue), 277 int(aValueSize)); 278 nsCOMPtr<nsIVariant> value(new BlobVariant(data)); 279 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 280 281 return BindByName(aName, value); 282 } 283 284 NS_IMETHODIMP 285 BindingParams::BindBlobArrayByName(const nsACString& aName, 286 const nsTArray<uint8_t>& aValue) { 287 return BindBlobByName(aName, aValue.Elements(), aValue.Length()); 288 } 289 290 NS_IMETHODIMP 291 BindingParams::BindStringAsBlobByName(const nsACString& aName, 292 const nsAString& aValue) { 293 return DoBindStringAsBlobByName(this, aName, aValue); 294 } 295 296 NS_IMETHODIMP 297 BindingParams::BindUTF8StringAsBlobByName(const nsACString& aName, 298 const nsACString& aValue) { 299 return DoBindStringAsBlobByName(this, aName, aValue); 300 } 301 302 NS_IMETHODIMP 303 BindingParams::BindAdoptedBlobByName(const nsACString& aName, uint8_t* aValue, 304 uint32_t aValueSize) { 305 UniqueFreePtr<uint8_t> uniqueValue(aValue); 306 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); 307 std::pair<uint8_t*, int> data(uniqueValue.release(), int(aValueSize)); 308 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data)); 309 310 return BindByName(aName, value); 311 } 312 313 NS_IMETHODIMP 314 BindingParams::BindArrayOfIntegersByName(const nsACString& aName, 315 const nsTArray<int64_t>& aValue) { 316 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX); 317 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()), 318 int(aValue.Length())); 319 nsCOMPtr<nsIVariant> value(new ArrayOfIntegersVariant(data)); 320 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 321 322 return BindByName(aName, value); 323 } 324 325 NS_IMETHODIMP 326 BindingParams::BindArrayOfDoublesByName(const nsACString& aName, 327 const nsTArray<double>& aValue) { 328 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX); 329 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()), 330 int(aValue.Length())); 331 nsCOMPtr<nsIVariant> value(new ArrayOfDoublesVariant(data)); 332 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 333 334 return BindByName(aName, value); 335 } 336 337 NS_IMETHODIMP 338 BindingParams::BindArrayOfStringsByName(const nsACString& aName, 339 const nsTArray<nsString>& aValue) { 340 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX); 341 nsTArray<nsCString> UTF8Strings(aValue.Length()); 342 for (const nsString& str : aValue) { 343 UTF8Strings.AppendElement(NS_ConvertUTF16toUTF8(str)); 344 } 345 std::pair<const void*, int> data( 346 static_cast<const void*>(UTF8Strings.Elements()), 347 int(UTF8Strings.Length())); 348 // The variant will make a copy of all the buffers. 349 nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data)); 350 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 351 352 return BindByName(aName, value); 353 } 354 355 NS_IMETHODIMP 356 BindingParams::BindArrayOfUTF8StringsByName(const nsACString& aName, 357 const nsTArray<nsCString>& aValue) { 358 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX); 359 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()), 360 int(aValue.Length())); 361 // The variant will make a copy of all the buffers. 362 nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data)); 363 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 364 365 return BindByName(aName, value); 366 } 367 368 NS_IMETHODIMP 369 BindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) { 370 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); 371 ENSURE_INDEX_VALUE(aIndex, mParamCount); 372 373 // Store the variant for later use. 374 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue); 375 if (!variant) return NS_ERROR_UNEXPECTED; 376 if (mParameters.Length() <= aIndex) { 377 (void)mParameters.SetLength(aIndex); 378 (void)mParameters.AppendElement(variant); 379 } else { 380 mParameters.ReplaceElementAt(aIndex, variant); 381 } 382 return NS_OK; 383 } 384 385 NS_IMETHODIMP 386 AsyncBindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) { 387 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); 388 // In the asynchronous case we do not know how many parameters there are to 389 // bind to, so we cannot check the validity of aIndex. 390 391 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue); 392 if (!variant) return NS_ERROR_UNEXPECTED; 393 if (mParameters.Length() <= aIndex) { 394 mParameters.SetLength(aIndex); 395 mParameters.AppendElement(variant); 396 } else { 397 mParameters.ReplaceElementAt(aIndex, variant); 398 } 399 return NS_OK; 400 } 401 402 NS_IMETHODIMP 403 BindingParams::BindUTF8StringByIndex(uint32_t aIndex, 404 const nsACString& aValue) { 405 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue)); 406 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 407 408 return BindByIndex(aIndex, value); 409 } 410 411 NS_IMETHODIMP 412 BindingParams::BindStringByIndex(uint32_t aIndex, const nsAString& aValue) { 413 nsCOMPtr<nsIVariant> value(new TextVariant(aValue)); 414 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 415 416 return BindByIndex(aIndex, value); 417 } 418 419 NS_IMETHODIMP 420 BindingParams::BindDoubleByIndex(uint32_t aIndex, double aValue) { 421 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue)); 422 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 423 424 return BindByIndex(aIndex, value); 425 } 426 427 NS_IMETHODIMP 428 BindingParams::BindInt32ByIndex(uint32_t aIndex, int32_t aValue) { 429 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue)); 430 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 431 432 return BindByIndex(aIndex, value); 433 } 434 435 NS_IMETHODIMP 436 BindingParams::BindInt64ByIndex(uint32_t aIndex, int64_t aValue) { 437 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue)); 438 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 439 440 return BindByIndex(aIndex, value); 441 } 442 443 NS_IMETHODIMP 444 BindingParams::BindNullByIndex(uint32_t aIndex) { 445 nsCOMPtr<nsIVariant> value(new NullVariant()); 446 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 447 448 return BindByIndex(aIndex, value); 449 } 450 451 NS_IMETHODIMP 452 BindingParams::BindBlobByIndex(uint32_t aIndex, const uint8_t* aValue, 453 uint32_t aValueSize) { 454 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); 455 std::pair<const void*, int> data(static_cast<const void*>(aValue), 456 int(aValueSize)); 457 nsCOMPtr<nsIVariant> value(new BlobVariant(data)); 458 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 459 460 return BindByIndex(aIndex, value); 461 } 462 463 NS_IMETHODIMP 464 BindingParams::BindBlobArrayByIndex(uint32_t aIndex, 465 const nsTArray<uint8_t>& aValue) { 466 return BindBlobByIndex(aIndex, aValue.Elements(), aValue.Length()); 467 } 468 469 NS_IMETHODIMP 470 BindingParams::BindStringAsBlobByIndex(uint32_t aIndex, 471 const nsAString& aValue) { 472 return DoBindStringAsBlobByIndex(this, aIndex, aValue); 473 } 474 475 NS_IMETHODIMP 476 BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex, 477 const nsACString& aValue) { 478 return DoBindStringAsBlobByIndex(this, aIndex, aValue); 479 } 480 481 NS_IMETHODIMP 482 BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex, uint8_t* aValue, 483 uint32_t aValueSize) { 484 UniqueFreePtr<uint8_t> uniqueValue(aValue); 485 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); 486 std::pair<uint8_t*, int> data(uniqueValue.release(), int(aValueSize)); 487 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data)); 488 489 return BindByIndex(aIndex, value); 490 } 491 492 NS_IMETHODIMP 493 BindingParams::BindArrayOfIntegersByIndex(uint32_t aIndex, 494 const nsTArray<int64_t>& aValue) { 495 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX); 496 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()), 497 int(aValue.Length())); 498 nsCOMPtr<nsIVariant> value(new ArrayOfIntegersVariant(data)); 499 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 500 501 return BindByIndex(aIndex, value); 502 } 503 504 NS_IMETHODIMP 505 BindingParams::BindArrayOfDoublesByIndex(uint32_t aIndex, 506 const nsTArray<double>& aValue) { 507 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX); 508 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()), 509 int(aValue.Length())); 510 nsCOMPtr<nsIVariant> value(new ArrayOfDoublesVariant(data)); 511 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 512 513 return BindByIndex(aIndex, value); 514 } 515 516 NS_IMETHODIMP 517 BindingParams::BindArrayOfStringsByIndex(uint32_t aIndex, 518 const nsTArray<nsString>& aValue) { 519 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX); 520 nsTArray<nsCString> UTF8Strings(aValue.Length()); 521 for (const nsString& str : aValue) { 522 UTF8Strings.AppendElement(NS_ConvertUTF16toUTF8(str).get()); 523 } 524 std::pair<const void*, int> data( 525 static_cast<const void*>(UTF8Strings.Elements()), 526 int(UTF8Strings.Length())); 527 // The variant will make a copy of all the buffers. 528 nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data)); 529 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 530 531 return BindByIndex(aIndex, value); 532 } 533 534 NS_IMETHODIMP 535 BindingParams::BindArrayOfUTF8StringsByIndex( 536 uint32_t aIndex, const nsTArray<nsCString>& aValue) { 537 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX); 538 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()), 539 int(aValue.Length())); 540 // The variant will make a copy of all the buffers. 541 nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data)); 542 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); 543 544 return BindByIndex(aIndex, value); 545 } 546 547 } // namespace mozilla::storage