Back to index

lightning-sunbird  0.9+nobinonly
mozSqlConnection.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is Jan Varga
00017  * Portions created by the Initial Developer are Copyright (C) 2003
00018  * the Initial Developer. All Rights Reserved.
00019  *
00020  * Contributor(s):
00021  *
00022  * Alternatively, the contents of this file may be used under the terms of
00023  * either the GNU General Public License Version 2 or later (the "GPL"), or
00024  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00025  * in which case the provisions of the GPL or the LGPL are applicable instead
00026  * of those above. If you wish to allow use of your version of this file only
00027  * under the terms of either the GPL or the LGPL, and not to allow others to
00028  * use your version of this file under the terms of the MPL, indicate your
00029  * decision by deleting the provisions above and replace them with the notice
00030  * and other provisions required by the GPL or the LGPL. If you do not delete
00031  * the provisions above, a recipient may use your version of this file under
00032  * the terms of any one of the MPL, the GPL or the LGPL.
00033  *
00034  * ***** END LICENSE BLOCK ***** */
00035 
00036 #include "nsIProxyObjectManager.h"
00037 #include "mozSqlRequest.h"
00038 #include "mozSqlConnection.h"
00039 
00040 mozSqlConnection::mozSqlConnection()
00041   : mLock(nsnull),
00042     mCondVar(nsnull),
00043     mThread(nsnull),
00044     mShutdown(PR_FALSE),
00045     mWaiting(PR_FALSE)
00046 {
00047   mExecLock = PR_NewLock();
00048 }
00049 
00050 mozSqlConnection::~mozSqlConnection()
00051 {
00052   mRequests.Clear();
00053 
00054   if (mCondVar)
00055     PR_DestroyCondVar(mCondVar);
00056   PR_DestroyLock(mExecLock);
00057   if (mLock)
00058     PR_DestroyLock(mLock);
00059 }
00060 
00061 // We require a special implementation of Release, which knows about
00062 // a circular strong reference
00063 NS_IMPL_THREADSAFE_ADDREF(mozSqlConnection)
00064 NS_IMPL_THREADSAFE_QUERY_INTERFACE3(mozSqlConnection,
00065                                     mozISqlConnection,
00066                                     nsIRunnable,
00067                                 nsISupportsWeakReference)
00068 NS_IMETHODIMP_(nsrefcnt)
00069 mozSqlConnection::Release()
00070 {
00071   PR_AtomicDecrement((PRInt32*)&mRefCnt);
00072   // Delete if the last reference is our strong circular reference.
00073   if (mThread && mRefCnt == 1) {
00074     PR_Lock(mLock);
00075     mRequests.Clear();
00076     mShutdown = PR_TRUE;
00077     if (mWaiting)
00078       PR_NotifyCondVar(mCondVar);
00079     else
00080       CancelExec();
00081     PR_Unlock(mLock);
00082     return 0;
00083   }
00084   else if (mRefCnt == 0) {
00085     delete this;
00086     return 0;
00087   }
00088   return mRefCnt;
00089 }
00090 
00091 NS_IMETHODIMP
00092 mozSqlConnection::GetServerVersion(nsAString& aServerVersion) 
00093 {
00094   aServerVersion = mServerVersion;
00095   return NS_OK;
00096 }
00097 
00098 NS_IMETHODIMP
00099 mozSqlConnection::GetErrorMessage(nsAString& aErrorMessage) 
00100 {
00101   aErrorMessage = mErrorMessage;
00102   return NS_OK;
00103 }
00104 
00105 NS_IMETHODIMP
00106 mozSqlConnection::GetLastID(PRInt32* aLastID) 
00107 {
00108   *aLastID = mLastID;
00109   return NS_OK;
00110 }
00111 
00112 NS_IMETHODIMP
00113 mozSqlConnection::Init(const nsAString & aHost, PRInt32 aPort,
00114                        const nsAString & aDatabase, const nsAString & aUsername,
00115                        const nsAString & aPassword)
00116 {
00117   // descendants have to implement this themselves
00118   return NS_ERROR_NOT_IMPLEMENTED;
00119 }
00120 
00121 NS_IMETHODIMP
00122 mozSqlConnection::ExecuteQuery(const nsAString& aQuery, mozISqlResult** _retval)
00123 {
00124   PR_Lock(mExecLock);
00125   nsresult rv = RealExec(aQuery, _retval, nsnull);
00126   PR_Unlock(mExecLock);
00127   return rv;
00128 }
00129 
00130 NS_IMETHODIMP
00131 mozSqlConnection::ExecuteUpdate(const nsAString& aUpdate, PRInt32* _retval)
00132 {
00133   PR_Lock(mExecLock);
00134   nsresult rv = RealExec(aUpdate, nsnull, _retval);
00135   PR_Unlock(mExecLock);
00136   return rv;
00137 }
00138 
00139 NS_IMETHODIMP
00140 mozSqlConnection::AsyncExecuteQuery(const nsAString& aQuery, nsISupports* aCtxt, 
00141                                     mozISqlRequestObserver* aObserver,
00142                                     mozISqlRequest **_retval)
00143 {
00144   if (!mThread) {
00145     mLock = PR_NewLock();
00146     mCondVar = PR_NewCondVar(mLock);
00147     NS_NewThread(getter_AddRefs(mThread), this, 0, PR_UNJOINABLE_THREAD);
00148   }
00149 
00150   mozSqlRequest* request = new mozSqlRequest(this);
00151   if (! request)
00152     return NS_ERROR_OUT_OF_MEMORY;
00153 
00154   request->mIsQuery = PR_TRUE;
00155   request->mQuery = aQuery;
00156   request->mCtxt = aCtxt;
00157 
00158   nsresult rv = NS_GetProxyForObject(NS_CURRENT_EVENTQ,
00159                                      NS_GET_IID(mozISqlRequestObserver),
00160                                      aObserver,
00161                                      PROXY_SYNC | PROXY_ALWAYS,
00162                                      getter_AddRefs(request->mObserver));
00163   if (NS_FAILED(rv))
00164     return rv;
00165 
00166   PR_Lock(mLock);
00167   mRequests.AppendObject(request);
00168   if (mWaiting && mRequests.Count() == 1)
00169     PR_NotifyCondVar(mCondVar);
00170   PR_Unlock(mLock);
00171 
00172   NS_ADDREF(*_retval = request);
00173 
00174   return NS_OK;
00175 }
00176 
00177 NS_IMETHODIMP
00178 mozSqlConnection::AsyncExecuteUpdate(const nsAString& aQuery, nsISupports* aCtxt, 
00179                                      mozISqlRequestObserver* aObserver,
00180                                      mozISqlRequest **_retval)
00181 {
00182   return NS_OK;
00183 }
00184 
00185 NS_IMETHODIMP
00186 mozSqlConnection::BeginTransaction()
00187 {
00188   PRInt32 affectedRows;
00189   return ExecuteUpdate(NS_LITERAL_STRING("begin"), &affectedRows);
00190 }
00191 
00192 NS_IMETHODIMP
00193 mozSqlConnection::CommitTransaction()
00194 {
00195   PRInt32 affectedRows;
00196   return ExecuteUpdate(NS_LITERAL_STRING("commit"), &affectedRows);
00197 }
00198 
00199 NS_IMETHODIMP
00200 mozSqlConnection::RollbackTransaction()
00201 {
00202   PRInt32 affectedRows;
00203   return ExecuteUpdate(NS_LITERAL_STRING("rollback"), &affectedRows);
00204 }
00205 
00206 NS_IMETHODIMP
00207 mozSqlConnection::GetPrimaryKeys(const nsAString& aSchema, const nsAString& aTable, mozISqlResult** _retval)
00208 {
00209   // descendants have to implement this themselves
00210   return NS_ERROR_NOT_IMPLEMENTED;
00211 }
00212 
00213 NS_IMETHODIMP
00214 mozSqlConnection::Run()
00215 {
00216   PR_Lock(mLock);
00217   while(!mShutdown) {
00218 
00219     while (mRequests.Count()) {
00220       mCurrentRequest = mRequests[0];
00221       mRequests.RemoveObjectAt(0);
00222 
00223 
00224       mozSqlRequest* r = (mozSqlRequest*)mCurrentRequest.get();
00225 
00226       PR_Unlock(mLock);
00227       r->mObserver->OnStartRequest(mCurrentRequest, r->mCtxt);
00228       PR_Lock(mLock);
00229 
00230       r->mStatus = mozISqlRequest::STATUS_EXECUTED;
00231 
00232       PR_Unlock(mLock);
00233 
00234       nsresult rv = ExecuteQuery(r->mQuery, getter_AddRefs(r->mResult));
00235 
00236       PR_Lock(mLock);
00237 
00238       if (NS_SUCCEEDED(rv))
00239         r->mStatus = mozISqlRequest::STATUS_COMPLETE;
00240       else {
00241         r->mStatus = mozISqlRequest::STATUS_ERROR;
00242        GetErrorMessage(r->mErrorMessage);
00243       }
00244         
00245       PR_Unlock(mLock);
00246       r->mObserver->OnStopRequest(mCurrentRequest, r->mCtxt);
00247       PR_Lock(mLock);
00248 
00249       mCurrentRequest = nsnull;
00250 
00251     }
00252     
00253     mWaiting = PR_TRUE;
00254     PR_WaitCondVar(mCondVar, PR_INTERVAL_NO_TIMEOUT);
00255     mWaiting = PR_FALSE;
00256   }
00257   PR_Unlock(mLock);
00258 
00259   return NS_OK;
00260 }
00261 
00262 nsresult
00263 mozSqlConnection::CancelRequest(mozISqlRequest* aRequest)
00264 {
00265   PR_Lock(mLock);
00266   if (mCurrentRequest == aRequest)
00267     CancelExec();
00268   else {
00269     if (mRequests.RemoveObject(aRequest))
00270       ((mozSqlRequest*)aRequest)->mStatus = mozISqlRequest::STATUS_CANCELLED;
00271   }
00272   PR_Unlock(mLock);
00273 
00274   return NS_OK;
00275 }