mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 12:50:09 +00:00
Bug 499990 - Locale-aware collation, r=sdwilsh, sr=vladimir
This commit is contained in:
parent
d1ebeafde8
commit
1dbee03d3f
@ -85,6 +85,7 @@ CPPSRCS = \
|
||||
mozStoragePrivateHelpers.cpp \
|
||||
mozStorageBindingParamsArray.cpp \
|
||||
mozStorageBindingParams.cpp \
|
||||
SQLCollations.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
|
269
storage/src/SQLCollations.cpp
Normal file
269
storage/src/SQLCollations.cpp
Normal file
@ -0,0 +1,269 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Storage code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Drew Willcoxon <adw@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "SQLCollations.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace storage {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Local Helper Functions
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Helper function for the UTF-8 locale collations.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2 as provided by SQLite. It
|
||||
* must be a non-null-terminated char* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1 as provided by SQLite. It
|
||||
* must be a non-null-terminated char* buffer.
|
||||
* @param aComparisonStrength
|
||||
* The sorting strength, one of the nsICollation constants.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
int
|
||||
localeCollationHelper8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2,
|
||||
PRInt32 aComparisonStrength)
|
||||
{
|
||||
NS_ConvertUTF8toUTF16 str1(static_cast<const char *>(aStr1), aLen1);
|
||||
NS_ConvertUTF8toUTF16 str2(static_cast<const char *>(aStr2), aLen2);
|
||||
Service *serv = static_cast<Service *>(aService);
|
||||
return serv->localeCompareStrings(str1, str2, aComparisonStrength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for the UTF-16 locale collations.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes (not characters) in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2 as provided by SQLite. It
|
||||
* must be a non-null-terminated PRUnichar* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes (not characters) in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1 as provided by SQLite. It
|
||||
* must be a non-null-terminated PRUnichar* buffer.
|
||||
* @param aComparisonStrength
|
||||
* The sorting strength, one of the nsICollation constants.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
int
|
||||
localeCollationHelper16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2,
|
||||
PRInt32 aComparisonStrength)
|
||||
{
|
||||
const PRUnichar *buf1 = static_cast<const PRUnichar *>(aStr1);
|
||||
const PRUnichar *buf2 = static_cast<const PRUnichar *>(aStr2);
|
||||
|
||||
// The second argument to the nsDependentSubstring constructor is exclusive:
|
||||
// It points to the PRUnichar immediately following the last one in the target
|
||||
// substring. Since aLen1 and aLen2 are in bytes, divide by sizeof(PRUnichar)
|
||||
// so that the pointer arithmetic is correct.
|
||||
nsDependentSubstring str1(buf1, buf1 + (aLen1 / sizeof(PRUnichar)));
|
||||
nsDependentSubstring str2(buf2, buf2 + (aLen2 / sizeof(PRUnichar)));
|
||||
Service *serv = static_cast<Service *>(aService);
|
||||
return serv->localeCompareStrings(str1, str2, aComparisonStrength);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Exposed Functions
|
||||
|
||||
int
|
||||
registerCollations(sqlite3 *aDB,
|
||||
Service *aService)
|
||||
{
|
||||
struct Collations {
|
||||
const char *zName;
|
||||
int enc;
|
||||
int(*xCompare)(void*, int, const void*, int, const void*);
|
||||
} collations[] = {
|
||||
{"locale",
|
||||
SQLITE_UTF8,
|
||||
localeCollation8},
|
||||
{"locale_case_sensitive",
|
||||
SQLITE_UTF8,
|
||||
localeCollationCaseSensitive8},
|
||||
{"locale_accent_sensitive",
|
||||
SQLITE_UTF8,
|
||||
localeCollationAccentSensitive8},
|
||||
{"locale_case_accent_sensitive",
|
||||
SQLITE_UTF8,
|
||||
localeCollationCaseAccentSensitive8},
|
||||
{"locale",
|
||||
SQLITE_UTF16,
|
||||
localeCollation16},
|
||||
{"locale_case_sensitive",
|
||||
SQLITE_UTF16,
|
||||
localeCollationCaseSensitive16},
|
||||
{"locale_accent_sensitive",
|
||||
SQLITE_UTF16,
|
||||
localeCollationAccentSensitive16},
|
||||
{"locale_case_accent_sensitive",
|
||||
SQLITE_UTF16,
|
||||
localeCollationCaseAccentSensitive16},
|
||||
};
|
||||
|
||||
int rv = SQLITE_OK;
|
||||
for (size_t i = 0; SQLITE_OK == rv && i < NS_ARRAY_LENGTH(collations); ++i) {
|
||||
struct Collations *p = &collations[i];
|
||||
rv = ::sqlite3_create_collation(aDB, p->zName, p->enc, aService,
|
||||
p->xCompare);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// SQL Collations
|
||||
|
||||
int
|
||||
localeCollation8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2)
|
||||
{
|
||||
return localeCollationHelper8(aService, aLen1, aStr1, aLen2, aStr2,
|
||||
nsICollation::kCollationCaseInSensitive);
|
||||
}
|
||||
|
||||
int
|
||||
localeCollationCaseSensitive8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2)
|
||||
{
|
||||
return localeCollationHelper8(aService, aLen1, aStr1, aLen2, aStr2,
|
||||
nsICollation::kCollationAccentInsenstive);
|
||||
}
|
||||
|
||||
int
|
||||
localeCollationAccentSensitive8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2)
|
||||
{
|
||||
return localeCollationHelper8(aService, aLen1, aStr1, aLen2, aStr2,
|
||||
nsICollation::kCollationCaseInsensitiveAscii);
|
||||
}
|
||||
|
||||
int
|
||||
localeCollationCaseAccentSensitive8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2)
|
||||
{
|
||||
return localeCollationHelper8(aService, aLen1, aStr1, aLen2, aStr2,
|
||||
nsICollation::kCollationCaseSensitive);
|
||||
}
|
||||
|
||||
int
|
||||
localeCollation16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2)
|
||||
{
|
||||
return localeCollationHelper16(aService, aLen1, aStr1, aLen2, aStr2,
|
||||
nsICollation::kCollationCaseInSensitive);
|
||||
}
|
||||
|
||||
int
|
||||
localeCollationCaseSensitive16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2)
|
||||
{
|
||||
return localeCollationHelper16(aService, aLen1, aStr1, aLen2, aStr2,
|
||||
nsICollation::kCollationAccentInsenstive);
|
||||
}
|
||||
|
||||
int
|
||||
localeCollationAccentSensitive16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2)
|
||||
{
|
||||
return localeCollationHelper16(aService, aLen1, aStr1, aLen2, aStr2,
|
||||
nsICollation::kCollationCaseInsensitiveAscii);
|
||||
}
|
||||
|
||||
int
|
||||
localeCollationCaseAccentSensitive16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2)
|
||||
{
|
||||
return localeCollationHelper16(aService, aLen1, aStr1, aLen2, aStr2,
|
||||
nsICollation::kCollationCaseSensitive);
|
||||
}
|
||||
|
||||
} // namespace storage
|
||||
} // namespace mozilla
|
282
storage/src/SQLCollations.h
Normal file
282
storage/src/SQLCollations.h
Normal file
@ -0,0 +1,282 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Storage code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Drew Willcoxon <adw@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _mozilla_storage_SQLCollations_h_
|
||||
#define _mozilla_storage_SQLCollations_h_
|
||||
|
||||
#include "mozStorageService.h"
|
||||
#include "nscore.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace storage {
|
||||
|
||||
/**
|
||||
* Registers the collating sequences declared here with the specified
|
||||
* database and Service.
|
||||
*
|
||||
* @param aDB
|
||||
* The database we'll be registering the collations with.
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by our collations.
|
||||
* @return the SQLite status code indicating success or failure.
|
||||
*/
|
||||
NS_HIDDEN_(int) registerCollations(sqlite3 *aDB, Service *aService);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Predefined Functions
|
||||
|
||||
/**
|
||||
* Custom UTF-8 collating sequence that respects the application's locale.
|
||||
* Comparison is case- and accent-insensitive. This is called by SQLite.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2. It will be passed in by
|
||||
* SQLite as a non-null-terminated char* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1. It will be passed in by
|
||||
* SQLite as a non-null-terminated char* buffer.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
NS_HIDDEN_(int) localeCollation8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2);
|
||||
|
||||
/**
|
||||
* Custom UTF-8 collating sequence that respects the application's locale.
|
||||
* Comparison is case-sensitive and accent-insensitive. This is called by
|
||||
* SQLite.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2. It will be passed in by
|
||||
* SQLite as a non-null-terminated char* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1. It will be passed in by
|
||||
* SQLite as a non-null-terminated char* buffer.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
NS_HIDDEN_(int) localeCollationCaseSensitive8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2);
|
||||
|
||||
/**
|
||||
* Custom UTF-8 collating sequence that respects the application's locale.
|
||||
* Comparison is case-insensitive and accent-sensitive. This is called by
|
||||
* SQLite.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2. It will be passed in by
|
||||
* SQLite as a non-null-terminated char* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1. It will be passed in by
|
||||
* SQLite as a non-null-terminated char* buffer.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
NS_HIDDEN_(int) localeCollationAccentSensitive8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2);
|
||||
|
||||
/**
|
||||
* Custom UTF-8 collating sequence that respects the application's locale.
|
||||
* Comparison is case- and accent-sensitive. This is called by SQLite.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2. It will be passed in by
|
||||
* SQLite as a non-null-terminated char* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1. It will be passed in by
|
||||
* SQLite as a non-null-terminated char* buffer.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
NS_HIDDEN_(int) localeCollationCaseAccentSensitive8(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2);
|
||||
|
||||
/**
|
||||
* Custom UTF-16 collating sequence that respects the application's locale.
|
||||
* Comparison is case- and accent-insensitive. This is called by SQLite.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes (not characters) in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2. It will be passed in by
|
||||
* SQLite as a non-null-terminated PRUnichar* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes (not characters) in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1. It will be passed in by
|
||||
* SQLite as a non-null-terminated PRUnichar* buffer.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
NS_HIDDEN_(int) localeCollation16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2);
|
||||
|
||||
/**
|
||||
* Custom UTF-16 collating sequence that respects the application's locale.
|
||||
* Comparison is case-sensitive and accent-insensitive. This is called by
|
||||
* SQLite.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes (not characters) in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2. It will be passed in by
|
||||
* SQLite as a non-null-terminated PRUnichar* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes (not characters) in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1. It will be passed in by
|
||||
* SQLite as a non-null-terminated PRUnichar* buffer.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
NS_HIDDEN_(int) localeCollationCaseSensitive16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2);
|
||||
|
||||
/**
|
||||
* Custom UTF-16 collating sequence that respects the application's locale.
|
||||
* Comparison is case-insensitive and accent-sensitive. This is called by
|
||||
* SQLite.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes (not characters) in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2. It will be passed in by
|
||||
* SQLite as a non-null-terminated PRUnichar* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes (not characters) in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1. It will be passed in by
|
||||
* SQLite as a non-null-terminated PRUnichar* buffer.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
NS_HIDDEN_(int) localeCollationAccentSensitive16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2);
|
||||
|
||||
/**
|
||||
* Custom UTF-16 collating sequence that respects the application's locale.
|
||||
* Comparison is case- and accent-sensitive. This is called by SQLite.
|
||||
*
|
||||
* @param aService
|
||||
* The Service that owns the nsICollation used by this collation.
|
||||
* @param aLen1
|
||||
* The number of bytes (not characters) in aStr1.
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2. It will be passed in by
|
||||
* SQLite as a non-null-terminated PRUnichar* buffer.
|
||||
* @param aLen2
|
||||
* The number of bytes (not characters) in aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1. It will be passed in by
|
||||
* SQLite as a non-null-terminated PRUnichar* buffer.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative number.
|
||||
* If aStr1 > aStr2, returns a positive number. If aStr1 == aStr2,
|
||||
* returns 0.
|
||||
*/
|
||||
NS_HIDDEN_(int) localeCollationCaseAccentSensitive16(void *aService,
|
||||
int aLen1,
|
||||
const void *aStr1,
|
||||
int aLen2,
|
||||
const void *aStr2);
|
||||
|
||||
} // namespace storage
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // _mozilla_storage_SQLCollations_h_
|
@ -25,6 +25,7 @@
|
||||
* Brett Wilson <brettw@gmail.com>
|
||||
* Shawn Wilsher <me@shawnwilsher.com>
|
||||
* Lev Serebryakov <lev@serebryakov.spb.ru>
|
||||
* Drew Willcoxon <adw@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -63,6 +64,7 @@
|
||||
#include "mozStorageArgValueArray.h"
|
||||
#include "mozStoragePrivateHelpers.h"
|
||||
#include "mozStorageStatementData.h"
|
||||
#include "SQLCollations.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#include "prprf.h"
|
||||
@ -242,7 +244,7 @@ aggregateFunctionFinalHelper(sqlite3_context *aCtx)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Connection
|
||||
|
||||
Connection::Connection(mozIStorageService *aService)
|
||||
Connection::Connection(Service *aService)
|
||||
: sharedAsyncExecutionMutex("Connection::sharedAsyncExecutionMutex")
|
||||
, mDBConn(nsnull)
|
||||
, mAsyncExecutionMutex(nsAutoLock::NewLock("AsyncExecutionMutex"))
|
||||
@ -338,7 +340,17 @@ Connection::initialize(nsIFile *aDatabaseFile)
|
||||
#endif
|
||||
|
||||
// Register our built-in SQL functions.
|
||||
if (registerFunctions(mDBConn) != SQLITE_OK) {
|
||||
srv = registerFunctions(mDBConn);
|
||||
if (srv != SQLITE_OK) {
|
||||
::sqlite3_close(mDBConn);
|
||||
mDBConn = nsnull;
|
||||
return convertResultCode(srv);
|
||||
}
|
||||
|
||||
// Register our built-in SQL collating sequences.
|
||||
srv = registerCollations(mDBConn, mStorageService);
|
||||
if (srv != SQLITE_OK) {
|
||||
::sqlite3_close(mDBConn);
|
||||
mDBConn = nsnull;
|
||||
return convertResultCode(srv);
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
#ifndef _MOZSTORAGECONNECTION_H_
|
||||
#define _MOZSTORAGECONNECTION_H_
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
@ -48,6 +49,7 @@
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "mozIStorageProgressHandler.h"
|
||||
#include "mozIStorageConnection.h"
|
||||
#include "mozStorageService.h"
|
||||
|
||||
#include "nsIMutableArray.h"
|
||||
|
||||
@ -57,7 +59,6 @@ struct PRLock;
|
||||
class nsIFile;
|
||||
class nsIEventTarget;
|
||||
class nsIThread;
|
||||
class mozIStorageService;
|
||||
|
||||
namespace mozilla {
|
||||
namespace storage {
|
||||
@ -68,7 +69,7 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGECONNECTION
|
||||
|
||||
Connection(mozIStorageService* aService);
|
||||
Connection(Service *aService);
|
||||
|
||||
/**
|
||||
* Creates the connection to the database.
|
||||
@ -166,9 +167,10 @@ private:
|
||||
PRLock *mProgressHandlerMutex;
|
||||
nsCOMPtr<mozIStorageProgressHandler> mProgressHandler;
|
||||
|
||||
// This isn't accessed but is used to make sure that the connections do
|
||||
// not outlive the service.
|
||||
nsCOMPtr<mozIStorageService> mStorageService;
|
||||
// This is here for two reasons: 1) It's used to make sure that the
|
||||
// connections do not outlive the service. 2) Our custom collating functions
|
||||
// call its localeCompareStrings() method.
|
||||
nsRefPtr<Service> mStorageService;
|
||||
};
|
||||
|
||||
} // namespace storage
|
||||
|
@ -176,7 +176,7 @@ registerFunctions(sqlite3 *aDB)
|
||||
};
|
||||
|
||||
int rv = SQLITE_OK;
|
||||
for (unsigned i = 0; SQLITE_OK == rv && i < NS_ARRAY_LENGTH(functions); ++i) {
|
||||
for (size_t i = 0; SQLITE_OK == rv && i < NS_ARRAY_LENGTH(functions); ++i) {
|
||||
struct Functions *p = &functions[i];
|
||||
rv = ::sqlite3_create_function(aDB, p->zName, p->nArg, p->enc, p->pContext,
|
||||
p->xFunc, NULL, NULL);
|
||||
|
@ -38,7 +38,7 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _mozStorageSQLFunctions_h_
|
||||
#define _mozStorageUnicodeFunctions_h_
|
||||
#define _mozStorageSQLFunctions_h_
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "nscore.h"
|
||||
|
@ -24,6 +24,7 @@
|
||||
* Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
|
||||
* Brett Wilson <brettw@gmail.com>
|
||||
* Shawn Wilsher <me@shawnwilsher.com>
|
||||
* Drew Willcoxon <adw@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -42,10 +43,12 @@
|
||||
#include "mozStorageService.h"
|
||||
#include "mozStorageConnection.h"
|
||||
#include "prinit.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCollationCID.h"
|
||||
#include "nsEmbedCID.h"
|
||||
#include "mozStoragePrivateHelpers.h"
|
||||
#include "nsILocale.h"
|
||||
#include "nsILocaleService.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
@ -118,6 +121,11 @@ Service::getXPConnect()
|
||||
return xpc.forget();
|
||||
}
|
||||
|
||||
Service::Service()
|
||||
: mMutex("Service::mMutex")
|
||||
{
|
||||
}
|
||||
|
||||
Service::~Service()
|
||||
{
|
||||
// Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but
|
||||
@ -127,7 +135,6 @@ Service::~Service()
|
||||
NS_WARNING("sqlite3 did not shutdown cleanly.");
|
||||
|
||||
gService = nsnull;
|
||||
::PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
void
|
||||
@ -139,9 +146,6 @@ Service::shutdown()
|
||||
nsresult
|
||||
Service::initialize()
|
||||
{
|
||||
mLock = ::PR_NewLock();
|
||||
NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Disable memory allocation statistic collection, improving performance.
|
||||
// This must be done prior to a call to sqlite3_initialize to have any
|
||||
// effect.
|
||||
@ -157,7 +161,7 @@ Service::initialize()
|
||||
return convertResultCode(rc);
|
||||
|
||||
// This makes multiple connections to the same database share the same pager
|
||||
// cache. We do not need to lock here with mLock because this function is
|
||||
// cache. We do not need to lock here with mMutex because this function is
|
||||
// only ever called from Service::GetSingleton, which will only
|
||||
// call this function once, and will not return until this function returns.
|
||||
// (It does not matter where this is called relative to sqlite3_initialize.)
|
||||
@ -177,6 +181,69 @@ Service::initialize()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
Service::localeCompareStrings(const nsAString &aStr1,
|
||||
const nsAString &aStr2,
|
||||
PRInt32 aComparisonStrength)
|
||||
{
|
||||
// The implementation of nsICollation.CompareString() is platform-dependent.
|
||||
// On Linux it's not thread-safe. It may not be on Windows and OS X either,
|
||||
// but it's more difficult to tell. We therefore synchronize this method.
|
||||
MutexAutoLock mutex(mMutex);
|
||||
|
||||
nsICollation *coll = getLocaleCollation();
|
||||
if (!coll) {
|
||||
NS_ERROR("Storage service has no collation");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRInt32 res;
|
||||
nsresult rv = coll->CompareString(aComparisonStrength, aStr1, aStr2, &res);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Collation compare string failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsICollation *
|
||||
Service::getLocaleCollation()
|
||||
{
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
|
||||
if (mLocaleCollation)
|
||||
return mLocaleCollation;
|
||||
|
||||
nsCOMPtr<nsILocaleService> svc(do_GetService(NS_LOCALESERVICE_CONTRACTID));
|
||||
if (!svc) {
|
||||
NS_WARNING("Could not get locale service");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILocale> appLocale;
|
||||
nsresult rv = svc->GetApplicationLocale(getter_AddRefs(appLocale));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Could not get application locale");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICollationFactory> collFact =
|
||||
do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID);
|
||||
if (!collFact) {
|
||||
NS_WARNING("Could not create collation factory");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
rv = collFact->CreateCollation(appLocale, getter_AddRefs(mLocaleCollation));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Could not create collation");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return mLocaleCollation;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageService
|
||||
|
||||
@ -228,7 +295,7 @@ Service::OpenDatabase(nsIFile *aDatabaseFile,
|
||||
NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
MutexAutoLock mutex(mMutex);
|
||||
nsresult rv = msc->initialize(aDatabaseFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
@ -252,7 +319,7 @@ Service::OpenUnsharedDatabase(nsIFile *aDatabaseFile,
|
||||
// without affecting the caches currently in use by other connections.
|
||||
nsresult rv;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
MutexAutoLock mutex(mMutex);
|
||||
int rc = ::sqlite3_enable_shared_cache(0);
|
||||
if (rc != SQLITE_OK)
|
||||
return convertResultCode(rc);
|
||||
|
@ -24,6 +24,7 @@
|
||||
* Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
|
||||
* Brett Wilson <brettw@gmail.com>
|
||||
* Shawn Wilsher <me@shawnwilsher.com>
|
||||
* Drew Willcoxon <adw@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -43,9 +44,10 @@
|
||||
#define _MOZSTORAGESERVICE_H_
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICollation.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "prlock.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
#include "mozIStorageService.h"
|
||||
|
||||
@ -63,6 +65,23 @@ public:
|
||||
*/
|
||||
nsresult initialize();
|
||||
|
||||
/**
|
||||
* Compares two strings using the Service's locale-aware collation.
|
||||
*
|
||||
* @param aStr1
|
||||
* The string to be compared against aStr2.
|
||||
* @param aStr2
|
||||
* The string to be compared against aStr1.
|
||||
* @param aComparisonStrength
|
||||
* The sorting strength, one of the nsICollation constants.
|
||||
* @return aStr1 - aStr2. That is, if aStr1 < aStr2, returns a negative
|
||||
* number. If aStr1 > aStr2, returns a positive number. If
|
||||
* aStr1 == aStr2, returns 0.
|
||||
*/
|
||||
int localeCompareStrings(const nsAString &aStr1,
|
||||
const nsAString &aStr2,
|
||||
PRInt32 aComparisonStrength);
|
||||
|
||||
static Service *getSingleton();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -76,19 +95,39 @@ public:
|
||||
static already_AddRefed<nsIXPConnect> getXPConnect();
|
||||
|
||||
private:
|
||||
Service();
|
||||
virtual ~Service();
|
||||
|
||||
/**
|
||||
* Used for locking around calls when initializing connections so that we
|
||||
* can ensure that the state of sqlite3_enable_shared_cache is sane.
|
||||
* Used for 1) locking around calls when initializing connections so that we
|
||||
* can ensure that the state of sqlite3_enable_shared_cache is sane and 2)
|
||||
* synchronizing access to mLocaleCollation.
|
||||
*/
|
||||
PRLock *mLock;
|
||||
Mutex mMutex;
|
||||
|
||||
/**
|
||||
* Shuts down the storage service, freeing all of the acquired resources.
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* Lazily creates and returns a collation created from the application's
|
||||
* locale that all statements of all Connections of this Service may use.
|
||||
* Since the collation's lifetime is that of the Service and no statement may
|
||||
* execute outside the lifetime of the Service, this method returns a raw
|
||||
* pointer.
|
||||
*/
|
||||
nsICollation *getLocaleCollation();
|
||||
|
||||
/**
|
||||
* Lazily created collation that all statements of all Connections of this
|
||||
* Service may use. The collation is created from the application's locale.
|
||||
*
|
||||
* @note Collation implementations are platform-dependent and in general not
|
||||
* thread-safe. Access to this collation should be synchronized.
|
||||
*/
|
||||
nsCOMPtr<nsICollation> mLocaleCollation;
|
||||
|
||||
nsCOMPtr<nsIFile> mProfileStorageFile;
|
||||
|
||||
static Service *gService;
|
||||
|
174
storage/test/unit/locale_collation.txt
Normal file
174
storage/test/unit/locale_collation.txt
Normal file
@ -0,0 +1,174 @@
|
||||
|
||||
!
|
||||
"
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
)
|
||||
*
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
;
|
||||
<
|
||||
=
|
||||
>
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
[
|
||||
\
|
||||
]
|
||||
^
|
||||
_
|
||||
`
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
{
|
||||
|
|
||||
}
|
||||
~
|
||||
ludwig van beethoven
|
||||
Ludwig van Beethoven
|
||||
Ludwig van beethoven
|
||||
Jane
|
||||
jane
|
||||
JANE
|
||||
jAne
|
||||
jaNe
|
||||
janE
|
||||
JAne
|
||||
JaNe
|
||||
JanE
|
||||
JANe
|
||||
JaNE
|
||||
JAnE
|
||||
jANE
|
||||
Umberto Eco
|
||||
Umberto eco
|
||||
umberto eco
|
||||
umberto Eco
|
||||
UMBERTO ECO
|
||||
ace
|
||||
bash
|
||||
*ace
|
||||
!ace
|
||||
%ace
|
||||
~ace
|
||||
#ace
|
||||
cork
|
||||
denizen
|
||||
[denizen]
|
||||
(denizen)
|
||||
{denizen}
|
||||
/denizen/
|
||||
#denizen#
|
||||
$denizen$
|
||||
@denizen
|
||||
elf
|
||||
full
|
||||
gnome
|
||||
gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Japanese
|
||||
gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Javanese
|
||||
hint
|
||||
Internationalization
|
||||
Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization
|
||||
Zinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizatio
|
||||
n
|
||||
Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalization
|
||||
ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTioninternationalizationinternationalizationinternationalizationinternationalization
|
||||
ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTion
|
||||
jostle
|
||||
kin
|
||||
Laymen
|
||||
lumens
|
||||
Lumens
|
||||
motleycrew
|
||||
motley crew
|
||||
niven's creative talents
|
||||
nivens creative talents
|
||||
opie
|
||||
posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rockies
|
||||
posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rokkies
|
||||
posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the rockies
|
||||
quilt's
|
||||
quilts
|
||||
quilt
|
||||
Rondo
|
||||
street
|
||||
tamale oxidization and iodization in rapid progress
|
||||
tamale oxidization and iodization in rapid Progress
|
||||
until
|
||||
vera
|
||||
Wobble
|
||||
Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoneme
|
||||
Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoname
|
||||
yearn
|
||||
zodiac
|
||||
a
|
||||
å
|
337
storage/test/unit/test_locale_collation.js
Normal file
337
storage/test/unit/test_locale_collation.js
Normal file
@ -0,0 +1,337 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Storage Test Code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Drew Willcoxon <adw@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Bug 499990 - Locale-aware collation
|
||||
*
|
||||
* Tests our custom, locale-aware collating sequences.
|
||||
*/
|
||||
|
||||
// The name of the file containing the strings we'll sort during this test.
|
||||
// The file's data is taken from intl/locale/tests/sort/us-ascii_base.txt and
|
||||
// and intl/locale/tests/sort/us-ascii_sort.txt.
|
||||
const DATA_BASENAME = "locale_collation.txt";
|
||||
|
||||
// The test data from DATA_BASENAME is read into this array.
|
||||
var gStrings;
|
||||
|
||||
// A collation created from the application's locale. Used by localeCompare().
|
||||
var gLocaleCollation;
|
||||
|
||||
// A connection to our in-memory UTF-16-encoded database.
|
||||
var gUtf16Conn;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//// Helper Functions
|
||||
|
||||
/**
|
||||
* Since we create a UTF-16 database we have to clean it up, in addition to
|
||||
* the normal cleanup of Storage tests.
|
||||
*/
|
||||
function cleanupLocaleTests()
|
||||
{
|
||||
print("-- Cleaning up test_locale_collation.js suite.");
|
||||
gUtf16Conn.close();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test database similar to the default one created in
|
||||
* head_storage.js, except that this one uses UTF-16 encoding.
|
||||
*
|
||||
* @return A connection to the database.
|
||||
*/
|
||||
function createUtf16Database()
|
||||
{
|
||||
print("Creating the in-memory UTF-16-encoded database.");
|
||||
let conn = getService().openSpecialDatabase("memory");
|
||||
conn.executeSimpleSQL("PRAGMA encoding = 'UTF-16'");
|
||||
|
||||
print("Make sure the encoding was set correctly and is now UTF-16.");
|
||||
let stmt = conn.createStatement("PRAGMA encoding");
|
||||
do_check_true(stmt.executeStep());
|
||||
let enc = stmt.getString(0);
|
||||
stmt.finalize();
|
||||
|
||||
// The value returned will actually be UTF-16le or UTF-16be.
|
||||
do_check_true(enc === "UTF-16le" || enc === "UTF-16be");
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares aActual to aExpected, ensuring that the numbers and orderings of
|
||||
* the two arrays' elements are the same.
|
||||
*
|
||||
* @param aActual
|
||||
* An array of strings retrieved from the database.
|
||||
* @param aExpected
|
||||
* An array of strings to which aActual should be equivalent.
|
||||
*/
|
||||
function ensureResultsAreCorrect(aActual, aExpected)
|
||||
{
|
||||
print("Actual results: " + aActual);
|
||||
print("Expected results: " + aExpected);
|
||||
|
||||
do_check_eq(aActual.length, aExpected.length);
|
||||
for (let i = 0; i < aActual.length; i++)
|
||||
do_check_eq(aActual[i], aExpected[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously SELECTs all rows from the test table of the given database
|
||||
* using the given collation.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The rows are
|
||||
* ordered by this collation.
|
||||
* @param aConn
|
||||
* A connection to either the UTF-8 database or the UTF-16 database.
|
||||
* @return The resulting strings in an array.
|
||||
*/
|
||||
function getResults(aCollation, aConn)
|
||||
{
|
||||
let results = [];
|
||||
let stmt = aConn.createStatement("SELECT t FROM test " +
|
||||
"ORDER BY t COLLATE " + aCollation + " ASC");
|
||||
while (stmt.executeStep())
|
||||
results.push(stmt.row.t);
|
||||
stmt.finalize();
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts strings into our test table of the given database in the order given.
|
||||
*
|
||||
* @param aStrings
|
||||
* An array of strings.
|
||||
* @param aConn
|
||||
* A connection to either the UTF-8 database or the UTF-16 database.
|
||||
*/
|
||||
function initTableWithStrings(aStrings, aConn)
|
||||
{
|
||||
print("Initializing test table.");
|
||||
|
||||
aConn.executeSimpleSQL("DROP TABLE IF EXISTS test");
|
||||
aConn.createTable("test", "t TEXT");
|
||||
let stmt = aConn.createStatement("INSERT INTO test (t) VALUES (:t)");
|
||||
aStrings.forEach(function (str) {
|
||||
stmt.params.t = str;
|
||||
stmt.execute();
|
||||
stmt.reset();
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorting function suitable for passing to Array.prototype.sort().
|
||||
* The returned function uses the application's locale to compare strings.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The sorting
|
||||
* strength is computed from this value.
|
||||
* @return A function to use as a sorting callback.
|
||||
*/
|
||||
function localeCompare(aCollation)
|
||||
{
|
||||
var strength;
|
||||
|
||||
switch (aCollation) {
|
||||
case "locale":
|
||||
strength = Ci.nsICollation.kCollationCaseInSensitive;
|
||||
break;
|
||||
case "locale_case_sensitive":
|
||||
strength = Ci.nsICollation.kCollationAccentInsenstive;
|
||||
break;
|
||||
case "locale_accent_sensitive":
|
||||
strength = Ci.nsICollation.kCollationCaseInsensitiveAscii;
|
||||
break;
|
||||
case "locale_case_accent_sensitive":
|
||||
strength = Ci.nsICollation.kCollationCaseSensitive;
|
||||
break;
|
||||
default:
|
||||
do_throw("Error in test: unknown collation '" + aCollation + "'");
|
||||
break;
|
||||
}
|
||||
return function (aStr1, aStr2)
|
||||
gLocaleCollation.compareString(strength, aStr1, aStr2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the test data from the file DATA_BASENAME and returns it as an array
|
||||
* of strings.
|
||||
*
|
||||
* @return The test data as an array of strings.
|
||||
*/
|
||||
function readTestData()
|
||||
{
|
||||
print("Reading in test data.");
|
||||
|
||||
let file = do_get_file(DATA_BASENAME);
|
||||
|
||||
let istream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
istream.init(file, -1, -1, 0);
|
||||
istream.QueryInterface(Components.interfaces.nsILineInputStream);
|
||||
|
||||
let line = {};
|
||||
let lines = [];
|
||||
while (istream.readLine(line))
|
||||
lines.push(line.value);
|
||||
istream.close();
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the results from the given database using the given collation and
|
||||
* ensures that they match gStrings sorted by the same collation.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The rows from the
|
||||
* database and the expected results are ordered by this collation.
|
||||
* @param aConn
|
||||
* A connection to either the UTF-8 database or the UTF-16 database.
|
||||
*/
|
||||
function runTest(aCollation, aConn)
|
||||
{
|
||||
ensureResultsAreCorrect(getResults(aCollation, aConn),
|
||||
gStrings.slice(0).sort(localeCompare(aCollation)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the results from the UTF-8 database using the given collation and
|
||||
* ensures that they match gStrings sorted by the same collation.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The rows from the
|
||||
* database and the expected results are ordered by this collation.
|
||||
*/
|
||||
function runUtf8Test(aCollation)
|
||||
{
|
||||
runTest(aCollation, getOpenedDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the results from the UTF-16 database using the given collation and
|
||||
* ensures that they match gStrings sorted by the same collation.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The rows from the
|
||||
* database and the expected results are ordered by this collation.
|
||||
*/
|
||||
function runUtf16Test(aCollation)
|
||||
{
|
||||
runTest(aCollation, gUtf16Conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the test suite.
|
||||
*/
|
||||
function setup()
|
||||
{
|
||||
print("-- Setting up the test_locale_collation.js suite.");
|
||||
|
||||
gStrings = readTestData();
|
||||
|
||||
initTableWithStrings(gStrings, getOpenedDatabase());
|
||||
|
||||
gUtf16Conn = createUtf16Database();
|
||||
initTableWithStrings(gStrings, gUtf16Conn);
|
||||
|
||||
let localeSvc = Cc["@mozilla.org/intl/nslocaleservice;1"].
|
||||
getService(Ci.nsILocaleService);
|
||||
let collFact = Cc["@mozilla.org/intl/collation-factory;1"].
|
||||
createInstance(Ci.nsICollationFactory);
|
||||
gLocaleCollation = collFact.CreateCollation(localeSvc.getApplicationLocale());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//// Test Runs
|
||||
|
||||
let gTests = [
|
||||
{
|
||||
desc: "Case and accent sensitive UTF-8",
|
||||
run: function () runUtf8Test("locale_case_accent_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case sensitive, accent insensitive UTF-8",
|
||||
run: function () runUtf8Test("locale_case_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case insensitive, accent sensitive UTF-8",
|
||||
run: function () runUtf8Test("locale_accent_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case and accent insensitive UTF-8",
|
||||
run: function () runUtf8Test("locale")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case and accent sensitive UTF-16",
|
||||
run: function () runUtf16Test("locale_case_accent_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case sensitive, accent insensitive UTF-16",
|
||||
run: function () runUtf16Test("locale_case_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case insensitive, accent sensitive UTF-16",
|
||||
run: function () runUtf16Test("locale_accent_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case and accent insensitive UTF-16",
|
||||
run: function () runUtf16Test("locale")
|
||||
},
|
||||
];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
gTests.forEach(function (test) {
|
||||
print("-- Running test: " + test.desc);
|
||||
test.run();
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user