/* ***** 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 Jan Varga * Portions created by the Initial Developer are Copyright (C) 2003 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * 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 "prprf.h" #include "nsReadableUtils.h" #include "mozSqlConnectionPgsql.h" #include "mozSqlResultPgsql.h" mozSqlConnectionPgsql::mozSqlConnectionPgsql() : mConnection(nsnull) { } mozSqlConnectionPgsql::~mozSqlConnectionPgsql() { if (mConnection) PQfinish(mConnection); } NS_IMPL_ADDREF_INHERITED(mozSqlConnectionPgsql, mozSqlConnection) NS_IMPL_RELEASE_INHERITED(mozSqlConnectionPgsql, mozSqlConnection) // QueryInterface NS_INTERFACE_MAP_BEGIN(mozSqlConnectionPgsql) NS_INTERFACE_MAP_ENTRY(mozISqlConnectionPgsql) NS_INTERFACE_MAP_END_INHERITING(mozSqlConnection) NS_IMETHODIMP mozSqlConnectionPgsql::Init(const nsAString & aHost, PRInt32 aPort, const nsAString & aDatabase, const nsAString & aUsername, const nsAString & aPassword) { if (mConnection) return NS_OK; if (aPort == -1) aPort = 5432; char port[11]; char options[] = ""; char tty[] = ""; PR_snprintf(port, 11, "%d", aPort); mConnection = PQsetdbLogin(NS_ConvertUTF16toUTF8(aHost).get(), port, options, tty, NS_ConvertUTF16toUTF8(aDatabase).get(), NS_ConvertUTF16toUTF8(aUsername).get(), NS_ConvertUTF16toUTF8(aPassword).get()); return Setup(); } NS_IMETHODIMP mozSqlConnectionPgsql::GetPrimaryKeys(const nsAString& aSchema, const nsAString& aTable, mozISqlResult** _retval) { nsAutoString select; nsAutoString from; nsAutoString where; if (mVersion >= SERVER_VERSION(7,3,0)) { select.AssignLiteral("SELECT n.nspname AS TABLE_SCHEM, "); 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"); where.AssignLiteral(" AND ct.relnamespace = n.oid "); if (!aSchema.IsEmpty()) { where.Append(NS_LITERAL_STRING(" AND n.nspname = '") + aSchema); where.Append(PRUnichar('\'')); } } else { select.AssignLiteral("SELECT NULL AS TABLE_SCHEM, "); from.AssignLiteral(" FROM pg_class ct, pg_class ci, pg_attribute a, pg_index i "); } if (!aTable.IsEmpty()) { where.Append(NS_LITERAL_STRING(" AND ct.relname = '") + aTable); where.Append(PRUnichar('\'')); } 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 "); NS_NAMED_LITERAL_STRING(where2, " WHERE ct.oid=i.indrelid AND ci.oid=i.indexrelid AND a.attrelid=ci.oid AND i.indisprimary "); NS_NAMED_LITERAL_STRING(order2, " ORDER BY table_name, pk_name, key_seq"); return RealExec(select + select2 + from + where2 + where + order2, _retval, nsnull); } nsresult mozSqlConnectionPgsql::Setup() { if (PQstatus(mConnection) == CONNECTION_BAD) { CopyUTF8toUTF16(PQerrorMessage(mConnection), mErrorMessage); mConnection = nsnull; return NS_ERROR_FAILURE; } PQsetClientEncoding(mConnection, "UNICODE"); /* PGresult* result = PQexec(mConnection, "SET DATESTYLE TO US"); PRInt32 stat = PQresultStatus(result); if (stat != PGRES_COMMAND_OK) { CopyUTF8toUTF16(PQresultErrorMessage(result), mErrorMessage); PQfinish(mConnection); mConnection = nsnull; return NS_ERROR_FAILURE; } */ PGresult* result = PQexec(mConnection, "select version()"); PRInt32 stat = PQresultStatus(result); if (stat != PGRES_TUPLES_OK) { CopyUTF8toUTF16(PQresultErrorMessage(result), mErrorMessage); return NS_ERROR_FAILURE; } char* version = PQgetvalue(result, 0, 0); NS_ConvertUTF8toUTF16 buffer(version); nsAString::const_iterator start, end, iter; buffer.BeginReading(iter); buffer.EndReading(end); while (iter != end && !nsCRT::IsAsciiSpace(*iter)) ++iter; while (iter != end && nsCRT::IsAsciiSpace(*iter)) ++iter; start = iter; while (iter != end && !nsCRT::IsAsciiSpace(*iter)) ++iter; mServerVersion = Substring(start,iter); PRInt32 numbers[3] = {0,0,0}; mServerVersion.BeginReading(iter); mServerVersion.EndReading(end); for (PRInt32 i = 0; i < 3; i++) { start = iter; while (iter != end && *iter != PRUnichar('.')) ++iter; nsAutoString v(Substring(start,iter)); PRInt32 err; numbers[i] = v.ToInteger(&err); while (iter != end && *iter == PRUnichar('.')) ++iter; } mVersion = SERVER_VERSION(numbers[0], numbers[1], numbers[2]); return NS_OK; } nsresult mozSqlConnectionPgsql::RealExec(const nsAString& aQuery, mozISqlResult** aResult, PRInt32* aAffectedRows) { if (! mConnection) return NS_ERROR_NOT_INITIALIZED; PGresult* r; r = PQexec(mConnection, NS_ConvertUTF16toUTF8(aQuery).get()); PRInt32 stat = PQresultStatus(r); if (PQstatus(mConnection) == CONNECTION_BAD) { PQreset(mConnection); nsresult rv = Setup(); if (NS_FAILED(rv)) return rv; r = PQexec(mConnection, NS_ConvertUTF16toUTF8(aQuery).get()); stat = PQresultStatus(r); } if (stat == PGRES_TUPLES_OK) { if (!aResult) return NS_ERROR_NULL_POINTER; 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 ("; static char select2[] = "select oid, typname from pg_type where oid in ("; char* select; if (mVersion >= SERVER_VERSION(7,3,0)) select = select1; else select = select2; PRInt32 columnCount = PQnfields(r); char* query = (char*)malloc(strlen(select) + columnCount * 11 + 2); strcpy(query, select); for (PRInt32 i = 0; i < columnCount; i++) { PRInt32 oid = PQftype(r, i); char oidStr[11]; if (i) sprintf(oidStr, ",%d", oid); else sprintf(oidStr, "%d", oid); strcat(query, oidStr); } strcat(query, ")"); PGresult* types = PQexec(mConnection, query); free(query); stat = PQresultStatus(types); if (stat != PGRES_TUPLES_OK) { CopyUTF8toUTF16(PQresultErrorMessage(types), mErrorMessage); return NS_ERROR_FAILURE; } if (*aResult) { ((mozSqlResultPgsql*)*aResult)->SetResult(r, types); nsresult rv = ((mozSqlResult*)*aResult)->Rebuild(); if (NS_FAILED(rv)) return rv; NS_ADDREF(*aResult); } else { mozSqlResult* result = new mozSqlResultPgsql(this, aQuery); if (! result) return NS_ERROR_OUT_OF_MEMORY; ((mozSqlResultPgsql*)result)->SetResult(r, types); nsresult rv = result->Init(); if (NS_FAILED(rv)) return rv; NS_ADDREF(*aResult = result); } } else if (stat == PGRES_COMMAND_OK) { if (!aAffectedRows) return NS_ERROR_NULL_POINTER; PR_sscanf(PQcmdTuples(r), "%d", aAffectedRows); mLastID = PQoidValue(r); } else { CopyUTF8toUTF16(PQresultErrorMessage(r), mErrorMessage); return NS_ERROR_FAILURE; } return NS_OK; } nsresult mozSqlConnectionPgsql::CancelExec() { if (!PQrequestCancel(mConnection)) { CopyUTF8toUTF16(PQerrorMessage(mConnection), mErrorMessage); return NS_ERROR_FAILURE; } return NS_OK; } nsresult mozSqlConnectionPgsql::GetIDName(nsAString& aIDName) { aIDName.AssignLiteral("OID"); return NS_OK; }