diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /storage/mozStorageBindingParams.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | uxp-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz |
Add m-esr52 at 52.6.0
Diffstat (limited to 'storage/mozStorageBindingParams.cpp')
-rw-r--r-- | storage/mozStorageBindingParams.cpp | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/storage/mozStorageBindingParams.cpp b/storage/mozStorageBindingParams.cpp new file mode 100644 index 0000000000..98e1144201 --- /dev/null +++ b/storage/mozStorageBindingParams.cpp @@ -0,0 +1,525 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <limits.h> + +#include "mozilla/UniquePtrExtensions.h" +#include "nsString.h" + +#include "mozStorageError.h" +#include "mozStoragePrivateHelpers.h" +#include "mozStorageBindingParams.h" +#include "mozStorageBindingParamsArray.h" +#include "Variant.h" + +namespace mozilla { +namespace storage { + +//////////////////////////////////////////////////////////////////////////////// +//// Local Helper Objects + +namespace { + +struct BindingColumnData +{ + BindingColumnData(sqlite3_stmt *aStmt, + int aColumn) + : stmt(aStmt) + , column(aColumn) + { + } + sqlite3_stmt *stmt; + int column; +}; + +//////////////////////////////////////////////////////////////////////////////// +//// Variant Specialization Functions (variantToSQLiteT) + +int +sqlite3_T_int(BindingColumnData aData, + int aValue) +{ + return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue); +} + +int +sqlite3_T_int64(BindingColumnData aData, + sqlite3_int64 aValue) +{ + return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue); +} + +int +sqlite3_T_double(BindingColumnData aData, + double aValue) +{ + return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue); +} + +int +sqlite3_T_text(BindingColumnData aData, + const nsCString& aValue) +{ + return ::sqlite3_bind_text(aData.stmt, + aData.column + 1, + aValue.get(), + aValue.Length(), + SQLITE_TRANSIENT); +} + +int +sqlite3_T_text16(BindingColumnData aData, + const nsString& aValue) +{ + return ::sqlite3_bind_text16(aData.stmt, + aData.column + 1, + aValue.get(), + aValue.Length() * 2, // Length in bytes! + SQLITE_TRANSIENT); +} + +int +sqlite3_T_null(BindingColumnData aData) +{ + return ::sqlite3_bind_null(aData.stmt, aData.column + 1); +} + +int +sqlite3_T_blob(BindingColumnData aData, + const void *aBlob, + int aSize) +{ + return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize, + free); + +} + +#include "variantToSQLiteT_impl.h" + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +//// BindingParams + +BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray, + Statement *aOwningStatement) +: mLocked(false) +, mOwningArray(aOwningArray) +, mOwningStatement(aOwningStatement) +, mParamCount(0) +{ + (void)mOwningStatement->GetParameterCount(&mParamCount); + mParameters.SetCapacity(mParamCount); +} + +BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray) +: mLocked(false) +, mOwningArray(aOwningArray) +, mOwningStatement(nullptr) +, mParamCount(0) +{ +} + +AsyncBindingParams::AsyncBindingParams( + mozIStorageBindingParamsArray *aOwningArray +) +: BindingParams(aOwningArray) +{ +} + +void +BindingParams::lock() +{ + NS_ASSERTION(mLocked == false, "Parameters have already been locked!"); + mLocked = true; + + // We no longer need to hold a reference to our statement or our owning array. + // The array owns us at this point, and it will own a reference to the + // statement. + mOwningStatement = nullptr; + mOwningArray = nullptr; +} + +void +BindingParams::unlock(Statement *aOwningStatement) +{ + NS_ASSERTION(mLocked == true, "Parameters were not yet locked!"); + mLocked = false; + mOwningStatement = aOwningStatement; +} + +const mozIStorageBindingParamsArray * +BindingParams::getOwner() const +{ + return mOwningArray; +} + +//////////////////////////////////////////////////////////////////////////////// +//// nsISupports + +NS_IMPL_ISUPPORTS( + BindingParams +, mozIStorageBindingParams +, IStorageBindingParamsInternal +) + + +//////////////////////////////////////////////////////////////////////////////// +//// IStorageBindingParamsInternal + +already_AddRefed<mozIStorageError> +BindingParams::bind(sqlite3_stmt *aStatement) +{ + // Iterate through all of our stored data, and bind it. + for (size_t i = 0; i < mParameters.Length(); i++) { + int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]); + if (rc != SQLITE_OK) { + // We had an error while trying to bind. Now we need to create an error + // object with the right message. Note that we special case + // SQLITE_MISMATCH, but otherwise get the message from SQLite. + const char *msg = "Could not covert nsIVariant to SQLite type."; + if (rc != SQLITE_MISMATCH) + msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement)); + + nsCOMPtr<mozIStorageError> err(new Error(rc, msg)); + return err.forget(); + } + } + + return nullptr; +} + +already_AddRefed<mozIStorageError> +AsyncBindingParams::bind(sqlite3_stmt * aStatement) +{ + // We should bind by index using the super-class if there is nothing in our + // hashtable. + if (!mNamedParameters.Count()) + return BindingParams::bind(aStatement); + + nsCOMPtr<mozIStorageError> err; + + for (auto iter = mNamedParameters.Iter(); !iter.Done(); iter.Next()) { + const nsACString &key = iter.Key(); + + // We do not accept any forms of names other than ":name", but we need to + // add the colon for SQLite. + nsAutoCString name(":"); + name.Append(key); + int oneIdx = ::sqlite3_bind_parameter_index(aStatement, name.get()); + + if (oneIdx == 0) { + nsAutoCString errMsg(key); + errMsg.AppendLiteral(" is not a valid named parameter."); + err = new Error(SQLITE_RANGE, errMsg.get()); + break; + } + + // XPCVariant's AddRef and Release are not thread-safe and so we must not + // do anything that would invoke them here on the async thread. As such we + // can't cram aValue into mParameters using ReplaceObjectAt so that + // we can freeload off of the BindingParams::Bind implementation. + int rc = variantToSQLiteT(BindingColumnData(aStatement, oneIdx - 1), + iter.UserData()); + if (rc != SQLITE_OK) { + // We had an error while trying to bind. Now we need to create an error + // object with the right message. Note that we special case + // SQLITE_MISMATCH, but otherwise get the message from SQLite. + const char *msg = "Could not covert nsIVariant to SQLite type."; + if (rc != SQLITE_MISMATCH) { + msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement)); + } + err = new Error(rc, msg); + break; + } + } + + return err.forget(); +} + + +/////////////////////////////////////////////////////////////////////////////// +//// mozIStorageBindingParams + +NS_IMETHODIMP +BindingParams::BindByName(const nsACString &aName, + nsIVariant *aValue) +{ + NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); + + // Get the column index that we need to store this at. + uint32_t index; + nsresult rv = mOwningStatement->GetParameterIndex(aName, &index); + NS_ENSURE_SUCCESS(rv, rv); + + return BindByIndex(index, aValue); +} + +NS_IMETHODIMP +AsyncBindingParams::BindByName(const nsACString &aName, + nsIVariant *aValue) +{ + NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); + + RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue); + if (!variant) + return NS_ERROR_UNEXPECTED; + + mNamedParameters.Put(aName, variant); + return NS_OK; +} + + +NS_IMETHODIMP +BindingParams::BindUTF8StringByName(const nsACString &aName, + const nsACString &aValue) +{ + nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByName(aName, value); +} + +NS_IMETHODIMP +BindingParams::BindStringByName(const nsACString &aName, + const nsAString &aValue) +{ + nsCOMPtr<nsIVariant> value(new TextVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByName(aName, value); +} + +NS_IMETHODIMP +BindingParams::BindDoubleByName(const nsACString &aName, + double aValue) +{ + nsCOMPtr<nsIVariant> value(new FloatVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByName(aName, value); +} + +NS_IMETHODIMP +BindingParams::BindInt32ByName(const nsACString &aName, + int32_t aValue) +{ + nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByName(aName, value); +} + +NS_IMETHODIMP +BindingParams::BindInt64ByName(const nsACString &aName, + int64_t aValue) +{ + nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByName(aName, value); +} + +NS_IMETHODIMP +BindingParams::BindNullByName(const nsACString &aName) +{ + nsCOMPtr<nsIVariant> value(new NullVariant()); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByName(aName, value); +} + +NS_IMETHODIMP +BindingParams::BindBlobByName(const nsACString &aName, + const uint8_t *aValue, + uint32_t aValueSize) +{ + NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); + std::pair<const void *, int> data( + static_cast<const void *>(aValue), + int(aValueSize) + ); + nsCOMPtr<nsIVariant> value(new BlobVariant(data)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByName(aName, value); +} + +NS_IMETHODIMP +BindingParams::BindStringAsBlobByName(const nsACString& aName, + const nsAString& aValue) +{ + return DoBindStringAsBlobByName(this, aName, aValue); +} + +NS_IMETHODIMP +BindingParams::BindUTF8StringAsBlobByName(const nsACString& aName, + const nsACString& aValue) +{ + return DoBindStringAsBlobByName(this, aName, aValue); +} + + +NS_IMETHODIMP +BindingParams::BindAdoptedBlobByName(const nsACString &aName, + uint8_t *aValue, + uint32_t aValueSize) +{ + UniqueFreePtr<uint8_t> uniqueValue(aValue); + NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); + std::pair<uint8_t *, int> data(uniqueValue.release(), int(aValueSize)); + nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data)); + + return BindByName(aName, value); +} + +NS_IMETHODIMP +BindingParams::BindByIndex(uint32_t aIndex, + nsIVariant *aValue) +{ + NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); + ENSURE_INDEX_VALUE(aIndex, mParamCount); + + // Store the variant for later use. + RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue); + if (!variant) + return NS_ERROR_UNEXPECTED; + if (mParameters.Length() <= aIndex) { + (void)mParameters.SetLength(aIndex); + (void)mParameters.AppendElement(variant); + } + else { + NS_ENSURE_TRUE(mParameters.ReplaceElementAt(aIndex, variant), + NS_ERROR_OUT_OF_MEMORY); + } + return NS_OK; +} + +NS_IMETHODIMP +AsyncBindingParams::BindByIndex(uint32_t aIndex, + nsIVariant *aValue) +{ + NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); + // In the asynchronous case we do not know how many parameters there are to + // bind to, so we cannot check the validity of aIndex. + + RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue); + if (!variant) + return NS_ERROR_UNEXPECTED; + if (mParameters.Length() <= aIndex) { + mParameters.SetLength(aIndex); + mParameters.AppendElement(variant); + } + else { + NS_ENSURE_TRUE(mParameters.ReplaceElementAt(aIndex, variant), + NS_ERROR_OUT_OF_MEMORY); + } + return NS_OK; +} + +NS_IMETHODIMP +BindingParams::BindUTF8StringByIndex(uint32_t aIndex, + const nsACString &aValue) +{ + nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByIndex(aIndex, value); +} + +NS_IMETHODIMP +BindingParams::BindStringByIndex(uint32_t aIndex, + const nsAString &aValue) +{ + nsCOMPtr<nsIVariant> value(new TextVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByIndex(aIndex, value); +} + +NS_IMETHODIMP +BindingParams::BindDoubleByIndex(uint32_t aIndex, + double aValue) +{ + nsCOMPtr<nsIVariant> value(new FloatVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByIndex(aIndex, value); +} + +NS_IMETHODIMP +BindingParams::BindInt32ByIndex(uint32_t aIndex, + int32_t aValue) +{ + nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByIndex(aIndex, value); +} + +NS_IMETHODIMP +BindingParams::BindInt64ByIndex(uint32_t aIndex, + int64_t aValue) +{ + nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByIndex(aIndex, value); +} + +NS_IMETHODIMP +BindingParams::BindNullByIndex(uint32_t aIndex) +{ + nsCOMPtr<nsIVariant> value(new NullVariant()); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByIndex(aIndex, value); +} + +NS_IMETHODIMP +BindingParams::BindBlobByIndex(uint32_t aIndex, + const uint8_t *aValue, + uint32_t aValueSize) +{ + NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); + std::pair<const void *, int> data( + static_cast<const void *>(aValue), + int(aValueSize) + ); + nsCOMPtr<nsIVariant> value(new BlobVariant(data)); + NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); + + return BindByIndex(aIndex, value); +} + +NS_IMETHODIMP +BindingParams::BindStringAsBlobByIndex(uint32_t aIndex, const nsAString& aValue) +{ + return DoBindStringAsBlobByIndex(this, aIndex, aValue); +} + +NS_IMETHODIMP +BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex, + const nsACString& aValue) +{ + return DoBindStringAsBlobByIndex(this, aIndex, aValue); +} + +NS_IMETHODIMP +BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex, + uint8_t *aValue, + uint32_t aValueSize) +{ + UniqueFreePtr<uint8_t> uniqueValue(aValue); + NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); + std::pair<uint8_t *, int> data(uniqueValue.release(), int(aValueSize)); + nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data)); + + return BindByIndex(aIndex, value); +} + +} // namespace storage +} // namespace mozilla |