Back to index

lightning-sunbird  0.9+nobinonly
mozSqlConnectionPgsql.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 "prprf.h"
00037 #include "nsReadableUtils.h"
00038 #include "mozSqlConnectionPgsql.h"
00039 #include "mozSqlResultPgsql.h"
00040 
00041 mozSqlConnectionPgsql::mozSqlConnectionPgsql()
00042   : mConnection(nsnull)
00043 {
00044 }
00045 
00046 mozSqlConnectionPgsql::~mozSqlConnectionPgsql()
00047 {
00048   if (mConnection)
00049     PQfinish(mConnection);
00050 }
00051 
00052 NS_IMPL_ADDREF_INHERITED(mozSqlConnectionPgsql, mozSqlConnection)
00053 NS_IMPL_RELEASE_INHERITED(mozSqlConnectionPgsql, mozSqlConnection)
00054 
00055 // QueryInterface
00056 NS_INTERFACE_MAP_BEGIN(mozSqlConnectionPgsql)
00057   NS_INTERFACE_MAP_ENTRY(mozISqlConnectionPgsql)
00058 NS_INTERFACE_MAP_END_INHERITING(mozSqlConnection)
00059 
00060 NS_IMETHODIMP
00061 mozSqlConnectionPgsql::Init(const nsAString & aHost, PRInt32 aPort,
00062                             const nsAString & aDatabase, const nsAString & aUsername,
00063                             const nsAString & aPassword)
00064 {
00065   if (mConnection)
00066     return NS_OK;
00067 
00068   if (aPort == -1)
00069     aPort = 5432;
00070   char port[11];
00071   char options[] = "";
00072   char tty[] = "";
00073   PR_snprintf(port, 11, "%d", aPort);
00074 
00075   mConnection = PQsetdbLogin(NS_ConvertUCS2toUTF8(aHost).get(),
00076                              port, options, tty,
00077                              NS_ConvertUCS2toUTF8(aDatabase).get(),
00078                              NS_ConvertUCS2toUTF8(aUsername).get(),
00079                              NS_ConvertUCS2toUTF8(aPassword).get());
00080 
00081   return Setup();
00082 }
00083 
00084 NS_IMETHODIMP
00085 mozSqlConnectionPgsql::GetPrimaryKeys(const nsAString& aSchema, const nsAString& aTable, mozISqlResult** _retval)
00086 {
00087   nsAutoString select;
00088   nsAutoString from;
00089   nsAutoString where;
00090   if (mVersion >= SERVER_VERSION(7,3,0)) {
00091     select.AssignLiteral("SELECT n.nspname AS TABLE_SCHEM, ");
00092     from.AssignLiteral(" FROM pg_catalog.pg_namespace n, pg_catalog.pg_class ct, pg_catalog.pg_class ci, pg_catalog.pg_attribute a, pg_catalog.pg_index i");
00093     where.AssignLiteral(" AND ct.relnamespace = n.oid ");
00094     if (!aSchema.IsEmpty()) {
00095       where.Append(NS_LITERAL_STRING(" AND n.nspname = '") + aSchema);
00096       where.Append(PRUnichar('\''));
00097     }
00098   }
00099   else {
00100     select.AssignLiteral("SELECT NULL AS TABLE_SCHEM, ");
00101     from.AssignLiteral(" FROM pg_class ct, pg_class ci, pg_attribute a, pg_index i ");
00102   }
00103 
00104   if (!aTable.IsEmpty()) {
00105     where.Append(NS_LITERAL_STRING(" AND ct.relname = '") + aTable);
00106     where.Append(PRUnichar('\''));
00107   }
00108 
00109   NS_NAMED_LITERAL_STRING(select2, " ct.relname AS TABLE_NAME, a.attname AS COLUMN_NAME, a.attnum AS KEY_SEQ, ci.relname AS PK_NAME ");
00110   NS_NAMED_LITERAL_STRING(where2, " WHERE ct.oid=i.indrelid AND ci.oid=i.indexrelid AND a.attrelid=ci.oid AND i.indisprimary ");
00111   NS_NAMED_LITERAL_STRING(order2, " ORDER BY table_name, pk_name, key_seq");
00112 
00113   return RealExec(select + select2 + from + where2 + where + order2, _retval, nsnull);
00114 }
00115 
00116 nsresult
00117 mozSqlConnectionPgsql::Setup()
00118 {
00119   if (PQstatus(mConnection) == CONNECTION_BAD) {
00120     CopyUTF8toUTF16(PQerrorMessage(mConnection), mErrorMessage);
00121     mConnection = nsnull;
00122     return NS_ERROR_FAILURE;
00123   }
00124 
00125   PQsetClientEncoding(mConnection, "UNICODE");
00126 
00127 /*
00128   PGresult* result = PQexec(mConnection, "SET DATESTYLE TO US");
00129   PRInt32 stat = PQresultStatus(result);
00130   if (stat != PGRES_COMMAND_OK) {
00131     CopyUTF8toUTF16(PQresultErrorMessage(result), mErrorMessage);
00132     PQfinish(mConnection);
00133     mConnection = nsnull;
00134     return NS_ERROR_FAILURE;
00135   }
00136 */
00137 
00138   PGresult* result = PQexec(mConnection, "select version()");
00139   PRInt32 stat = PQresultStatus(result);
00140   if (stat != PGRES_TUPLES_OK) {
00141     CopyUTF8toUTF16(PQresultErrorMessage(result), mErrorMessage);
00142     return NS_ERROR_FAILURE;
00143   }
00144   char* version = PQgetvalue(result, 0, 0);
00145   NS_ConvertUTF8toUCS2 buffer(version);
00146   nsAString::const_iterator start, end, iter;
00147   buffer.BeginReading(iter);
00148   buffer.EndReading(end);
00149   while (iter != end && !nsCRT::IsAsciiSpace(*iter))
00150     ++iter;
00151   while (iter != end && nsCRT::IsAsciiSpace(*iter))
00152     ++iter;
00153   start = iter;
00154   while (iter != end && !nsCRT::IsAsciiSpace(*iter))
00155     ++iter;
00156   mServerVersion = Substring(start,iter);
00157 
00158   PRInt32 numbers[3] = {0,0,0};
00159   mServerVersion.BeginReading(iter);
00160   mServerVersion.EndReading(end);
00161   for (PRInt32 i = 0; i < 3; i++) {
00162     start = iter;
00163     while (iter != end && *iter != PRUnichar('.'))
00164       ++iter;
00165     nsAutoString v(Substring(start,iter));
00166     PRInt32 err;
00167     numbers[i] = v.ToInteger(&err);
00168     while (iter != end && *iter == PRUnichar('.'))
00169       ++iter;
00170   }
00171   mVersion = SERVER_VERSION(numbers[0], numbers[1], numbers[2]);
00172 
00173   return NS_OK;
00174 }
00175 
00176 nsresult
00177 mozSqlConnectionPgsql::RealExec(const nsAString& aQuery,
00178                                 mozISqlResult** aResult, PRInt32* aAffectedRows)
00179 {
00180   if (! mConnection)
00181     return NS_ERROR_NOT_INITIALIZED;
00182 
00183   PGresult* r;
00184   r = PQexec(mConnection, NS_ConvertUCS2toUTF8(aQuery).get());
00185   PRInt32 stat = PQresultStatus(r);
00186 
00187   if (PQstatus(mConnection) == CONNECTION_BAD) {
00188     PQreset(mConnection);
00189     nsresult rv = Setup();
00190     if (NS_FAILED(rv))
00191       return rv;
00192     r = PQexec(mConnection, NS_ConvertUCS2toUTF8(aQuery).get());
00193     stat = PQresultStatus(r);
00194   }
00195 
00196   if (stat == PGRES_TUPLES_OK) {
00197     if (!aResult)
00198       return NS_ERROR_NULL_POINTER;
00199 
00200     static char select1[] = "select t.oid, case when t.typbasetype = 0 then t.typname else (select t2.typname from pg_type t2 where t2.oid=t.typbasetype) end as typname from pg_type t where t.oid in (";
00201     static char select2[] = "select oid, typname from pg_type where oid in (";
00202     char* select;
00203     if (mVersion >= SERVER_VERSION(7,3,0))
00204       select = select1;
00205     else
00206       select = select2;
00207     PRInt32 columnCount = PQnfields(r);
00208     char* query = (char*)malloc(strlen(select) + columnCount * 11 + 2);
00209     strcpy(query, select);
00210     for (PRInt32 i = 0; i < columnCount; i++) {
00211       PRInt32 oid = PQftype(r, i);
00212       char oidStr[11];
00213       if (i)
00214         sprintf(oidStr, ",%d", oid);
00215       else
00216         sprintf(oidStr, "%d", oid);
00217       strcat(query, oidStr);
00218     }
00219     strcat(query, ")");
00220     PGresult* types = PQexec(mConnection, query);
00221     free(query);
00222     stat = PQresultStatus(types);
00223     if (stat != PGRES_TUPLES_OK) {
00224       CopyUTF8toUTF16(PQresultErrorMessage(types), mErrorMessage);
00225       return NS_ERROR_FAILURE;
00226     }
00227 
00228     if (*aResult) {
00229       ((mozSqlResultPgsql*)*aResult)->SetResult(r, types);
00230       nsresult rv = ((mozSqlResult*)*aResult)->Rebuild();
00231       if (NS_FAILED(rv))
00232         return rv;
00233       NS_ADDREF(*aResult);
00234     }
00235     else {
00236       mozSqlResult* result = new mozSqlResultPgsql(this, aQuery);
00237       if (! result)
00238         return NS_ERROR_OUT_OF_MEMORY;
00239       ((mozSqlResultPgsql*)result)->SetResult(r, types);
00240       nsresult rv = result->Init();
00241       if (NS_FAILED(rv))
00242         return rv;
00243       NS_ADDREF(*aResult = result);
00244     }
00245   }
00246   else if (stat == PGRES_COMMAND_OK) {
00247     if (!aAffectedRows)
00248       return NS_ERROR_NULL_POINTER;
00249     PR_sscanf(PQcmdTuples(r), "%d", aAffectedRows);
00250     mLastID = PQoidValue(r);
00251   }
00252   else {
00253     CopyUTF8toUTF16(PQresultErrorMessage(r), mErrorMessage);
00254     return NS_ERROR_FAILURE;
00255   }
00256 
00257   return NS_OK;
00258 }
00259 
00260 nsresult
00261 mozSqlConnectionPgsql::CancelExec()
00262 {
00263   if (!PQrequestCancel(mConnection)) {
00264     CopyUTF8toUTF16(PQerrorMessage(mConnection), mErrorMessage);
00265     return NS_ERROR_FAILURE;
00266   }
00267 
00268   return NS_OK;
00269 }
00270 
00271 nsresult
00272 mozSqlConnectionPgsql::GetIDName(nsAString& aIDName)
00273 {
00274   aIDName.AssignLiteral("OID");
00275   return NS_OK;
00276 }