зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1594368, bug 483318) for causing multiple failures. CLOSED TREE
Backed out changeset 6107713f0780 (bug 1594368) Backed out changeset d23ddf67f8a4 (bug 483318) Backed out changeset 507b979e3c93 (bug 483318)
This commit is contained in:
Родитель
b69016113a
Коммит
e3cca2b9b7
|
@ -771,7 +771,6 @@ system_headers = [
|
|||
"soundtouch/SoundTouch.h",
|
||||
"spawn.h",
|
||||
"sqlite3.h",
|
||||
"sqlite3_static_ext.h",
|
||||
"sslerr.h",
|
||||
"ssl.h",
|
||||
"sslproto.h",
|
||||
|
|
|
@ -289,23 +289,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(StorageBaseStatementInternal,
|
|||
_class, _optionalGuard, AdoptedBlob, \
|
||||
(const nsACString& aWhere, uint8_t* aValue, uint32_t aValueSize), \
|
||||
(uint32_t aWhere, uint8_t * aValue, uint32_t aValueSize), \
|
||||
(aWhere, aValue, aValueSize)) \
|
||||
BIND_GEN_IMPL(_class, _optionalGuard, ArrayOfIntegers, \
|
||||
(const nsACString& aWhere, const nsTArray<int64_t>& aValue), \
|
||||
(uint32_t aWhere, const nsTArray<int64_t>& aValue), \
|
||||
(aWhere, aValue)) \
|
||||
BIND_GEN_IMPL(_class, _optionalGuard, ArrayOfDoubles, \
|
||||
(const nsACString& aWhere, const nsTArray<double>& aValue), \
|
||||
(uint32_t aWhere, const nsTArray<double>& aValue), \
|
||||
(aWhere, aValue)) \
|
||||
BIND_GEN_IMPL(_class, _optionalGuard, ArrayOfStrings, \
|
||||
(const nsACString& aWhere, const nsTArray<nsString>& aValue), \
|
||||
(uint32_t aWhere, const nsTArray<nsString>& aValue), \
|
||||
(aWhere, aValue)) \
|
||||
BIND_GEN_IMPL(_class, _optionalGuard, ArrayOfUTF8Strings, \
|
||||
(const nsACString& aWhere, const nsTArray<nsCString>& aValue), \
|
||||
(uint32_t aWhere, const nsTArray<nsCString>& aValue), \
|
||||
(aWhere, aValue))
|
||||
(aWhere, aValue, aValueSize))
|
||||
|
||||
} // namespace storage
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
#ifndef mozilla_storage_Variant_h__
|
||||
#define mozilla_storage_Variant_h__
|
||||
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include <utility>
|
||||
|
||||
#include "nsIVariant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define VARIANT_BASE_IID \
|
||||
{ /* 78888042-0fa3-4f7a-8b19-7996f99bf1aa */ \
|
||||
|
@ -29,9 +30,6 @@
|
|||
* nsCString -> TEXT (use UTF8TextVariant)
|
||||
* uint8_t[] -> BLOB (use BlobVariant)
|
||||
* nullptr -> NULL (use NullVariant)
|
||||
* int64_t[] -> ARRAY (use ArrayOfIntegersVariant)
|
||||
* double[] -> ARRAY (use ArrayOfDoublesVariant)
|
||||
* nsCString[] -> ARRAY (use ArrayOfUTF8StringsVariant)
|
||||
*
|
||||
* The kvstore component also reuses this class as a common implementation
|
||||
* of a simple threadsafe variant for the storage of primitive values only.
|
||||
|
@ -41,33 +39,18 @@
|
|||
* Bug 1494102 tracks that work.
|
||||
*/
|
||||
|
||||
namespace mozilla::storage {
|
||||
namespace mozilla {
|
||||
namespace storage {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Base Class
|
||||
|
||||
class Variant_base : public nsIVariant, public nsIInterfaceRequestor {
|
||||
class Variant_base : public nsIVariant {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIVARIANT
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(VARIANT_BASE_IID)
|
||||
|
||||
NS_IMETHOD
|
||||
GetInterface(const nsIID& aIID, void** aResult) override {
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = nullptr;
|
||||
|
||||
// This is used to recognize nsIVariant instances derived from Variant_base
|
||||
// from other implementations like XPCVariant that may not be thread-safe.
|
||||
if (aIID.Equals(VARIANT_BASE_IID) || aIID.Equals(NS_GET_IID(nsIVariant))) {
|
||||
nsCOMPtr<nsIVariant> result(static_cast<nsIVariant*>(this));
|
||||
result.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~Variant_base() = default;
|
||||
};
|
||||
|
@ -88,8 +71,8 @@ struct variant_traits {
|
|||
|
||||
template <typename DataType, bool Adopting = false>
|
||||
struct variant_storage_traits {
|
||||
using ConstructorType = DataType;
|
||||
using StorageType = DataType;
|
||||
typedef DataType ConstructorType;
|
||||
typedef DataType StorageType;
|
||||
static inline void storage_conversion(const ConstructorType aData,
|
||||
StorageType* _storage) {
|
||||
*_storage = aData;
|
||||
|
@ -102,30 +85,30 @@ struct variant_storage_traits {
|
|||
|
||||
template <typename DataType, bool Adopting = false>
|
||||
struct variant_boolean_traits {
|
||||
using StorageType =
|
||||
typename variant_storage_traits<DataType, Adopting>::StorageType;
|
||||
typedef typename variant_storage_traits<DataType, Adopting>::StorageType
|
||||
StorageType;
|
||||
static inline nsresult asBool(const StorageType&, bool*) { NO_CONVERSION }
|
||||
};
|
||||
|
||||
template <typename DataType, bool Adopting = false>
|
||||
struct variant_integer_traits {
|
||||
using StorageType =
|
||||
typename variant_storage_traits<DataType, Adopting>::StorageType;
|
||||
typedef typename variant_storage_traits<DataType, Adopting>::StorageType
|
||||
StorageType;
|
||||
static inline nsresult asInt32(const StorageType&, int32_t*) { NO_CONVERSION }
|
||||
static inline nsresult asInt64(const StorageType&, int64_t*) { NO_CONVERSION }
|
||||
};
|
||||
|
||||
template <typename DataType, bool Adopting = false>
|
||||
struct variant_float_traits {
|
||||
using StorageType =
|
||||
typename variant_storage_traits<DataType, Adopting>::StorageType;
|
||||
typedef typename variant_storage_traits<DataType, Adopting>::StorageType
|
||||
StorageType;
|
||||
static inline nsresult asDouble(const StorageType&, double*) { NO_CONVERSION }
|
||||
};
|
||||
|
||||
template <typename DataType, bool Adopting = false>
|
||||
struct variant_text_traits {
|
||||
using StorageType =
|
||||
typename variant_storage_traits<DataType, Adopting>::StorageType;
|
||||
typedef typename variant_storage_traits<DataType, Adopting>::StorageType
|
||||
StorageType;
|
||||
static inline nsresult asUTF8String(const StorageType&, nsACString&) {
|
||||
NO_CONVERSION
|
||||
}
|
||||
|
@ -135,9 +118,9 @@ struct variant_text_traits {
|
|||
};
|
||||
|
||||
template <typename DataType, bool Adopting = false>
|
||||
struct variant_array_traits {
|
||||
using StorageType =
|
||||
typename variant_storage_traits<DataType, Adopting>::StorageType;
|
||||
struct variant_blob_traits {
|
||||
typedef typename variant_storage_traits<DataType, Adopting>::StorageType
|
||||
StorageType;
|
||||
static inline nsresult asArray(const StorageType&, uint16_t*, uint32_t*,
|
||||
void**) {
|
||||
NO_CONVERSION
|
||||
|
@ -181,9 +164,8 @@ struct variant_traits<int64_t> {
|
|||
template <>
|
||||
struct variant_integer_traits<int64_t> {
|
||||
static inline nsresult asInt32(int64_t aValue, int32_t* _result) {
|
||||
if (aValue > INT32_MAX || aValue < INT32_MIN) {
|
||||
if (aValue > INT32_MAX || aValue < INT32_MIN)
|
||||
return NS_ERROR_CANNOT_CONVERT_DATA;
|
||||
}
|
||||
|
||||
*_result = static_cast<int32_t>(aValue);
|
||||
return NS_OK;
|
||||
|
@ -228,8 +210,8 @@ struct variant_traits<nsString> {
|
|||
};
|
||||
template <>
|
||||
struct variant_storage_traits<nsString> {
|
||||
using ConstructorType = const nsAString&;
|
||||
using StorageType = nsString;
|
||||
typedef const nsAString& ConstructorType;
|
||||
typedef nsString StorageType;
|
||||
static inline void storage_conversion(ConstructorType aText,
|
||||
StorageType* _outData) {
|
||||
*_outData = aText;
|
||||
|
@ -255,8 +237,8 @@ struct variant_traits<nsCString> {
|
|||
};
|
||||
template <>
|
||||
struct variant_storage_traits<nsCString> {
|
||||
using ConstructorType = const nsACString&;
|
||||
using StorageType = nsCString;
|
||||
typedef const nsACString& ConstructorType;
|
||||
typedef nsCString StorageType;
|
||||
static inline void storage_conversion(ConstructorType aText,
|
||||
StorageType* _outData) {
|
||||
*_outData = aText;
|
||||
|
@ -277,151 +259,88 @@ struct variant_text_traits<nsCString> {
|
|||
};
|
||||
|
||||
/**
|
||||
* ARRAY types
|
||||
* BLOB types
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN(bugprone-macro-parentheses)
|
||||
|
||||
#define SPECIALIZE_ARRAY_TO_NUMERIC_VARIANT(Type, DataType) \
|
||||
template <> \
|
||||
struct variant_traits<Type[]> { \
|
||||
static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; } \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct variant_storage_traits<Type[], false> { \
|
||||
using ConstructorType = std::pair<const void*, int>; \
|
||||
using StorageType = FallibleTArray<Type>; \
|
||||
static inline void storage_conversion(ConstructorType aArrayAndLength, \
|
||||
StorageType* _outData) { \
|
||||
_outData->Clear(); \
|
||||
MOZ_ALWAYS_TRUE(_outData->AppendElements( \
|
||||
static_cast<const Type*>(aArrayAndLength.first), \
|
||||
aArrayAndLength.second, fallible)); \
|
||||
} \
|
||||
static inline void destroy(const StorageType& _outData) {} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct variant_storage_traits<Type[], true> { \
|
||||
using ConstructorType = std::pair<Type*, int>; \
|
||||
using StorageType = std::pair<Type*, int>; \
|
||||
static inline void storage_conversion(ConstructorType aArrayAndLength, \
|
||||
StorageType* _outData) { \
|
||||
*_outData = aArrayAndLength; \
|
||||
} \
|
||||
static inline void destroy(StorageType& aArrayAndLength) { \
|
||||
if (aArrayAndLength.first) { \
|
||||
free(aArrayAndLength.first); \
|
||||
aArrayAndLength.first = nullptr; \
|
||||
} \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct variant_array_traits<Type[], false> { \
|
||||
static inline nsresult asArray(FallibleTArray<Type>& aData, \
|
||||
uint16_t* _type, uint32_t* _size, \
|
||||
void** _result) { \
|
||||
/* For empty arrays, we return nullptr. */ \
|
||||
if (aData.Length() == 0) { \
|
||||
*_result = nullptr; \
|
||||
*_type = DataType; \
|
||||
*_size = 0; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
/* Otherwise, we copy the array. */ \
|
||||
*_result = moz_xmemdup(aData.Elements(), aData.Length() * sizeof(Type)); \
|
||||
*_type = DataType; \
|
||||
*_size = aData.Length(); \
|
||||
return NS_OK; \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct variant_array_traits<Type[], true> { \
|
||||
static inline nsresult asArray(std::pair<Type*, int>& aData, \
|
||||
uint16_t* _type, uint32_t* _size, \
|
||||
void** _result) { \
|
||||
/* For empty arrays, we return nullptr. */ \
|
||||
if (aData.second == 0) { \
|
||||
*_result = nullptr; \
|
||||
*_type = DataType; \
|
||||
*_size = 0; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
/* Otherwise, transfer the data out. */ \
|
||||
*_result = aData.first; \
|
||||
aData.first = nullptr; \
|
||||
/* If we asked for it twice, better not use adopting! */ \
|
||||
MOZ_ASSERT(*_result); \
|
||||
*_type = DataType; \
|
||||
*_size = aData.second; \
|
||||
return NS_OK; \
|
||||
} \
|
||||
}
|
||||
|
||||
// NOLINTEND(bugprone-macro-parentheses)
|
||||
|
||||
SPECIALIZE_ARRAY_TO_NUMERIC_VARIANT(uint8_t, nsIDataType::VTYPE_UINT8);
|
||||
SPECIALIZE_ARRAY_TO_NUMERIC_VARIANT(int64_t, nsIDataType::VTYPE_INT64);
|
||||
SPECIALIZE_ARRAY_TO_NUMERIC_VARIANT(double, nsIDataType::VTYPE_DOUBLE);
|
||||
|
||||
template <>
|
||||
struct variant_traits<nsCString[]> {
|
||||
struct variant_traits<uint8_t[]> {
|
||||
static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variant_storage_traits<nsCString[], false> {
|
||||
using ConstructorType = std::pair<const void*, int>;
|
||||
using StorageType = FallibleTArray<nsCString>;
|
||||
static inline void storage_conversion(ConstructorType aArrayAndLength,
|
||||
struct variant_storage_traits<uint8_t[], false> {
|
||||
typedef std::pair<const void*, int> ConstructorType;
|
||||
typedef FallibleTArray<uint8_t> StorageType;
|
||||
static inline void storage_conversion(ConstructorType aBlob,
|
||||
StorageType* _outData) {
|
||||
_outData->Clear();
|
||||
if (!_outData->SetCapacity(aArrayAndLength.second, fallible)) {
|
||||
MOZ_ASSERT_UNREACHABLE("Cannot allocate.");
|
||||
return;
|
||||
}
|
||||
// We copy the strings to own their buffers.
|
||||
const nsCString* str = static_cast<const nsCString*>(aArrayAndLength.first);
|
||||
for (int32_t i = 0; i < aArrayAndLength.second; ++i, str++) {
|
||||
MOZ_ALWAYS_TRUE(_outData->AppendElement(ToNewCString(*str), fallible));
|
||||
}
|
||||
(void)_outData->AppendElements(static_cast<const uint8_t*>(aBlob.first),
|
||||
aBlob.second, fallible);
|
||||
}
|
||||
|
||||
static inline void destroy(const StorageType& _outData) {}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variant_array_traits<nsCString[], false> {
|
||||
static inline nsresult asArray(FallibleTArray<nsCString>& aData,
|
||||
struct variant_storage_traits<uint8_t[], true> {
|
||||
typedef std::pair<uint8_t*, int> ConstructorType;
|
||||
typedef std::pair<uint8_t*, int> StorageType;
|
||||
static inline void storage_conversion(ConstructorType aBlob,
|
||||
StorageType* _outData) {
|
||||
*_outData = aBlob;
|
||||
}
|
||||
static inline void destroy(StorageType& aData) {
|
||||
if (aData.first) {
|
||||
free(aData.first);
|
||||
aData.first = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct variant_blob_traits<uint8_t[], false> {
|
||||
static inline nsresult asArray(FallibleTArray<uint8_t>& aData,
|
||||
uint16_t* _type, uint32_t* _size,
|
||||
void** _result) {
|
||||
// For empty arrays, we return nullptr.
|
||||
// For empty blobs, we return nullptr.
|
||||
if (aData.Length() == 0) {
|
||||
*_result = nullptr;
|
||||
*_type = nsIDataType::VTYPE_UTF8STRING;
|
||||
*_type = nsIDataType::VTYPE_UINT8;
|
||||
*_size = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise, we copy the array.
|
||||
// This memory will be freed up after Sqlite made its own copy in
|
||||
// sqlite3_T_array. The string buffers are owned by mData.
|
||||
const char** strings =
|
||||
(const char**)moz_xmalloc(sizeof(char*) * aData.Length());
|
||||
const char** iter = strings;
|
||||
for (const nsCString& str : aData) {
|
||||
*iter = str.get();
|
||||
iter++;
|
||||
}
|
||||
*_result = strings;
|
||||
*_type = nsIDataType::VTYPE_UTF8STRING;
|
||||
*_result = moz_xmemdup(aData.Elements(), aData.Length() * sizeof(uint8_t));
|
||||
|
||||
// Set type and size
|
||||
*_type = nsIDataType::VTYPE_UINT8;
|
||||
*_size = aData.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variant_blob_traits<uint8_t[], true> {
|
||||
static inline nsresult asArray(std::pair<uint8_t*, int>& aData,
|
||||
uint16_t* _type, uint32_t* _size,
|
||||
void** _result) {
|
||||
// For empty blobs, we return nullptr.
|
||||
if (aData.second == 0) {
|
||||
*_result = nullptr;
|
||||
*_type = nsIDataType::VTYPE_UINT8;
|
||||
*_size = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise, transfer the data out.
|
||||
*_result = aData.first;
|
||||
aData.first = nullptr;
|
||||
MOZ_ASSERT(*_result); // We asked for it twice, better not use adopting!
|
||||
|
||||
// Set type and size
|
||||
*_type = nsIDataType::VTYPE_UINT8;
|
||||
*_size = aData.second;
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* nullptr type
|
||||
*/
|
||||
|
@ -486,11 +405,11 @@ class Variant final : public Variant_base {
|
|||
|
||||
NS_IMETHOD GetAsArray(uint16_t* _type, nsIID*, uint32_t* _size,
|
||||
void** _data) override {
|
||||
return variant_array_traits<DataType, Adopting>::asArray(mData, _type,
|
||||
_size, _data);
|
||||
return variant_blob_traits<DataType, Adopting>::asArray(mData, _type, _size,
|
||||
_data);
|
||||
}
|
||||
|
||||
protected:
|
||||
private:
|
||||
typename variant_storage_traits<DataType, Adopting>::StorageType mData;
|
||||
};
|
||||
|
||||
|
@ -499,21 +418,17 @@ class Variant final : public Variant_base {
|
|||
|
||||
// Currently, BooleanVariant is only useful for kvstore.
|
||||
// Bug 1494102 tracks implementing full boolean variant support for mozStorage.
|
||||
using BooleanVariant = Variant<bool>;
|
||||
typedef Variant<bool> BooleanVariant;
|
||||
|
||||
using IntegerVariant = Variant<int64_t>;
|
||||
using FloatVariant = Variant<double>;
|
||||
using TextVariant = Variant<nsString>;
|
||||
using UTF8TextVariant = Variant<nsCString>;
|
||||
using BlobVariant = Variant<uint8_t[], false>;
|
||||
using AdoptedBlobVariant = Variant<uint8_t[], true>;
|
||||
using ArrayOfIntegersVariant = Variant<int64_t[], false>;
|
||||
using AdoptedArrayOfIntegersVariant = Variant<int64_t[], true>;
|
||||
using ArrayOfDoublesVariant = Variant<double[], false>;
|
||||
using AdoptedArrayOfDoublesVariant = Variant<double[], true>;
|
||||
using ArrayOfUTF8StringsVariant = Variant<nsCString[], false>;
|
||||
typedef Variant<int64_t> IntegerVariant;
|
||||
typedef Variant<double> FloatVariant;
|
||||
typedef Variant<nsString> TextVariant;
|
||||
typedef Variant<nsCString> UTF8TextVariant;
|
||||
typedef Variant<uint8_t[], false> BlobVariant;
|
||||
typedef Variant<uint8_t[], true> AdoptedBlobVariant;
|
||||
|
||||
} // namespace mozilla::storage
|
||||
} // namespace storage
|
||||
} // namespace mozilla
|
||||
|
||||
#include "Variant_inl.h"
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ namespace storage {
|
|||
//// Variant_base
|
||||
|
||||
inline NS_IMPL_ADDREF(Variant_base) inline NS_IMPL_RELEASE(
|
||||
Variant_base) inline NS_IMPL_QUERY_INTERFACE(Variant_base, nsIVariant,
|
||||
nsIInterfaceRequestor)
|
||||
Variant_base) inline NS_IMPL_QUERY_INTERFACE(Variant_base, nsIVariant)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIVariant
|
||||
|
|
|
@ -103,7 +103,6 @@ if not CONFIG["MOZ_AVOID_DISK_REMNANT_ON_CLOSE"]:
|
|||
|
||||
LOCAL_INCLUDES += [
|
||||
"/dom/base",
|
||||
"/third_party/sqlite3/ext",
|
||||
"/third_party/sqlite3/src",
|
||||
]
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ interface mozIStorageBindingParams : nsISupports {
|
|||
* The name of the parameter to bind aValue to.
|
||||
* @param aValue
|
||||
* The value to bind.
|
||||
* @warning To bind an array use a specific `bindArrayOf` method instead.
|
||||
*/
|
||||
void bindByName(in AUTF8String aName,
|
||||
in nsIVariant aValue);
|
||||
|
@ -57,17 +56,6 @@ interface mozIStorageBindingParams : nsISupports {
|
|||
in octetPtr aValue,
|
||||
in unsigned long aValueSize);
|
||||
|
||||
// These allow to bind arrays through the carray() tabled-valued function,
|
||||
// thus they should only be used when the query contains `carray(?N)`.
|
||||
void bindArrayOfIntegersByName(in AUTF8String aName,
|
||||
in Array<int64_t> aValue);
|
||||
void bindArrayOfDoublesByName(in AUTF8String aName,
|
||||
in Array<double> aValue);
|
||||
void bindArrayOfStringsByName(in AUTF8String aName,
|
||||
in Array<AString> aValue);
|
||||
void bindArrayOfUTF8StringsByName(in AUTF8String aName,
|
||||
in Array<AUTF8String> aValue);
|
||||
|
||||
/**
|
||||
* Binds aValue to the parameter with the index aIndex.
|
||||
*
|
||||
|
@ -75,7 +63,6 @@ interface mozIStorageBindingParams : nsISupports {
|
|||
* The zero-based index of the parameter to bind aValue to.
|
||||
* @param aValue
|
||||
* The value to bind.
|
||||
* @warning To bind an array use a specific `bindArrayOf` method instead.
|
||||
*/
|
||||
void bindByIndex(in unsigned long aIndex,
|
||||
in nsIVariant aValue);
|
||||
|
@ -113,15 +100,4 @@ interface mozIStorageBindingParams : nsISupports {
|
|||
void bindAdoptedBlobByIndex(in unsigned long aIndex,
|
||||
in octetPtr aValue,
|
||||
in unsigned long aValueSize);
|
||||
|
||||
// These allow to bind arrays through the carray() tabled-valued function,
|
||||
// thus they should only be used when the query contains `carray(?N)`.
|
||||
void bindArrayOfIntegersByIndex(in unsigned long aIndex,
|
||||
in Array<int64_t> aValue);
|
||||
void bindArrayOfDoublesByIndex(in unsigned long aIndex,
|
||||
in Array<double> aValue);
|
||||
void bindArrayOfStringsByIndex(in unsigned long aIndex,
|
||||
in Array<AString> aValue);
|
||||
void bindArrayOfUTF8StringsByIndex(in unsigned long aIndex,
|
||||
in Array<AUTF8String> aValue);
|
||||
};
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozStoragePrivateHelpers.h"
|
||||
#include "mozStorageBindingParams.h"
|
||||
#include "Variant.h"
|
||||
#include "sqlite3_static_ext.h"
|
||||
|
||||
namespace mozilla::storage {
|
||||
|
||||
|
@ -64,25 +63,6 @@ int sqlite3_T_blob(BindingColumnData aData, const void* aBlob, int aSize) {
|
|||
return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize, free);
|
||||
}
|
||||
|
||||
int sqlite3_T_array(BindingColumnData aData, void* aArray, int aSize,
|
||||
int aType) {
|
||||
// In debug builds ensure that the statement includes at least one `carray()`.
|
||||
MOZ_ASSERT(
|
||||
::strstr(::sqlite3_sql(aData.stmt), "carray("),
|
||||
"Binding arrays to SQL statements requires using the carray() function.");
|
||||
|
||||
if (aType == CARRAY_TEXT) {
|
||||
// We don't manage the string buffers lifecycle, thus let SQLite make its
|
||||
// own copy.
|
||||
int srv = ::sqlite3_carray_bind(aData.stmt, aData.column + 1, aArray, aSize,
|
||||
aType, SQLITE_TRANSIENT);
|
||||
free(aArray);
|
||||
return srv;
|
||||
}
|
||||
return ::sqlite3_carray_bind(aData.stmt, aData.column + 1, aArray, aSize,
|
||||
aType, free);
|
||||
}
|
||||
|
||||
#include "variantToSQLiteT_impl.h"
|
||||
|
||||
} // namespace
|
||||
|
@ -310,61 +290,6 @@ BindingParams::BindAdoptedBlobByName(const nsACString& aName, uint8_t* aValue,
|
|||
return BindByName(aName, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindArrayOfIntegersByName(const nsACString& aName,
|
||||
const nsTArray<int64_t>& aValue) {
|
||||
NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
|
||||
std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
|
||||
int(aValue.Length()));
|
||||
nsCOMPtr<nsIVariant> value(new ArrayOfIntegersVariant(data));
|
||||
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return BindByName(aName, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindArrayOfDoublesByName(const nsACString& aName,
|
||||
const nsTArray<double>& aValue) {
|
||||
NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
|
||||
std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
|
||||
int(aValue.Length()));
|
||||
nsCOMPtr<nsIVariant> value(new ArrayOfDoublesVariant(data));
|
||||
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return BindByName(aName, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindArrayOfStringsByName(const nsACString& aName,
|
||||
const nsTArray<nsString>& aValue) {
|
||||
NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
|
||||
nsTArray<nsCString> UTF8Strings(aValue.Length());
|
||||
for (const nsString& str : aValue) {
|
||||
UTF8Strings.AppendElement(NS_ConvertUTF16toUTF8(str));
|
||||
}
|
||||
std::pair<const void*, int> data(
|
||||
static_cast<const void*>(UTF8Strings.Elements()),
|
||||
int(UTF8Strings.Length()));
|
||||
// The variant will make a copy of all the buffers.
|
||||
nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data));
|
||||
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return BindByName(aName, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindArrayOfUTF8StringsByName(const nsACString& aName,
|
||||
const nsTArray<nsCString>& aValue) {
|
||||
NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
|
||||
std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
|
||||
int(aValue.Length()));
|
||||
// The variant will make a copy of all the buffers.
|
||||
nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data));
|
||||
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return BindByName(aName, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) {
|
||||
NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
|
||||
|
@ -489,59 +414,4 @@ BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex, uint8_t* aValue,
|
|||
return BindByIndex(aIndex, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindArrayOfIntegersByIndex(uint32_t aIndex,
|
||||
const nsTArray<int64_t>& aValue) {
|
||||
NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
|
||||
std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
|
||||
int(aValue.Length()));
|
||||
nsCOMPtr<nsIVariant> value(new ArrayOfIntegersVariant(data));
|
||||
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return BindByIndex(aIndex, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindArrayOfDoublesByIndex(uint32_t aIndex,
|
||||
const nsTArray<double>& aValue) {
|
||||
NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
|
||||
std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
|
||||
int(aValue.Length()));
|
||||
nsCOMPtr<nsIVariant> value(new ArrayOfDoublesVariant(data));
|
||||
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return BindByIndex(aIndex, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindArrayOfStringsByIndex(uint32_t aIndex,
|
||||
const nsTArray<nsString>& aValue) {
|
||||
NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
|
||||
nsTArray<nsCString> UTF8Strings(aValue.Length());
|
||||
for (const nsString& str : aValue) {
|
||||
UTF8Strings.AppendElement(NS_ConvertUTF16toUTF8(str).get());
|
||||
}
|
||||
std::pair<const void*, int> data(
|
||||
static_cast<const void*>(UTF8Strings.Elements()),
|
||||
int(UTF8Strings.Length()));
|
||||
// The variant will make a copy of all the buffers.
|
||||
nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data));
|
||||
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return BindByIndex(aIndex, value);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BindingParams::BindArrayOfUTF8StringsByIndex(
|
||||
uint32_t aIndex, const nsTArray<nsCString>& aValue) {
|
||||
NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
|
||||
std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
|
||||
int(aValue.Length()));
|
||||
// The variant will make a copy of all the buffers.
|
||||
nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data));
|
||||
NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return BindByIndex(aIndex, value);
|
||||
}
|
||||
|
||||
} // namespace mozilla::storage
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include "SQLCollations.h"
|
||||
#include "FileSystemModule.h"
|
||||
#include "mozStorageHelper.h"
|
||||
#include "sqlite3_static_ext.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
@ -170,12 +169,6 @@ int sqlite3_T_blob(sqlite3_context* aCtx, const void* aData, int aSize) {
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
int sqlite3_T_array(sqlite3_context* aCtx, const void* aData, int aSize,
|
||||
int aType) {
|
||||
// Not supported for now.
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
#include "variantToSQLiteT_impl.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
#include "nsError.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
|
||||
#include "Variant.h"
|
||||
#include "mozStoragePrivateHelpers.h"
|
||||
|
@ -95,9 +95,8 @@ void checkAndLogStatementPerformance(sqlite3_stmt* aStatement) {
|
|||
|
||||
// CREATE INDEX always sorts (sorting is a necessary step in creating
|
||||
// an index). So ignore the warning there.
|
||||
if (::strstr(sql, "CREATE INDEX") || ::strstr(sql, "CREATE UNIQUE INDEX")) {
|
||||
if (::strstr(sql, "CREATE INDEX") || ::strstr(sql, "CREATE UNIQUE INDEX"))
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString message("Suboptimal indexes for the SQL statement ");
|
||||
#ifdef MOZ_STORAGE_SORTWARNING_SQL_DUMP
|
||||
|
@ -148,14 +147,11 @@ nsIVariant* convertJSValToVariant(JSContext* aCtx, const JS::Value& aValue) {
|
|||
}
|
||||
|
||||
Variant_base* convertVariantToStorageVariant(nsIVariant* aVariant) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> variant = do_QueryInterface(aVariant);
|
||||
RefPtr<Variant_base> variant = do_QueryObject(aVariant);
|
||||
if (variant) {
|
||||
// JS helpers already convert the JS representation to a Storage Variant,
|
||||
// in such a case there's nothing left to do here, so just pass-through.
|
||||
RefPtr<Variant_base> variantObj = do_GetInterface(variant);
|
||||
if (variantObj) {
|
||||
return variantObj;
|
||||
}
|
||||
return variant;
|
||||
}
|
||||
|
||||
if (!aVariant) return new NullVariant();
|
||||
|
@ -203,10 +199,6 @@ Variant_base* convertVariantToStorageVariant(nsIVariant* aVariant) {
|
|||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return new TextVariant(v);
|
||||
}
|
||||
case nsIDataType::VTYPE_EMPTY:
|
||||
case nsIDataType::VTYPE_EMPTY_ARRAY:
|
||||
case nsIDataType::VTYPE_VOID:
|
||||
return new NullVariant();
|
||||
case nsIDataType::VTYPE_ARRAY: {
|
||||
uint16_t type;
|
||||
nsIID iid;
|
||||
|
@ -220,19 +212,17 @@ Variant_base* convertVariantToStorageVariant(nsIVariant* aVariant) {
|
|||
// Take ownership of the data avoiding a further copy.
|
||||
return new AdoptedBlobVariant(v);
|
||||
}
|
||||
// We don't convert other kind of arrays because it makes the API more
|
||||
// error prone, especially on the javascript side where it may not be
|
||||
// so uncommon to mistakenly pass an array instead of a primitive.
|
||||
// Consumers should instead use the dedicated `BindArrayOf` methods.
|
||||
[[fallthrough]];
|
||||
}
|
||||
case nsIDataType::VTYPE_EMPTY:
|
||||
case nsIDataType::VTYPE_EMPTY_ARRAY:
|
||||
case nsIDataType::VTYPE_VOID:
|
||||
return new NullVariant();
|
||||
case nsIDataType::VTYPE_ID:
|
||||
case nsIDataType::VTYPE_INTERFACE:
|
||||
case nsIDataType::VTYPE_INTERFACE_IS:
|
||||
default:
|
||||
NS_WARNING(
|
||||
nsPrintfCString("Unsupported variant type: %d", dataType).get());
|
||||
MOZ_ASSERT_UNREACHABLE("Tried to bind an unsupported Variant type");
|
||||
NS_WARNING("Unsupported variant type");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ UNIFIED_SOURCES += [
|
|||
"test_async_callbacks_with_spun_event_loops.cpp",
|
||||
"test_async_thread_naming.cpp",
|
||||
"test_asyncStatementExecution_transaction.cpp",
|
||||
"test_binding_arrays.cpp",
|
||||
"test_binding_params.cpp",
|
||||
"test_file_perms.cpp",
|
||||
"test_interruptSynchronousConnection.cpp",
|
||||
|
|
|
@ -1,174 +0,0 @@
|
|||
/* -*- 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 "storage_test_harness.h"
|
||||
|
||||
#include "mozStorageHelper.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* This file tests binding and reading out array parameters through the
|
||||
* mozIStorageStatement API.
|
||||
*/
|
||||
|
||||
TEST(storage_binding_arrays, Integers)
|
||||
{
|
||||
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
|
||||
|
||||
(void)db->ExecuteSimpleSQL("CREATE TABLE test (val BLOB)"_ns);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> insert, select;
|
||||
(void)db->CreateStatement(
|
||||
"INSERT INTO test (val) SELECT value FROM carray(?1)"_ns,
|
||||
getter_AddRefs(insert));
|
||||
(void)db->CreateStatement("SELECT val FROM test WHERE val IN carray(?1)"_ns,
|
||||
getter_AddRefs(select));
|
||||
|
||||
nsTArray<int64_t> inserted = {1, 2};
|
||||
{
|
||||
mozStorageStatementScoper scoper(insert);
|
||||
bool hasResult;
|
||||
do_check_true(
|
||||
NS_SUCCEEDED(insert->BindArrayOfIntegersByIndex(0, inserted)));
|
||||
do_check_true(NS_SUCCEEDED(insert->ExecuteStep(&hasResult)));
|
||||
do_check_false(hasResult);
|
||||
}
|
||||
|
||||
nsAutoCString result;
|
||||
{
|
||||
mozStorageStatementScoper scoper(select);
|
||||
do_check_true(
|
||||
NS_SUCCEEDED(select->BindArrayOfIntegersByIndex(0, inserted)));
|
||||
bool hasResult;
|
||||
for (auto expected : inserted) {
|
||||
do_check_true(NS_SUCCEEDED(select->ExecuteStep(&hasResult)));
|
||||
do_check_true(hasResult);
|
||||
int64_t result;
|
||||
do_check_true(NS_SUCCEEDED(select->GetInt64(0, &result)));
|
||||
do_check_true(result == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(storage_binding_arrays, Doubles)
|
||||
{
|
||||
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
|
||||
|
||||
(void)db->ExecuteSimpleSQL("CREATE TABLE test (val BLOB)"_ns);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> insert, select;
|
||||
(void)db->CreateStatement(
|
||||
"INSERT INTO test (val) SELECT value FROM carray(?1)"_ns,
|
||||
getter_AddRefs(insert));
|
||||
(void)db->CreateStatement("SELECT val FROM test WHERE val IN carray(?1)"_ns,
|
||||
getter_AddRefs(select));
|
||||
|
||||
nsTArray<double> inserted = {1.1, 2.2};
|
||||
{
|
||||
mozStorageStatementScoper scoper(insert);
|
||||
bool hasResult;
|
||||
do_check_true(NS_SUCCEEDED(insert->BindArrayOfDoublesByIndex(0, inserted)));
|
||||
do_check_true(NS_SUCCEEDED(insert->ExecuteStep(&hasResult)));
|
||||
do_check_false(hasResult);
|
||||
}
|
||||
|
||||
nsAutoCString result;
|
||||
{
|
||||
mozStorageStatementScoper scoper(select);
|
||||
do_check_true(NS_SUCCEEDED(select->BindArrayOfDoublesByIndex(0, inserted)));
|
||||
bool hasResult;
|
||||
for (auto expected : inserted) {
|
||||
do_check_true(NS_SUCCEEDED(select->ExecuteStep(&hasResult)));
|
||||
do_check_true(hasResult);
|
||||
double result;
|
||||
do_check_true(NS_SUCCEEDED(select->GetDouble(0, &result)));
|
||||
do_check_true(result == expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(storage_binding_arrays, UTF8Strings)
|
||||
{
|
||||
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
|
||||
|
||||
(void)db->ExecuteSimpleSQL("CREATE TABLE test (val BLOB)"_ns);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> insert, select;
|
||||
(void)db->CreateStatement(
|
||||
"INSERT INTO test (val) SELECT value FROM carray(?1)"_ns,
|
||||
getter_AddRefs(insert));
|
||||
(void)db->CreateStatement("SELECT val FROM test WHERE val IN carray(?1)"_ns,
|
||||
getter_AddRefs(select));
|
||||
|
||||
nsTArray<nsCString> inserted = {"test1"_ns, "test2"_ns};
|
||||
{
|
||||
mozStorageStatementScoper scoper(insert);
|
||||
bool hasResult;
|
||||
do_check_true(
|
||||
NS_SUCCEEDED(insert->BindArrayOfUTF8StringsByIndex(0, inserted)));
|
||||
do_check_true(NS_SUCCEEDED(insert->ExecuteStep(&hasResult)));
|
||||
do_check_false(hasResult);
|
||||
}
|
||||
|
||||
nsAutoCString result;
|
||||
{
|
||||
mozStorageStatementScoper scoper(select);
|
||||
bool hasResult;
|
||||
do_check_true(
|
||||
NS_SUCCEEDED(select->BindArrayOfUTF8StringsByIndex(0, inserted)));
|
||||
for (const auto& expected : inserted) {
|
||||
do_check_true(NS_SUCCEEDED(select->ExecuteStep(&hasResult)));
|
||||
do_check_true(hasResult);
|
||||
nsCString result;
|
||||
do_check_true(NS_SUCCEEDED(select->GetUTF8String(0, result)));
|
||||
do_check_true(result.Equals(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(storage_binding_arrays, AsyncStatement_BindingParamsArray)
|
||||
{
|
||||
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
|
||||
|
||||
(void)db->ExecuteSimpleSQL("CREATE TABLE test (val BLOB)"_ns);
|
||||
|
||||
nsCOMPtr<mozIStorageAsyncStatement> insert;
|
||||
(void)db->CreateAsyncStatement(
|
||||
"INSERT INTO test (val) SELECT value FROM carray(:values)"_ns,
|
||||
getter_AddRefs(insert));
|
||||
nsTArray<int64_t> insertedIntegers = {1, 2};
|
||||
nsTArray<nsCString> insertedStrings = {"test1"_ns, "test2"_ns};
|
||||
nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
|
||||
insert->NewBindingParamsArray(getter_AddRefs(paramsArray));
|
||||
nsCOMPtr<mozIStorageBindingParams> intParams;
|
||||
paramsArray->NewBindingParams(getter_AddRefs(intParams));
|
||||
do_check_true(NS_SUCCEEDED(
|
||||
intParams->BindArrayOfIntegersByName("values"_ns, insertedIntegers)));
|
||||
do_check_true(NS_SUCCEEDED(paramsArray->AddParams(intParams)));
|
||||
intParams = nullptr;
|
||||
nsCOMPtr<mozIStorageBindingParams> strParams;
|
||||
paramsArray->NewBindingParams(getter_AddRefs(strParams));
|
||||
do_check_true(NS_SUCCEEDED(
|
||||
strParams->BindArrayOfUTF8StringsByName("values"_ns, insertedStrings)));
|
||||
do_check_true(NS_SUCCEEDED(paramsArray->AddParams(strParams)));
|
||||
strParams = nullptr;
|
||||
do_check_true(NS_SUCCEEDED(insert->BindParameters(paramsArray)));
|
||||
paramsArray = nullptr;
|
||||
blocking_async_execute(insert);
|
||||
insert->Finalize();
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> select;
|
||||
(void)db->CreateStatement("SELECT count(*) FROM test"_ns,
|
||||
getter_AddRefs(select));
|
||||
bool hasResult;
|
||||
do_check_true(NS_SUCCEEDED(select->ExecuteStep(&hasResult)));
|
||||
do_check_true(hasResult);
|
||||
do_check_true(select->AsInt64(0) == 4);
|
||||
select->Finalize();
|
||||
|
||||
blocking_async_close(db);
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* This file tests binding arrays to statements.
|
||||
*/
|
||||
|
||||
add_task(async function test_errors() {
|
||||
let db = Services.storage.openSpecialDatabase("memory");
|
||||
let stmt = db.createStatement("SELECT * FROM carray(?1)");
|
||||
|
||||
Assert.throws(
|
||||
() => stmt.bindArrayOfIntegersByIndex(0, 1),
|
||||
/NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY/,
|
||||
"Not an array"
|
||||
);
|
||||
Assert.throws(
|
||||
() => stmt.bindArrayOfIntegersByIndex(0, "string"),
|
||||
/NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY/,
|
||||
"Not an array"
|
||||
);
|
||||
Assert.throws(
|
||||
() => stmt.bindArrayOfIntegersByIndex(0, null),
|
||||
/NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY/,
|
||||
"Not an array"
|
||||
);
|
||||
Assert.throws(
|
||||
() => stmt.bindArrayOfUTF8StringsByIndex(0, null),
|
||||
/NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY/,
|
||||
"Not an array"
|
||||
);
|
||||
|
||||
stmt.finalize();
|
||||
db.close();
|
||||
});
|
||||
|
||||
add_task(async function test_bind_empty_array() {
|
||||
let db = Services.storage.openSpecialDatabase("memory");
|
||||
let stmt = db.createStatement("SELECT * FROM carray(?1)");
|
||||
stmt.bindArrayOfIntegersByIndex(0, []);
|
||||
Assert.ok(!stmt.executeStep(), "Execution succeeds with no results");
|
||||
stmt.finalize();
|
||||
db.close();
|
||||
});
|
||||
|
||||
add_task(async function test_bind() {
|
||||
let db = getOpenedDatabase();
|
||||
db.executeSimpleSQL(`
|
||||
CREATE TABLE test (
|
||||
id INTEGER,
|
||||
value BLOB /* no affinity */
|
||||
)
|
||||
`);
|
||||
|
||||
db.executeSimpleSQL(`
|
||||
INSERT INTO test (value)
|
||||
VALUES
|
||||
(1),
|
||||
(2),
|
||||
(1.1),
|
||||
(2.2),
|
||||
("test1"),
|
||||
("test2")
|
||||
`);
|
||||
|
||||
function bindStatement(stmt, results) {
|
||||
if (Number.isInteger(results[0])) {
|
||||
stmt.bindArrayOfIntegersByIndex(0, results);
|
||||
stmt.bindArrayOfIntegersByName("values", results);
|
||||
} else if (typeof results[0] == "number") {
|
||||
stmt.bindArrayOfDoublesByIndex(0, results);
|
||||
stmt.bindArrayOfDoublesByName("values", results);
|
||||
} else if (typeof results[0] == "string") {
|
||||
stmt.bindArrayOfStringsByIndex(0, results);
|
||||
stmt.bindArrayOfStringsByName("values", results);
|
||||
}
|
||||
}
|
||||
|
||||
for (let results of [[1, 2], [1.1, 2.2], ["test1", "test2"], []]) {
|
||||
info("sync statement");
|
||||
let query = `
|
||||
SELECT value FROM test
|
||||
WHERE value IN carray(?1)
|
||||
AND value IN carray(:values)
|
||||
`;
|
||||
let stmt = db.createStatement(query);
|
||||
bindStatement(stmt, results);
|
||||
for (let result of results) {
|
||||
Assert.ok(stmt.executeStep());
|
||||
Assert.equal(stmt.row.value, result);
|
||||
}
|
||||
stmt.finalize();
|
||||
|
||||
info("async statement");
|
||||
stmt = db.createAsyncStatement(query);
|
||||
bindStatement(stmt, results);
|
||||
let rv = await new Promise((resolve, reject) => {
|
||||
let rows = [];
|
||||
stmt.executeAsync({
|
||||
handleResult(resultSet) {
|
||||
let row = null;
|
||||
do {
|
||||
row = resultSet.getNextRow();
|
||||
if (row) {
|
||||
rows.push(row);
|
||||
}
|
||||
} while (row);
|
||||
},
|
||||
handleError(error) {
|
||||
reject(new Error(`Failed to execute statement: ${error.message}`));
|
||||
},
|
||||
handleCompletion(reason) {
|
||||
if (reason == Ci.mozIStorageStatementCallback.REASON_FINISHED) {
|
||||
resolve(rows.map(r => r.getResultByIndex(0)));
|
||||
} else {
|
||||
reject(new Error("Statement failed to execute or was cancelled"));
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
Assert.deepEqual(rv, results);
|
||||
stmt.finalize();
|
||||
}
|
||||
// we are the last test using this connection and since it has gone async
|
||||
// we *must* call asyncClose on it.
|
||||
await asyncClose(db);
|
||||
});
|
|
@ -782,12 +782,6 @@ function test_bind_no_such_name_async_deferred() {
|
|||
test_bind_no_such_name_async_deferred.asyncOnly = true;
|
||||
|
||||
function test_bind_bogus_type_by_index() {
|
||||
if (AppConstants.DEBUG) {
|
||||
// Skip this test as in debug builds this is a fatal assert.
|
||||
run_next_test();
|
||||
return;
|
||||
}
|
||||
|
||||
// We try to bind a JS Object here that should fail to bind.
|
||||
let stmt = makeTestStatement("INSERT INTO test (blober) VALUES (?)");
|
||||
|
||||
|
@ -800,12 +794,6 @@ function test_bind_bogus_type_by_index() {
|
|||
}
|
||||
|
||||
function test_bind_bogus_type_by_name() {
|
||||
if (AppConstants.DEBUG) {
|
||||
// Skip this test as in debug builds this is a fatal assert.
|
||||
run_next_test();
|
||||
return;
|
||||
}
|
||||
|
||||
// We try to bind a JS Object here that should fail to bind.
|
||||
let stmt = makeTestStatement("INSERT INTO test (blober) VALUES (:blob)");
|
||||
|
||||
|
|
|
@ -9,8 +9,6 @@ support-files = [
|
|||
"VacuumParticipant.sys.mjs",
|
||||
]
|
||||
|
||||
["test_bindArray.js"]
|
||||
|
||||
["test_bug-365166.js"]
|
||||
|
||||
["test_bug-393952.js"]
|
||||
|
|
|
@ -87,31 +87,20 @@ int variantToSQLiteT(T aObj, nsIVariant* aValue) {
|
|||
void* data;
|
||||
nsresult rv = aValue->GetAsArray(&arrayType, &iid, &count, &data);
|
||||
NS_ENSURE_SUCCESS(rv, SQLITE_MISMATCH);
|
||||
if (arrayType == nsIDataType::VTYPE_UINT8) {
|
||||
// The function should free the array accordingly!
|
||||
return sqlite3_T_blob(aObj, data, count);
|
||||
}
|
||||
// Empty array is handled as NULL.
|
||||
if (count == 0) {
|
||||
return sqlite3_T_null(aObj);
|
||||
}
|
||||
if (arrayType == nsIDataType::VTYPE_INT32 ||
|
||||
arrayType == nsIDataType::VTYPE_INT64) {
|
||||
return sqlite3_T_array(aObj, data, count, CARRAY_INT64);
|
||||
}
|
||||
if (arrayType == nsIDataType::VTYPE_FLOAT ||
|
||||
arrayType == nsIDataType::VTYPE_DOUBLE) {
|
||||
return sqlite3_T_array(aObj, data, count, CARRAY_DOUBLE);
|
||||
}
|
||||
if (arrayType == nsIDataType::VTYPE_UTF8STRING) {
|
||||
return sqlite3_T_array(aObj, data, count, CARRAY_TEXT);
|
||||
|
||||
// Check to make sure it's a supported type.
|
||||
NS_ASSERTION(arrayType == nsIDataType::VTYPE_UINT8,
|
||||
"Invalid type passed! You may leak!");
|
||||
if (arrayType != nsIDataType::VTYPE_UINT8) {
|
||||
// Technically this could leak with certain data types, but somebody was
|
||||
// being stupid passing us this anyway.
|
||||
free(data);
|
||||
return SQLITE_MISMATCH;
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported type in Storage bound array");
|
||||
// Technically this could leak with certain data types, but somebody was
|
||||
// being incautious passing us this anyway.
|
||||
free(data);
|
||||
return SQLITE_MISMATCH;
|
||||
// Finally do our thing. The function should free the array accordingly!
|
||||
int rc = sqlite3_T_blob(aObj, data, count);
|
||||
return rc;
|
||||
}
|
||||
// Maybe, it'll be possible to convert these
|
||||
// in future too.
|
||||
|
|
|
@ -1,561 +0,0 @@
|
|||
/*
|
||||
** 2016-06-29
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file demonstrates how to create a table-valued-function that
|
||||
** returns the values in a C-language array.
|
||||
** Examples:
|
||||
**
|
||||
** SELECT * FROM carray($ptr,5)
|
||||
**
|
||||
** The query above returns 5 integers contained in a C-language array
|
||||
** at the address $ptr. $ptr is a pointer to the array of integers.
|
||||
** The pointer value must be assigned to $ptr using the
|
||||
** sqlite3_bind_pointer() interface with a pointer type of "carray".
|
||||
** For example:
|
||||
**
|
||||
** static int aX[] = { 53, 9, 17, 2231, 4, 99 };
|
||||
** int i = sqlite3_bind_parameter_index(pStmt, "$ptr");
|
||||
** sqlite3_bind_pointer(pStmt, i, aX, "carray", 0);
|
||||
**
|
||||
** There is an optional third parameter to determine the datatype of
|
||||
** the C-language array. Allowed values of the third parameter are
|
||||
** 'int32', 'int64', 'double', 'char*', 'struct iovec'. Example:
|
||||
**
|
||||
** SELECT * FROM carray($ptr,10,'char*');
|
||||
**
|
||||
** The default value of the third parameter is 'int32'.
|
||||
**
|
||||
** HOW IT WORKS
|
||||
**
|
||||
** The carray "function" is really a virtual table with the
|
||||
** following schema:
|
||||
**
|
||||
** CREATE TABLE carray(
|
||||
** value,
|
||||
** pointer HIDDEN,
|
||||
** count HIDDEN,
|
||||
** ctype TEXT HIDDEN
|
||||
** );
|
||||
**
|
||||
** If the hidden columns "pointer" and "count" are unconstrained, then
|
||||
** the virtual table has no rows. Otherwise, the virtual table interprets
|
||||
** the integer value of "pointer" as a pointer to the array and "count"
|
||||
** as the number of elements in the array. The virtual table steps through
|
||||
** the array, element by element.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
struct iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
#else
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
|
||||
** Must exactly match the definitions in carray.h.
|
||||
*/
|
||||
#ifndef CARRAY_INT32
|
||||
# define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
# define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
# define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
# define CARRAY_TEXT 3 /* Data is char* */
|
||||
# define CARRAY_BLOB 4 /* Data is struct iovec* */
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_API
|
||||
# ifdef _WIN32
|
||||
# define SQLITE_API __declspec(dllexport)
|
||||
# else
|
||||
# define SQLITE_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Names of allowed datatypes
|
||||
*/
|
||||
static const char *azType[] = { "int32", "int64", "double", "char*",
|
||||
"struct iovec" };
|
||||
|
||||
/*
|
||||
** Structure used to hold the sqlite3_carray_bind() information
|
||||
*/
|
||||
typedef struct carray_bind carray_bind;
|
||||
struct carray_bind {
|
||||
void *aData; /* The data */
|
||||
int nData; /* Number of elements */
|
||||
int mFlags; /* Control flags */
|
||||
void (*xDel)(void*); /* Destructor for aData */
|
||||
};
|
||||
|
||||
|
||||
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef struct carray_cursor carray_cursor;
|
||||
struct carray_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_int64 iRowid; /* The rowid */
|
||||
void *pPtr; /* Pointer to the array of values */
|
||||
sqlite3_int64 iCnt; /* Number of integers in the array */
|
||||
unsigned char eType; /* One of the CARRAY_type values */
|
||||
};
|
||||
|
||||
/*
|
||||
** The carrayConnect() method is invoked to create a new
|
||||
** carray_vtab that describes the carray virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for carray_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the carray_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against carray will look like.
|
||||
*/
|
||||
static int carrayConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
sqlite3_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
/* Column numbers */
|
||||
#define CARRAY_COLUMN_VALUE 0
|
||||
#define CARRAY_COLUMN_POINTER 1
|
||||
#define CARRAY_COLUMN_COUNT 2
|
||||
#define CARRAY_COLUMN_CTYPE 3
|
||||
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for carray_cursor objects.
|
||||
*/
|
||||
static int carrayDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new carray_cursor object.
|
||||
*/
|
||||
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
carray_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a carray_cursor.
|
||||
*/
|
||||
static int carrayClose(sqlite3_vtab_cursor *cur){
|
||||
sqlite3_free(cur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a carray_cursor to its next row of output.
|
||||
*/
|
||||
static int carrayNext(sqlite3_vtab_cursor *cur){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
pCur->iRowid++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the carray_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int carrayColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
sqlite3_int64 x = 0;
|
||||
switch( i ){
|
||||
case CARRAY_COLUMN_POINTER: return SQLITE_OK;
|
||||
case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break;
|
||||
case CARRAY_COLUMN_CTYPE: {
|
||||
sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
default: {
|
||||
switch( pCur->eType ){
|
||||
case CARRAY_INT32: {
|
||||
int *p = (int*)pCur->pPtr;
|
||||
sqlite3_result_int(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_INT64: {
|
||||
sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr;
|
||||
sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_DOUBLE: {
|
||||
double *p = (double*)pCur->pPtr;
|
||||
sqlite3_result_double(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_TEXT: {
|
||||
const char **p = (const char**)pCur->pPtr;
|
||||
sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_BLOB: {
|
||||
const struct iovec *p = (struct iovec*)pCur->pPtr;
|
||||
sqlite3_result_blob(ctx, p[pCur->iRowid-1].iov_base,
|
||||
(int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_result_int64(ctx, x);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int carrayEof(sqlite3_vtab_cursor *cur){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
return pCur->iRowid>pCur->iCnt;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the carray_cursor object back
|
||||
** to the first row of output.
|
||||
*/
|
||||
static int carrayFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
|
||||
pCur->pPtr = 0;
|
||||
pCur->iCnt = 0;
|
||||
switch( idxNum ){
|
||||
case 1: {
|
||||
carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind");
|
||||
if( pBind==0 ) break;
|
||||
pCur->pPtr = pBind->aData;
|
||||
pCur->iCnt = pBind->nData;
|
||||
pCur->eType = pBind->mFlags & 0x07;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
case 3: {
|
||||
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
|
||||
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
|
||||
if( idxNum<3 ){
|
||||
pCur->eType = CARRAY_INT32;
|
||||
}else{
|
||||
unsigned char i;
|
||||
const char *zType = (const char*)sqlite3_value_text(argv[2]);
|
||||
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
|
||||
}
|
||||
if( i>=sizeof(azType)/sizeof(azType[0]) ){
|
||||
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||
"unknown datatype: %Q", zType);
|
||||
return SQLITE_ERROR;
|
||||
}else{
|
||||
pCur->eType = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pCur->iRowid = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the carray virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
**
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** idxNum is:
|
||||
**
|
||||
** 1 If only the pointer= constraint exists. In this case, the
|
||||
** parameter must be bound using sqlite3_carray_bind().
|
||||
**
|
||||
** 2 if the pointer= and count= constraints exist.
|
||||
**
|
||||
** 3 if the ctype= constraint also exists.
|
||||
**
|
||||
** idxNum is 0 otherwise and carray becomes an empty table.
|
||||
*/
|
||||
static int carrayBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i; /* Loop over constraints */
|
||||
int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */
|
||||
int cntIdx = -1; /* Index of the count= constraint, or -1 if none */
|
||||
int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */
|
||||
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
switch( pConstraint->iColumn ){
|
||||
case CARRAY_COLUMN_POINTER:
|
||||
ptrIdx = i;
|
||||
break;
|
||||
case CARRAY_COLUMN_COUNT:
|
||||
cntIdx = i;
|
||||
break;
|
||||
case CARRAY_COLUMN_CTYPE:
|
||||
ctypeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ptrIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
|
||||
pIdxInfo->estimatedCost = (double)1;
|
||||
pIdxInfo->estimatedRows = 100;
|
||||
pIdxInfo->idxNum = 1;
|
||||
if( cntIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 2;
|
||||
if( ctypeIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 3;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pIdxInfo->estimatedCost = (double)2147483647;
|
||||
pIdxInfo->estimatedRows = 2147483647;
|
||||
pIdxInfo->idxNum = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** carray virtual table.
|
||||
*/
|
||||
static sqlite3_module carrayModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
carrayConnect, /* xConnect */
|
||||
carrayBestIndex, /* xBestIndex */
|
||||
carrayDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
carrayOpen, /* xOpen - open a cursor */
|
||||
carrayClose, /* xClose - close a cursor */
|
||||
carrayFilter, /* xFilter - configure scan constraints */
|
||||
carrayNext, /* xNext - advance a cursor */
|
||||
carrayEof, /* xEof - check for end of scan */
|
||||
carrayColumn, /* xColumn - read data */
|
||||
carrayRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0, /* xShadow */
|
||||
0 /* xIntegrity */
|
||||
};
|
||||
|
||||
/*
|
||||
** Destructor for the carray_bind object
|
||||
*/
|
||||
static void carrayBindDel(void *pPtr){
|
||||
carray_bind *p = (carray_bind*)pPtr;
|
||||
if( p->xDel!=SQLITE_STATIC ){
|
||||
p->xDel(p->aData);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke this interface in order to bind to the single-argument
|
||||
** version of CARRAY().
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt,
|
||||
int idx,
|
||||
void *aData,
|
||||
int nData,
|
||||
int mFlags,
|
||||
void (*xDestroy)(void*)
|
||||
){
|
||||
carray_bind *pNew;
|
||||
int i;
|
||||
pNew = sqlite3_malloc64(sizeof(*pNew));
|
||||
if( pNew==0 ){
|
||||
if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){
|
||||
xDestroy(aData);
|
||||
}
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pNew->nData = nData;
|
||||
pNew->mFlags = mFlags;
|
||||
if( xDestroy==SQLITE_TRANSIENT ){
|
||||
sqlite3_int64 sz = nData;
|
||||
switch( mFlags & 0x07 ){
|
||||
case CARRAY_INT32: sz *= 4; break;
|
||||
case CARRAY_INT64: sz *= 8; break;
|
||||
case CARRAY_DOUBLE: sz *= 8; break;
|
||||
case CARRAY_TEXT: sz *= sizeof(char*); break;
|
||||
case CARRAY_BLOB: sz *= sizeof(struct iovec); break;
|
||||
}
|
||||
if( (mFlags & 0x07)==CARRAY_TEXT ){
|
||||
for(i=0; i<nData; i++){
|
||||
const char *z = ((char**)aData)[i];
|
||||
if( z ) sz += strlen(z) + 1;
|
||||
}
|
||||
}else if( (mFlags & 0x07)==CARRAY_BLOB ){
|
||||
for(i=0; i<nData; i++){
|
||||
sz += ((struct iovec*)aData)[i].iov_len;
|
||||
}
|
||||
}
|
||||
pNew->aData = sqlite3_malloc64( sz );
|
||||
if( pNew->aData==0 ){
|
||||
sqlite3_free(pNew);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( (mFlags & 0x07)==CARRAY_TEXT ){
|
||||
char **az = (char**)pNew->aData;
|
||||
char *z = (char*)&az[nData];
|
||||
for(i=0; i<nData; i++){
|
||||
const char *zData = ((char**)aData)[i];
|
||||
sqlite3_int64 n;
|
||||
if( zData==0 ){
|
||||
az[i] = 0;
|
||||
continue;
|
||||
}
|
||||
az[i] = z;
|
||||
n = strlen(zData);
|
||||
memcpy(z, zData, n+1);
|
||||
z += n+1;
|
||||
}
|
||||
}else if( (mFlags & 0x07)==CARRAY_BLOB ){
|
||||
struct iovec *p = (struct iovec*)pNew->aData;
|
||||
unsigned char *z = (unsigned char*)&p[nData];
|
||||
for(i=0; i<nData; i++){
|
||||
size_t n = ((struct iovec*)aData)[i].iov_len;
|
||||
p[i].iov_len = n;
|
||||
p[i].iov_base = z;
|
||||
z += n;
|
||||
memcpy(p[i].iov_base, ((struct iovec*)aData)[i].iov_base, n);
|
||||
}
|
||||
}else{
|
||||
memcpy(pNew->aData, aData, sz);
|
||||
}
|
||||
pNew->xDel = sqlite3_free;
|
||||
}else{
|
||||
pNew->aData = aData;
|
||||
pNew->xDel = xDestroy;
|
||||
}
|
||||
return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** For testing purpose in the TCL test harness, we need a method for
|
||||
** setting the pointer value. The inttoptr(X) SQL function accomplishes
|
||||
** this. Tcl script will bind an integer to X and the inttoptr() SQL
|
||||
** function will use sqlite3_result_pointer() to convert that integer into
|
||||
** a pointer.
|
||||
**
|
||||
** This is for testing on TCL only.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
static void inttoptrFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
void *p;
|
||||
sqlite3_int64 i64;
|
||||
i64 = sqlite3_value_int64(argv[0]);
|
||||
if( sizeof(i64)==sizeof(p) ){
|
||||
memcpy(&p, &i64, sizeof(p));
|
||||
}else{
|
||||
int i32 = i64 & 0xffffffff;
|
||||
memcpy(&p, &i32, sizeof(p));
|
||||
}
|
||||
sqlite3_result_pointer(context, p, "carray", 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
SQLITE_API int sqlite3_carray_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
|
||||
#ifdef SQLITE_TEST
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
|
||||
inttoptrFunc, 0, 0);
|
||||
}
|
||||
#endif /* SQLITE_TEST */
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
return rc;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
** 2020-11-17
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** Interface definitions for the CARRAY table-valued function
|
||||
** extension.
|
||||
*/
|
||||
|
||||
#ifndef _CARRAY_H
|
||||
#define _CARRAY_H
|
||||
|
||||
#include "sqlite3.h" /* Required for error code definitions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Use this interface to bind an array to the single-argument version
|
||||
** of CARRAY().
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt, /* Statement to be bound */
|
||||
int i, /* Parameter index */
|
||||
void *aData, /* Pointer to array data */
|
||||
int nData, /* Number of data elements */
|
||||
int mFlags, /* CARRAY flags */
|
||||
void (*xDel)(void*) /* Destructgor for aData*/
|
||||
);
|
||||
|
||||
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
|
||||
*/
|
||||
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
#define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
#define CARRAY_TEXT 3 /* Data is char* */
|
||||
#define CARRAY_BLOB 4 /* Data is struct iovec */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#endif /* ifndef _CARRAY_H */
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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 https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is an exported header containing declarations of methods for statically
|
||||
* linked SQLite3 extensions.
|
||||
*/
|
||||
|
||||
#ifndef SQLITE3_STATIC_EXT_H
|
||||
#define SQLITE3_STATIC_EXT_H
|
||||
#include "sqlite3.h"
|
||||
#include "misc/carray.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
SQLITE_API int sqlite3_carray_init(sqlite3*, char**,
|
||||
const sqlite3_api_routines*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE3_STATIC_EXT_H */
|
|
@ -32,8 +32,6 @@ vendoring:
|
|||
exclude:
|
||||
- "**"
|
||||
include:
|
||||
- ext/misc/carray.h
|
||||
- ext/misc/carray.c
|
||||
- LICENSE.md
|
||||
- VERSION
|
||||
keep:
|
||||
|
@ -46,12 +44,6 @@ vendoring:
|
|||
- action: move-file
|
||||
from: '{vendor_dir}/VERSION'
|
||||
to: '{vendor_dir}/VERSION.txt'
|
||||
- action: move-file
|
||||
from: '{vendor_dir}/ext/misc/carray.h'
|
||||
to: '{yaml_dir}/ext/misc/carray.h'
|
||||
- action: move-file
|
||||
from: '{vendor_dir}/ext/misc/carray.c'
|
||||
to: '{yaml_dir}/ext/misc/carray.c'
|
||||
- action: run-script
|
||||
script: '{yaml_dir}/vendor.sh'
|
||||
cwd: '{yaml_dir}'
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
NoVisibilityFlags()
|
||||
|
||||
EXPORTS += [
|
||||
"sqlite3.h",
|
||||
'sqlite3.h',
|
||||
]
|
||||
|
||||
# We allow warnings for third-party code that can be updated from upstream.
|
||||
|
@ -24,20 +24,11 @@ DIRS += [
|
|||
]
|
||||
|
||||
SOURCES += [
|
||||
"../ext/misc/carray.c",
|
||||
"sqlite3.c",
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"../ext",
|
||||
'sqlite3.c',
|
||||
]
|
||||
|
||||
OS_LIBS += CONFIG["DL_LIBS"]
|
||||
|
||||
# While the amalgamation already defines this, it is necessary for the static
|
||||
# extensions that we incorporate (e.g. carray).
|
||||
DEFINES["SQLITE_CORE"] = 1
|
||||
|
||||
# -DSQLITE_SECURE_DELETE=1 will cause SQLITE to 0-fill delete data so we
|
||||
# don't have to vacuum to make sure the data is not visible in the file.
|
||||
# -DSQLITE_DEFAULT_PAGE_SIZE=32768 and SQLITE_MAX_DEFAULT_PAGE_SIZE=32768
|
||||
|
|
|
@ -22,8 +22,6 @@ sqlite3_bind_value
|
|||
sqlite3_bind_zeroblob
|
||||
sqlite3_busy_handler
|
||||
sqlite3_busy_timeout
|
||||
sqlite3_carray_bind
|
||||
sqlite3_carray_init
|
||||
sqlite3_changes
|
||||
sqlite3_changes64
|
||||
sqlite3_clear_bindings
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
#include "NotifyRankingChanged.h"
|
||||
|
||||
#include "mozilla/storage.h"
|
||||
#include "mozIStorageResultSet.h"
|
||||
#include "mozIStorageRow.h"
|
||||
#include "mozilla/dom/Link.h"
|
||||
#include "nsDocShellCID.h"
|
||||
#include "mozilla/Components.h"
|
||||
|
@ -390,45 +388,21 @@ nsresult GetJSObjectFromArray(JSContext* aCtx, JS::Handle<JSObject*> aArray,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
struct VisitedUrlInfo {
|
||||
VisitedUrlInfo(nsCOMPtr<nsIURI>&& aURI,
|
||||
History::ContentParentSet&& aContentParentSet)
|
||||
: mURI(std::move(aURI)),
|
||||
mContentParentSet(std::move(aContentParentSet)) {}
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
bool mIsVisited{};
|
||||
History::ContentParentSet mContentParentSet;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class VisitedQuery final : public AsyncStatementCallback {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
using PendingVisitedQueries =
|
||||
nsTHashMap<nsURIHashKey, History::ContentParentSet>;
|
||||
using VisitedUrlsToContentParentSet =
|
||||
nsTHashMap<nsCStringHashKey, VisitedUrlInfo>;
|
||||
|
||||
static nsresult Start(PendingVisitedQueries&& aURIsToContentParentSet) {
|
||||
static nsresult Start(nsIURI* aURI,
|
||||
History::ContentParentSet&& aContentProcessesToNotify) {
|
||||
MOZ_ASSERT(aURI, "Null URI");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
History* history = History::GetService();
|
||||
NS_ENSURE_STATE(history);
|
||||
|
||||
VisitedUrlsToContentParentSet urls(aURIsToContentParentSet.Count());
|
||||
for (auto& origEntry : aURIsToContentParentSet) {
|
||||
auto& data = *origEntry.GetModifiableData();
|
||||
nsCOMPtr<nsIURI> URI = origEntry.GetKey();
|
||||
nsAutoCString spec;
|
||||
if (NS_SUCCEEDED(URI->GetSpec(spec))) {
|
||||
VisitedUrlInfo info = VisitedUrlInfo(std::move(URI), std::move(data));
|
||||
urls.InsertOrUpdate(spec, std::move(info));
|
||||
}
|
||||
}
|
||||
RefPtr<VisitedQuery> query = new VisitedQuery(std::move(urls));
|
||||
RefPtr<VisitedQuery> query =
|
||||
new VisitedQuery(aURI, std::move(aContentProcessesToNotify));
|
||||
return history->QueueVisitedStatement(std::move(query));
|
||||
}
|
||||
|
||||
|
@ -436,7 +410,6 @@ class VisitedQuery final : public AsyncStatementCallback {
|
|||
mozIVisitedStatusCallback* aCallback = nullptr) {
|
||||
MOZ_ASSERT(aURI, "Null URI");
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsMainThreadPtrHandle<mozIVisitedStatusCallback> callback(
|
||||
new nsMainThreadPtrHolder<mozIVisitedStatusCallback>(
|
||||
|
@ -444,45 +417,33 @@ class VisitedQuery final : public AsyncStatementCallback {
|
|||
|
||||
History* history = History::GetService();
|
||||
NS_ENSURE_STATE(history);
|
||||
VisitedUrlsToContentParentSet urls;
|
||||
nsAutoCString spec;
|
||||
if (NS_SUCCEEDED(aURI->GetSpec(spec))) {
|
||||
nsCOMPtr<nsIURI> uri = aURI;
|
||||
VisitedUrlInfo info =
|
||||
VisitedUrlInfo(std::move(uri), History::ContentParentSet());
|
||||
urls.InsertOrUpdate(spec, std::move(info));
|
||||
}
|
||||
RefPtr<VisitedQuery> query = new VisitedQuery(std::move(urls), callback);
|
||||
RefPtr<VisitedQuery> query = new VisitedQuery(aURI, callback);
|
||||
return history->QueueVisitedStatement(std::move(query));
|
||||
}
|
||||
|
||||
void Execute(mozIStorageAsyncStatement& aStatement) {
|
||||
nsTArray<nsCString> urls =
|
||||
ToTArray<nsTArray<nsCString>>(mUrlsToContentParentSet.Keys());
|
||||
MOZ_ALWAYS_SUCCEEDS(aStatement.BindArrayOfUTF8StringsByIndex(0, urls));
|
||||
// Bind by index for performance.
|
||||
nsresult rv = URIBinder::Bind(&aStatement, 0, mURI);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStoragePendingStatement> handle;
|
||||
MOZ_ALWAYS_SUCCEEDS(aStatement.ExecuteAsync(this, getter_AddRefs(handle)));
|
||||
rv = aStatement.ExecuteAsync(this, getter_AddRefs(handle));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet) override {
|
||||
nsCOMPtr<mozIStorageRow> row;
|
||||
while (NS_SUCCEEDED(aResultSet->GetNextRow(getter_AddRefs(row))) && row) {
|
||||
nsAutoCString spec;
|
||||
nsresult rv = row->GetUTF8String(0, spec);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// Ignore this error and continue updating others.
|
||||
continue;
|
||||
}
|
||||
if (auto entry = mUrlsToContentParentSet.Lookup(spec)) {
|
||||
entry.Data().mIsVisited = !!row->AsInt64(1);
|
||||
}
|
||||
}
|
||||
NS_IMETHOD HandleResult(mozIStorageResultSet* aResults) override {
|
||||
// If this method is called, we've gotten results, which means we have a
|
||||
// visit.
|
||||
mIsVisited = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
HandleError(mozIStorageError* aError) override {
|
||||
// We'll assume unvisited, that is the default value.
|
||||
NS_IMETHOD HandleError(mozIStorageError* aError) override {
|
||||
// mIsVisited is already set to false, and that's the assumption we will
|
||||
// make if an error occurred.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -496,38 +457,34 @@ class VisitedQuery final : public AsyncStatementCallback {
|
|||
void NotifyVisitedStatus() {
|
||||
// If an external handling callback is provided, just notify through it.
|
||||
if (mCallback) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
mUrlsToContentParentSet.Count() == 1,
|
||||
"Should only have 1 URI when a callback is provided");
|
||||
const auto iter = mUrlsToContentParentSet.ConstIter();
|
||||
if (!iter.Done()) {
|
||||
const VisitedUrlInfo& info = iter.Data();
|
||||
mCallback->IsVisited(info.mURI, info.mIsVisited);
|
||||
}
|
||||
mCallback->IsVisited(mURI, mIsVisited);
|
||||
return;
|
||||
}
|
||||
|
||||
if (History* history = History::GetService()) {
|
||||
for (const auto& entry : mUrlsToContentParentSet) {
|
||||
const VisitedUrlInfo& info = entry.GetData();
|
||||
auto status = info.mIsVisited ? IHistory::VisitedStatus::Visited
|
||||
: IHistory::VisitedStatus::Unvisited;
|
||||
history->NotifyVisited(info.mURI, status, &info.mContentParentSet);
|
||||
}
|
||||
auto status = mIsVisited ? IHistory::VisitedStatus::Visited
|
||||
: IHistory::VisitedStatus::Unvisited;
|
||||
history->NotifyVisited(mURI, status, &mContentProcessesToNotify);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
explicit VisitedQuery(VisitedUrlsToContentParentSet&& aUrlsToContentParentSet,
|
||||
const nsMainThreadPtrHandle<mozIVisitedStatusCallback>&
|
||||
aCallback = nullptr)
|
||||
: mUrlsToContentParentSet(std::move(aUrlsToContentParentSet)),
|
||||
mCallback(aCallback) {}
|
||||
explicit VisitedQuery(
|
||||
nsIURI* aURI,
|
||||
const nsMainThreadPtrHandle<mozIVisitedStatusCallback>& aCallback)
|
||||
: mURI(aURI), mCallback(aCallback) {}
|
||||
|
||||
explicit VisitedQuery(nsIURI* aURI,
|
||||
History::ContentParentSet&& aContentProcessesToNotify)
|
||||
: mURI(aURI),
|
||||
mContentProcessesToNotify(std::move(aContentProcessesToNotify)) {}
|
||||
|
||||
~VisitedQuery() = default;
|
||||
|
||||
VisitedUrlsToContentParentSet mUrlsToContentParentSet;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsMainThreadPtrHandle<mozIVisitedStatusCallback> mCallback;
|
||||
History::ContentParentSet mContentProcessesToNotify;
|
||||
bool mIsVisited = false;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(VisitedQuery, AsyncStatementCallback)
|
||||
|
@ -1066,7 +1023,7 @@ class InsertVisitedURIs final : public Runnable {
|
|||
#ifdef DEBUG
|
||||
for (nsTArray<VisitData>::size_type i = 0; i < mPlaces.Length(); i++) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
MOZ_ALWAYS_SUCCEEDS((NS_NewURI(getter_AddRefs(uri), mPlaces[i].spec)));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), mPlaces[i].spec)));
|
||||
MOZ_ASSERT(CanAddURI(uri),
|
||||
"Passed a VisitData with a URI we cannot add to history!");
|
||||
}
|
||||
|
@ -1565,18 +1522,14 @@ class ConcurrentStatementsHolder final : public mozIStorageCompletionCallback {
|
|||
// Now we can create our cached statements.
|
||||
|
||||
if (!mIsVisitedStatement) {
|
||||
// Bind by index to save a name lookup.
|
||||
(void)mReadOnlyDBConn->CreateAsyncStatement(
|
||||
nsLiteralCString("WITH urls (url, url_hash) AS ( "
|
||||
" SELECT value, hash(value) FROM carray(?1) "
|
||||
") "
|
||||
"SELECT url, last_visit_date NOTNULL "
|
||||
"FROM moz_places "
|
||||
"JOIN urls USING(url_hash, url) "),
|
||||
nsLiteralCString("SELECT 1 FROM moz_places h "
|
||||
"WHERE url_hash = hash(?1) AND url = ?1 AND "
|
||||
"last_visit_date NOTNULL "),
|
||||
getter_AddRefs(mIsVisitedStatement));
|
||||
MOZ_ASSERT(mIsVisitedStatement);
|
||||
auto queries = std::move(mVisitedQueries);
|
||||
if (mIsVisitedStatement) {
|
||||
auto queries = std::move(mVisitedQueries);
|
||||
for (auto& query : queries) {
|
||||
query->Execute(*mIsVisitedStatement);
|
||||
}
|
||||
|
@ -1586,12 +1539,11 @@ class ConcurrentStatementsHolder final : public mozIStorageCompletionCallback {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void QueueVisitedStatement(RefPtr<VisitedQuery>&& aVisitedQuery) {
|
||||
void QueueVisitedStatement(RefPtr<VisitedQuery> aCallback) {
|
||||
if (mIsVisitedStatement) {
|
||||
RefPtr<VisitedQuery> query = std::move(aVisitedQuery);
|
||||
query->Execute(*mIsVisitedStatement);
|
||||
aCallback->Execute(*mIsVisitedStatement);
|
||||
} else {
|
||||
mVisitedQueries.AppendElement(aVisitedQuery);
|
||||
mVisitedQueries.AppendElement(std::move(aCallback));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1601,9 +1553,11 @@ class ConcurrentStatementsHolder final : public mozIStorageCompletionCallback {
|
|||
mVisitedQueries.Clear();
|
||||
DebugOnly<nsresult> rv;
|
||||
if (mIsVisitedStatement) {
|
||||
MOZ_ALWAYS_SUCCEEDS(mIsVisitedStatement->Finalize());
|
||||
rv = mIsVisitedStatement->Finalize();
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
MOZ_ALWAYS_SUCCEEDS(mReadOnlyDBConn->AsyncClose(nullptr));
|
||||
rv = mReadOnlyDBConn->AsyncClose(nullptr);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
mReadOnlyDBConn = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -1619,7 +1573,7 @@ class ConcurrentStatementsHolder final : public mozIStorageCompletionCallback {
|
|||
|
||||
NS_IMPL_ISUPPORTS(ConcurrentStatementsHolder, mozIStorageCompletionCallback)
|
||||
|
||||
nsresult History::QueueVisitedStatement(RefPtr<VisitedQuery>&& aQuery) {
|
||||
nsresult History::QueueVisitedStatement(RefPtr<VisitedQuery> aQuery) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (IsShuttingDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
@ -2482,7 +2436,13 @@ void History::StartPendingVisitedQueries(PendingVisitedQueries&& aQueries) {
|
|||
Unused << cpc->SendStartVisitedQueries(uris);
|
||||
}
|
||||
} else {
|
||||
VisitedQuery::Start(std::move(aQueries));
|
||||
// TODO(bug 1594368): We could do a single query, as long as we can
|
||||
// then notify each URI individually.
|
||||
for (auto& entry : aQueries) {
|
||||
nsresult queryStatus = VisitedQuery::Start(
|
||||
entry.GetKey(), std::move(*entry.GetModifiableData()));
|
||||
Unused << NS_WARN_IF(NS_FAILED(queryStatus));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ class History final : public BaseHistory,
|
|||
|
||||
History();
|
||||
|
||||
nsresult QueueVisitedStatement(RefPtr<VisitedQuery>&&);
|
||||
nsresult QueueVisitedStatement(RefPtr<VisitedQuery>);
|
||||
|
||||
/**
|
||||
* Adds an entry in moz_places with the data in aVisitData.
|
||||
|
|
|
@ -1528,16 +1528,13 @@ PT.Remove.prototype = {
|
|||
await removeThem();
|
||||
|
||||
this.undo = async function () {
|
||||
let createdItems = [];
|
||||
for (let info of removedItems) {
|
||||
try {
|
||||
await createItemsFromBookmarksTree(info, true);
|
||||
createdItems.push(info);
|
||||
} catch (ex) {
|
||||
console.error(`Unable to undo removal of ${info.guid}`);
|
||||
}
|
||||
}
|
||||
removedItems = createdItems;
|
||||
};
|
||||
this.redo = removeThem;
|
||||
},
|
||||
|
|
|
@ -2107,8 +2107,9 @@ add_task(async function test_remove_invalid_url() {
|
|||
);
|
||||
});
|
||||
|
||||
await PT.Remove([folderGuid, guid]).transact();
|
||||
await ensureNonExistent(folderGuid, guid, folderedGuid);
|
||||
let guids = [folderGuid, guid];
|
||||
await PT.Remove(guids).transact();
|
||||
await ensureNonExistent(...guids, folderedGuid);
|
||||
// Shouldn't throw, should restore the folder but not the bookmarks.
|
||||
await PT.undo();
|
||||
await ensureNonExistent(guid, folderedGuid);
|
||||
|
@ -2117,7 +2118,7 @@ add_task(async function test_remove_invalid_url() {
|
|||
"The folder should have been re-created"
|
||||
);
|
||||
await PT.redo();
|
||||
await ensureNonExistent(folderGuid, guid, folderedGuid);
|
||||
await ensureNonExistent(guids, folderedGuid);
|
||||
// Cleanup
|
||||
await PT.clearTransactionsHistory();
|
||||
observer.reset();
|
||||
|
|
|
@ -581,7 +581,9 @@ add_task(async function stop_search() {
|
|||
let histogram = TelemetryTestUtils.getAndClearKeyedHistogram(
|
||||
SEARCH_TELEMETRY_LATENCY
|
||||
);
|
||||
let controller = new SearchSuggestionController();
|
||||
let controller = new SearchSuggestionController(() => {
|
||||
do_throw("The callback shouldn't be called after stop()");
|
||||
});
|
||||
let resultPromise = controller.fetch("mo", false, getEngine);
|
||||
controller.stop();
|
||||
await resultPromise.then(result => {
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#include "nsDebug.h"
|
||||
#include "AutoSQLiteLifetime.h"
|
||||
#include "sqlite3.h"
|
||||
#include "sqlite3_static_ext.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
#ifdef MOZ_MEMORY
|
||||
# include "mozmemory.h"
|
||||
|
@ -135,12 +133,7 @@ AutoSQLiteLifetime::AutoSQLiteLifetime() {
|
|||
if (sResult == SQLITE_OK) {
|
||||
// TODO (bug 1191405): do not preallocate the connections caches until we
|
||||
// have figured the impact on our consumers and memory.
|
||||
::sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0);
|
||||
|
||||
// Load the carray extension.
|
||||
DebugOnly<int> srv =
|
||||
::sqlite3_auto_extension((void (*)(void))sqlite3_carray_init);
|
||||
MOZ_ASSERT(srv == SQLITE_OK, "Should succeed loading carray extension");
|
||||
sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0);
|
||||
|
||||
// Explicitly initialize sqlite3. Although this is implicitly called by
|
||||
// various sqlite3 functions (and the sqlite3_open calls in our case),
|
||||
|
|
|
@ -244,7 +244,6 @@ LOCAL_INCLUDES += [
|
|||
"/dom/webbrowserpersist",
|
||||
"/js/xpconnect/loader",
|
||||
"/testing/gtest/mozilla",
|
||||
"/third_party/sqlite3/ext/",
|
||||
"/toolkit/crashreporter",
|
||||
"/xpcom/build",
|
||||
]
|
||||
|
|
Загрузка…
Ссылка в новой задаче