/* -*- 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.org 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): * Shawn Wilsher (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 #include "nsString.h" #include "mozStorageError.h" #include "mozStoragePrivateHelpers.h" #include "mozStorageBindingParams.h" #include "mozStorageBindingParamsArray.h" #include "Variant.h" namespace mozilla { namespace storage { //////////////////////////////////////////////////////////////////////////////// //// Local Helper Objects namespace { struct BindingColumnData { BindingColumnData(sqlite3_stmt *aStmt, int aColumn) : stmt(aStmt) , column(aColumn) { } sqlite3_stmt *stmt; int column; }; } // anonymous namespace //////////////////////////////////////////////////////////////////////////////// //// sqlite3_stmt Specialization Functions (varaintToSQLite3T) template < > int sqlite3_T_int(BindingColumnData aData, int aValue) { return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue); } template < > int sqlite3_T_int64(BindingColumnData aData, sqlite3_int64 aValue) { return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue); } template < > int sqlite3_T_double(BindingColumnData aData, double aValue) { return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue); } template < > int sqlite3_T_text16(BindingColumnData aData, nsString aValue) { return ::sqlite3_bind_text16(aData.stmt, aData.column + 1, PromiseFlatString(aValue).get(), aValue.Length() * 2, // Length in bytes! SQLITE_TRANSIENT); } template < > int sqlite3_T_null(BindingColumnData aData) { return ::sqlite3_bind_null(aData.stmt, aData.column + 1); } template < > int sqlite3_T_blob(BindingColumnData aData, const void *aBlob, int aSize) { return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize, NS_Free); } //////////////////////////////////////////////////////////////////////////////// //// BindingParams BindingParams::BindingParams(BindingParamsArray *aOwningArray, Statement *aOwningStatement) : mOwningArray(aOwningArray) , mOwningStatement(aOwningStatement) , mLocked(false) { (void)mOwningStatement->GetParameterCount(&mParamCount); (void)mParameters.SetCapacity(mParamCount); } void BindingParams::lock() { NS_ASSERTION(mLocked == false, "Parameters have already been locked!"); mLocked = true; // We no longer need to hold a reference to our statement or our owning array. // The array owns us at this point, and it will own a reference to the // statement. mOwningStatement = nsnull; mOwningArray = nsnull; } void BindingParams::unlock() { NS_ASSERTION(mLocked == true, "Parameters were not yet locked!"); mLocked = false; } const BindingParamsArray * BindingParams::getOwner() const { return mOwningArray; } already_AddRefed BindingParams::bind(sqlite3_stmt *aStatement) { // Iterate through all of our stored data, and bind it. for (PRInt32 i = 0; i < mParameters.Count(); i++) { int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]); if (rc != SQLITE_OK) { // We had an error while trying to bind. Now we need to create an error // object with the right message. Note that we special case // SQLITE_MISMATCH, but otherwise get the message from SQLite. const char *msg = "Could not covert nsIVariant to SQLite type."; if (rc != SQLITE_MISMATCH) msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement)); nsCOMPtr err(new Error(rc, msg)); return err.forget(); } } // No error occurred, so return null! return nsnull; } NS_IMPL_THREADSAFE_ISUPPORTS1( BindingParams, mozIStorageBindingParams ) /////////////////////////////////////////////////////////////////////////////// //// mozIStorageBindingParams NS_IMETHODIMP BindingParams::BindByName(const nsACString &aName, nsIVariant *aValue) { NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); // Get the column index that we need to store this at. PRUint32 index; nsresult rv = mOwningStatement->GetParameterIndex(aName, &index); NS_ENSURE_SUCCESS(rv, rv); return BindByIndex(index, aValue); } NS_IMETHODIMP BindingParams::BindUTF8StringByName(const nsACString &aName, const nsACString &aValue) { nsCOMPtr value(new UTF8TextVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByName(aName, value); } NS_IMETHODIMP BindingParams::BindStringByName(const nsACString &aName, const nsAString &aValue) { nsCOMPtr value(new TextVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByName(aName, value); } NS_IMETHODIMP BindingParams::BindDoubleByName(const nsACString &aName, double aValue) { nsCOMPtr value(new FloatVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByName(aName, value); } NS_IMETHODIMP BindingParams::BindInt32ByName(const nsACString &aName, PRInt32 aValue) { nsCOMPtr value(new IntegerVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByName(aName, value); } NS_IMETHODIMP BindingParams::BindInt64ByName(const nsACString &aName, PRInt64 aValue) { nsCOMPtr value(new IntegerVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByName(aName, value); } NS_IMETHODIMP BindingParams::BindNullByName(const nsACString &aName) { nsCOMPtr value(new NullVariant()); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByName(aName, value); } NS_IMETHODIMP BindingParams::BindBlobByName(const nsACString &aName, const PRUint8 *aValue, PRUint32 aValueSize) { NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); std::pair data( static_cast(aValue), int(aValueSize) ); nsCOMPtr value(new BlobVariant(data)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByName(aName, value); } NS_IMETHODIMP BindingParams::BindByIndex(PRUint32 aIndex, nsIVariant *aValue) { NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED); ENSURE_INDEX_VALUE(aIndex, mParamCount); // Store the variant for later use. NS_ENSURE_TRUE(mParameters.ReplaceObjectAt(aValue, aIndex), NS_ERROR_OUT_OF_MEMORY); return NS_OK; } NS_IMETHODIMP BindingParams::BindUTF8StringByIndex(PRUint32 aIndex, const nsACString &aValue) { nsCOMPtr value(new UTF8TextVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByIndex(aIndex, value); } NS_IMETHODIMP BindingParams::BindStringByIndex(PRUint32 aIndex, const nsAString &aValue) { nsCOMPtr value(new TextVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByIndex(aIndex, value); } NS_IMETHODIMP BindingParams::BindDoubleByIndex(PRUint32 aIndex, double aValue) { nsCOMPtr value(new FloatVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByIndex(aIndex, value); } NS_IMETHODIMP BindingParams::BindInt32ByIndex(PRUint32 aIndex, PRInt32 aValue) { nsCOMPtr value(new IntegerVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByIndex(aIndex, value); } NS_IMETHODIMP BindingParams::BindInt64ByIndex(PRUint32 aIndex, PRInt64 aValue) { nsCOMPtr value(new IntegerVariant(aValue)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByIndex(aIndex, value); } NS_IMETHODIMP BindingParams::BindNullByIndex(PRUint32 aIndex) { nsCOMPtr value(new NullVariant()); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByIndex(aIndex, value); } NS_IMETHODIMP BindingParams::BindBlobByIndex(PRUint32 aIndex, const PRUint8 *aValue, PRUint32 aValueSize) { NS_ENSURE_ARG_MAX(aValueSize, INT_MAX); std::pair data( static_cast(aValue), int(aValueSize) ); nsCOMPtr value(new BlobVariant(data)); NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); return BindByIndex(aIndex, value); } } // namespace storage } // namespace mozilla