Hi pgadmin hackers,

I have been having trouble with the speed of the pgAdmin query tool on remote links, and I'm sure I'm not the only one.
The delay is due to loading the data type information for every column:
> QUERY : Scalar query (localhost:50119): SELECT format_type(oid,-1) as typname FROM pg_type WHERE oid = 1114 > QUERY : Scalar query (localhost:50119): SELECT CASE WHEN typbasetype=0 THEN oid else typbasetype END AS basetype FROM pg_type WHERE oid=1114

I have been playing around with a fix for quite a while, but I have finally sat myself down and put it on github (https://github.com/aiht/pgadmin3/commit/80a896e674bf68cc67aa3dc0dd425db9aa7372aa) (patch attached, too).

I'm still trying to make sure it does exactly what I expect, so the debug logging is quite heavy, but I wanted to ask a few questions to see if I am on the right track. If this code is useful to the project, I'll trim the logging down so it isn't in the way.

Code conventions:
* Does the pg prefix for a class name have a specific meaning and if so, am I using it wrongly? * I have copied the i prefix on some methods, but I don't really understand what it's for; I was thinking perhaps 'internal'?

Further suggestions:
* This code supports pre-caching all types in one go, but currently only loads them one by one. Maybe this should be an option. * When a pgConn is Duplicate()d, its cache is copied for the new connection to use, but as far as I can see this is only called when doing File->New Window in the query tool. If more pgConns are constructed by Duplicate() then caching may be more efficient. * Quite a few other parts of the code do their own type-info loading; at least a few of them could share in this cache. However, the other code does not load types one by one so they do not have the same latency issues as the query tool.

Possible problems:
* Threading? As far as I have seen, the code doesn't tend to use locking. The query threads just avoid accessing each others objects while they are active. I have not added any locking, but each cache object belongs to a single connection, and is only used from code that was already using that connection, so I think it is okay. * The cache is currently not flushed, because I was not sure when to trigger it. The main object tree should probably flush its cache when the view is refreshed, but I am not sure about what kind of changes the server may make to existing types that require a flush. * I have not tested this on Postgres variants (EDB etc.) or on old versions. I have not tested the current version on Windows (although I did test an old version of the same code long ago).

I have not yet patched the MSVS project file, but the only change required should be to add the pgTypeCache.{h,cpp} files.


I hope it helps!
Harun

diff --git a/pgadmin/db/pgConn.cpp b/pgadmin/db/pgConn.cpp
index 3bfb268..660b52c 100644
--- a/pgadmin/db/pgConn.cpp
+++ b/pgadmin/db/pgConn.cpp
@@ -41,6 +41,7 @@ typedef u_long in_addr_t;
 #include "db/pgConn.h"
 #include "utils/misc.h"
 #include "db/pgSet.h"
+#include "utils/pgTypeCache.h"
 
 double pgConn::libpqVersion = 8.0;
 
@@ -80,6 +81,8 @@ pgConn::pgConn(const wxString &server, const wxString &service, const wxString &
 	needColQuoting = false;
 	utfConnectString = false;
 
+	typeCache = new pgTypeCache(this);
+
 	// Check the hostname/ipaddress
 	conn = 0;
 	noticeArg = 0;
@@ -227,6 +230,7 @@ pgConn::pgConn(const wxString &server, const wxString &service, const wxString &
 pgConn::~pgConn()
 {
 	Close();
+	delete typeCache;
 }
 
 
@@ -352,9 +356,15 @@ bool pgConn::Reconnect()
 
 pgConn *pgConn::Duplicate()
 {
-	return new pgConn(wxString(save_server), wxString(save_service), wxString(save_hostaddr), wxString(save_database), wxString(save_username), wxString(save_password),
+	pgConn *copy = new pgConn(wxString(save_server), wxString(save_service), wxString(save_hostaddr), wxString(save_database), wxString(save_username), wxString(save_password),
 	                  save_port, save_rolename, save_sslmode, save_oid,
 	                  save_applicationname, save_sslcert, save_sslkey, save_sslrootcert, save_sslcrl, save_sslcompression);
+
+	if(typeCache != NULL && copy != NULL && copy->typeCache != NULL)
+	{
+		copy->typeCache->SetInitial(typeCache);
+	}
+	return copy;
 }
 
 
@@ -1129,3 +1139,9 @@ bool pgConn::TableHasColumn(wxString schemaname, wxString tblname, const wxStrin
 	return false;
 }
 
+pgTypeCache *pgConn::GetTypeCache()
+{
+	wxASSERT(typeCache != NULL);
+	typeCache->assertConnMatchLink(this);
+	return typeCache;
+}
diff --git a/pgadmin/db/pgSet.cpp b/pgadmin/db/pgSet.cpp
index 5673cf1..68a689b 100644
--- a/pgadmin/db/pgSet.cpp
+++ b/pgadmin/db/pgSet.cpp
@@ -23,6 +23,7 @@
 #include "db/pgQueryThread.h"
 #include "utils/sysLogger.h"
 #include "utils/pgDefs.h"
+#include "utils/pgTypeCache.h"
 
 pgSet::pgSet()
 	: conv(wxConvLibc)
@@ -52,13 +53,6 @@ pgSet::pgSet(PGresult *newRes, pgConn *newConn, wxMBConv &cnv, bool needColQt)
 	else
 	{
 		nCols = PQnfields(res);
-		for (int x = 0; x < nCols + 1; x++)
-		{
-			colTypes.Add(wxT(""));
-			colFullTypes.Add(wxT(""));
-			colClasses.Add(0);
-		}
-
 		nRows = PQntuples(res);
 		MoveFirst();
 	}
@@ -100,84 +94,20 @@ long pgSet::GetInsertedCount() const
 pgTypClass pgSet::ColTypClass(const int col) const
 {
 	wxASSERT(col < nCols && col >= 0);
-
-	if (colClasses[col] != 0)
-		return (pgTypClass)colClasses[col];
-
-	wxString typoid = ExecuteScalar(
-	                      wxT("SELECT CASE WHEN typbasetype=0 THEN oid else typbasetype END AS basetype\n")
-	                      wxT("  FROM pg_type WHERE oid=") + NumToStr(ColTypeOid(col)));
-
-	switch (StrToLong(typoid))
-	{
-		case PGOID_TYPE_BOOL:
-			colClasses[col] = PGTYPCLASS_BOOL;
-			break;
-		case PGOID_TYPE_INT8:
-		case PGOID_TYPE_INT2:
-		case PGOID_TYPE_INT4:
-		case PGOID_TYPE_OID:
-		case PGOID_TYPE_XID:
-		case PGOID_TYPE_TID:
-		case PGOID_TYPE_CID:
-		case PGOID_TYPE_FLOAT4:
-		case PGOID_TYPE_FLOAT8:
-		case PGOID_TYPE_MONEY:
-		case PGOID_TYPE_BIT:
-		case PGOID_TYPE_NUMERIC:
-			colClasses[col] = PGTYPCLASS_NUMERIC;
-			break;
-		case PGOID_TYPE_BYTEA:
-		case PGOID_TYPE_CHAR:
-		case PGOID_TYPE_NAME:
-		case PGOID_TYPE_TEXT:
-		case PGOID_TYPE_VARCHAR:
-			colClasses[col] = PGTYPCLASS_STRING;
-			break;
-		case PGOID_TYPE_TIMESTAMP:
-		case PGOID_TYPE_TIMESTAMPTZ:
-		case PGOID_TYPE_TIME:
-		case PGOID_TYPE_TIMETZ:
-		case PGOID_TYPE_INTERVAL:
-			colClasses[col] = PGTYPCLASS_DATE;
-			break;
-		default:
-			colClasses[col] = PGTYPCLASS_OTHER;
-			break;
-	}
-
-	return (pgTypClass)colClasses[col];
+	return conn->GetTypeCache()->GetTypeClass(ColTypeOid(col));
 }
 
 
 wxString pgSet::ColType(const int col) const
 {
 	wxASSERT(col < nCols && col >= 0);
-
-	if (!colTypes[col].IsEmpty())
-		return colTypes[col];
-
-	wxString szSQL, szResult;
-	szSQL.Printf(wxT("SELECT format_type(oid,NULL) as typname FROM pg_type WHERE oid = %d"), (int)ColTypeOid(col));
-	szResult = ExecuteScalar(szSQL);
-	colTypes[col] = szResult;
-
-	return szResult;
+	return conn->GetTypeCache()->GetTypeName(ColTypeOid(col));
 }
 
 wxString pgSet::ColFullType(const int col) const
 {
 	wxASSERT(col < nCols && col >= 0);
-
-	if (!colFullTypes[col].IsEmpty())
-		return colFullTypes[col];
-
-	wxString szSQL, szResult;
-	szSQL.Printf(wxT("SELECT format_type(oid,%d) as typname FROM pg_type WHERE oid = %d"), (int)ColTypeMod(col), (int)ColTypeOid(col));
-	szResult = ExecuteScalar(szSQL);
-	colFullTypes[col] = szResult;
-
-	return szResult;
+	return conn->GetTypeCache()->GetFullTypeName(ColTypeOid(col), ColTypeMod(col));
 }
 
 int pgSet::ColScale(const int col) const
@@ -387,12 +317,6 @@ OID pgSet::GetOid(const wxString &col) const
 }
 
 
-wxString pgSet::ExecuteScalar(const wxString &sql) const
-{
-	return conn->ExecuteScalar(sql);
-}
-
-
 //////////////////////////////////////////////////////////////////
 
 pgSetIterator::pgSetIterator(pgConn *conn, const wxString &qry)
diff --git a/pgadmin/include/db/pgConn.h b/pgadmin/include/db/pgConn.h
index 993a059..3e87164 100644
--- a/pgadmin/include/db/pgConn.h
+++ b/pgadmin/include/db/pgConn.h
@@ -21,6 +21,8 @@
 // App headers
 #include "pgSet.h"
 
+class pgTypeCache;
+
 // status enums
 enum
 {
@@ -247,6 +249,8 @@ public:
 	pgNotification *GetNotification();
 	int GetTxStatus();
 
+	pgTypeCache *GetTypeCache();
+
 	void Reset();
 
 	bool StartCopy(const wxString query);
@@ -278,6 +282,10 @@ protected:
 	friend class pgQueryThread;
 
 private:
+	// This class can not be copied.
+	pgConn(const pgConn &rhs);
+	const pgConn &operator=(const pgConn &rhs);
+
 	bool DoConnect();
 
 	wxString qtString(const wxString &value);
@@ -290,6 +298,8 @@ private:
 	wxString reservedNamespaces;
 	wxString connstr;
 
+	pgTypeCache *typeCache;
+
 	wxString save_server, save_service, save_hostaddr, save_database, save_username, save_password, save_rolename, save_applicationname;
 	wxString save_sslcert, save_sslkey, save_sslrootcert, save_sslcrl;
 	int save_port, save_sslmode;
diff --git a/pgadmin/include/db/pgSet.h b/pgadmin/include/db/pgSet.h
index 1eee62f..61b3b2c 100644
--- a/pgadmin/include/db/pgSet.h
+++ b/pgadmin/include/db/pgSet.h
@@ -21,15 +21,6 @@
 
 #include "utils/misc.h"
 
-typedef enum
-{
-    PGTYPCLASS_NUMERIC = 1,
-    PGTYPCLASS_BOOL,
-    PGTYPCLASS_STRING,
-    PGTYPCLASS_DATE,
-    PGTYPCLASS_OTHER
-} pgTypClass;
-
 class pgConn;
 
 // Class declarations
@@ -139,8 +130,6 @@ protected:
 	wxString ExecuteScalar(const wxString &sql) const;
 	wxMBConv &conv;
 	bool needColQuoting;
-	mutable wxArrayString colTypes, colFullTypes;
-	wxArrayInt colClasses;
 };
 
 
diff --git a/pgadmin/include/utils/misc.h b/pgadmin/include/utils/misc.h
index 69403f3..b15fd3f 100644
--- a/pgadmin/include/utils/misc.h
+++ b/pgadmin/include/utils/misc.h
@@ -16,7 +16,7 @@
 #include <wx/datetime.h>
 #include <wx/tokenzr.h>
 
-#include "utils/misc.h"
+// ?? #include "utils/misc.h"
 
 class wxImageList;
 extern wxImageList *imageList;
@@ -265,5 +265,13 @@ wxString commandLineCleanOption(const wxString &option, bool schemaObject = fals
 wxString qtIdent(const wxString &value);    // add " if necessary
 wxString qtTypeIdent(const wxString &value);    // add " if necessary
 
-#endif
+typedef enum
+{
+    PGTYPCLASS_NUMERIC = 1,
+    PGTYPCLASS_BOOL,
+    PGTYPCLASS_STRING,
+    PGTYPCLASS_DATE,
+    PGTYPCLASS_OTHER
+} pgTypClass;
 
+#endif
diff --git a/pgadmin/include/utils/module.mk b/pgadmin/include/utils/module.mk
index e05ddef..30a833e 100644
--- a/pgadmin/include/utils/module.mk
+++ b/pgadmin/include/utils/module.mk
@@ -22,7 +22,8 @@ pgadmin3_SOURCES += \
 	include/utils/sysProcess.h \
 	include/utils/sysSettings.h \
 	include/utils/utffile.h \
-	include/utils/macros.h
+	include/utils/macros.h \
+	include/utils/pgTypeCache.h
 
 EXTRA_DIST += \
         include/utils/module.mk
diff --git a/pgadmin/include/utils/pgTypeCache.h b/pgadmin/include/utils/pgTypeCache.h
new file mode 100644
index 0000000..a759d7a
--- /dev/null
+++ b/pgadmin/include/utils/pgTypeCache.h
@@ -0,0 +1,88 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+//
+// Copyright (C) 2002 - 2012, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// pgTypeCache.h - cache for data type names and details.
+//
+//////////////////////////////////////////////////////////////////////////
+
+#ifndef PGTYPECACHE_H
+#define PGTYPECACHE_H
+
+// wxWindows headers
+#include <wx/wx.h>
+#include <wx/hashmap.h>
+
+// PostgreSQL headers
+#include <libpq-fe.h>
+
+#include "utils/misc.h"
+
+class pgConn;
+
+WX_DECLARE_HASH_MAP(int, wxString, wxIntegerHash, wxIntegerEqual, typmodStringMap);
+
+class CachedTypeDetails
+{
+public:
+	CachedTypeDetails();
+
+	pgTypClass typeClass;   // type class eg. numeric, string etc.
+	wxString basicName;      // format_type(oid, NULL)
+	int typTypMod;           // pg_types.typtypmod
+	typmodStringMap fullNames;        // map of typMod -> format_type(oid, typMod)
+};
+
+WX_DECLARE_HASH_MAP(OID, CachedTypeDetails, wxIntegerHash, wxIntegerEqual, oidTypeMap);
+
+class pgTypeCache
+{
+public:
+	pgTypeCache(pgConn *cn) : conn(cn), previousLimit(0) {}
+
+	// Pre-fill the cache with some cached data from another connection's cache.
+	void SetInitial(const pgTypeCache *other);
+
+	// Get the short type name from 'format_type(oid, NULL)'
+	wxString GetTypeName(OID oid);
+	// Get the full type name from 'format_type(oid, typeMod)'
+	wxString GetFullTypeName(OID oid, int typeMod = -1);
+	// Get the type class eg. numeric, string etc.
+	pgTypClass GetTypeClass(OID oid);
+
+	// Get the full type name from 'format_type(oid, pg_types.typtypmod)'
+	// TODO: Check if this should still be used. My old patch used it in three places:
+	// edbPackageFunctionFactory::AppendFunctions - now uses 'format_type(oid, NULL)'
+	// pgAggregateFactory::CreateObjects - still uses typtypmod.
+	// pgFunctionFactory::AppendFunctions - now uses 'format_type(oid, NULL)'
+	wxString GetDefaultFullTypeName(OID oid);
+
+	// Pre-fill the cache with all types in the database, or with only 'limit' types if it is provided.
+	void PreCache(int limit = 0);
+
+	// Make sure the two-way link to pgConn is correct.
+	void assertConnMatchLink( pgConn *test )
+	{
+		wxASSERT(conn != NULL);
+		wxASSERT(conn == test);
+	}
+
+private:
+	// This class can not be copied.
+	pgTypeCache(const pgTypeCache &rhs);
+	const pgTypeCache &operator=(const pgTypeCache &rhs);
+
+	oidTypeMap::iterator iLoadTypeIfMissing(OID oid, int *typeMod = NULL);
+	pgTypClass iGetTypeClass(OID baseOid);
+	void iLoadTypes(int limit, OID oid, int *typeMod = NULL);
+	void iLoadModName(oidTypeMap::iterator existingType, int typeMod);
+
+	pgConn *conn;
+	oidTypeMap types;
+	int previousLimit;
+};
+
+#endif
diff --git a/pgadmin/utils/module.mk b/pgadmin/utils/module.mk
index c307647..187ccbe 100644
--- a/pgadmin/utils/module.mk
+++ b/pgadmin/utils/module.mk
@@ -21,7 +21,8 @@ pgadmin3_SOURCES += \
 	utils/sysSettings.cpp \
 	utils/tabcomplete.c \
 	utils/utffile.cpp \
-	utils/macros.cpp
+	utils/macros.cpp \
+	utils/pgTypeCache.cpp
 
 EXTRA_DIST += \
 	utils/module.mk \
diff --git a/pgadmin/utils/pgTypeCache.cpp b/pgadmin/utils/pgTypeCache.cpp
new file mode 100644
index 0000000..b72ad1d
--- /dev/null
+++ b/pgadmin/utils/pgTypeCache.cpp
@@ -0,0 +1,236 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+// RCS-ID:      $Id$
+// Copyright (C) 2002 - 2008, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// pgTypeCache.cpp - cache for data type names and details.
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "pgAdmin3.h"
+
+#include "utils/pgTypeCache.h"
+#include "db/pgConn.h"
+#include "utils/pgDefs.h"
+
+CachedTypeDetails::CachedTypeDetails()
+	: typeClass(PGTYPCLASS_OTHER),
+	typTypMod(0)
+{
+}
+
+void pgTypeCache::SetInitial(const pgTypeCache *other)
+{
+	wxASSERT(other != NULL);
+	wxLogDebug(wxString::Format(wxT("pgTypeCache: set initial: %d cached types"), other->types.size()));
+	types = other->types;
+	previousLimit = other->previousLimit;
+}
+
+wxString pgTypeCache::GetTypeName(OID oid)
+{
+	oidTypeMap::iterator it = iLoadTypeIfMissing(oid);
+	wxLogDebug(wxString::Format(wxT("pgTypeCache: got basic name for oid %d: %s"), oid, (*it).second.basicName.c_str()));
+	return (*it).second.basicName;
+}
+
+pgTypClass pgTypeCache::GetTypeClass(OID oid)
+{
+	oidTypeMap::iterator it = iLoadTypeIfMissing(oid);
+	wxLogDebug(wxString::Format(wxT("pgTypeCache: got type class for oid %d: %d"), oid, (*it).second.typeClass));
+	return (*it).second.typeClass;
+}
+
+wxString pgTypeCache::GetFullTypeName(OID oid, int typeMod)
+{
+	oidTypeMap::iterator it = iLoadTypeIfMissing(oid, &typeMod);
+	wxLogDebug(wxString::Format(wxT("pgTypeCache: got full name for oid %d, typeMod %d: %s"), oid, typeMod, (*it).second.fullNames[typeMod].c_str()));
+	return (*it).second.fullNames[typeMod];
+}
+
+wxString pgTypeCache::GetDefaultFullTypeName(OID oid)
+{
+	oidTypeMap::iterator it = iLoadTypeIfMissing(oid);
+	wxLogDebug(wxString::Format(wxT("pgTypeCache: got default full name for oid %d: %s"), oid, (*it).second.fullNames[(*it).second.typTypMod].c_str()));
+	return (*it).second.fullNames[(*it).second.typTypMod];
+}
+
+void pgTypeCache::PreCache(int limit /*= 0*/)
+{
+	if (previousLimit == 0 || limit > previousLimit)
+	{
+		iLoadTypes(limit, 0, NULL);
+		previousLimit = limit;
+		if (previousLimit == 0)
+			previousLimit = types.size();
+	}
+}
+
+pgTypClass pgTypeCache::iGetTypeClass(OID baseOid)
+{
+	switch (baseOid)
+	{
+		case PGOID_TYPE_BOOL:
+			return PGTYPCLASS_BOOL;
+
+		case PGOID_TYPE_INT8:
+		case PGOID_TYPE_INT2:
+		case PGOID_TYPE_INT4:
+		case PGOID_TYPE_OID:
+		case PGOID_TYPE_XID:
+		case PGOID_TYPE_TID:
+		case PGOID_TYPE_CID:
+		case PGOID_TYPE_FLOAT4:
+		case PGOID_TYPE_FLOAT8:
+		case PGOID_TYPE_MONEY:
+		case PGOID_TYPE_BIT:
+		case PGOID_TYPE_NUMERIC:
+			return PGTYPCLASS_NUMERIC;
+
+		case PGOID_TYPE_BYTEA:
+		case PGOID_TYPE_CHAR:
+		case PGOID_TYPE_NAME:
+		case PGOID_TYPE_TEXT:
+		case PGOID_TYPE_VARCHAR:
+			return PGTYPCLASS_STRING;
+
+		case PGOID_TYPE_TIMESTAMP:
+		case PGOID_TYPE_TIMESTAMPTZ:
+		case PGOID_TYPE_TIME:
+		case PGOID_TYPE_TIMETZ:
+		case PGOID_TYPE_INTERVAL:
+			return PGTYPCLASS_DATE;
+
+		default:
+			return PGTYPCLASS_OTHER;
+	}
+}
+
+// Make sure that the requested OID and typmod combination is cached,
+// and return an iterator to the OID record.
+oidTypeMap::iterator pgTypeCache::iLoadTypeIfMissing(OID oid, int *typeMod /*= NULL*/)
+{
+	oidTypeMap::iterator it = types.find(oid);
+	bool typeMissing = it == types.end();
+	bool modMissing = !typeMissing && typeMod != NULL &&
+		(*it).second.fullNames.find(*typeMod) == (*it).second.fullNames.end();
+	if (typeMissing)
+	{
+		wxLogDebug(wxString::Format(wxT("pgTypeCache: cache miss for oid %d"), oid));
+		iLoadTypes(0, oid, typeMod);
+		it = types.find(oid);
+	}
+	else if (modMissing)
+	{
+		wxLogDebug(wxString::Format(wxT("pgTypeCache: partial cache hit for oid %d, typeMod %d"), oid, *typeMod));
+		iLoadModName(it, *typeMod);
+	}
+	else
+		wxLogDebug(wxString::Format(wxT("pgTypeCache: full cache hit for oid %d"), oid));
+
+	// Wait, what happens if we try to load an invalid OID? Bad things!
+	// It shouldn't happen, but maybe if a type was deleted after we got a field of that type in our resultset?
+	if (it == types.end())
+	{
+		wxLogWarning(wxString::Format(wxT("pgTypeCache: unable to load oid %d, returning dummy type info"), oid));
+		// Make up something that will at least avoid crashes.
+		CachedTypeDetails &currType = types[oid];
+
+		currType.typTypMod = -1;
+		currType.basicName = wxT("(unknown)");
+		currType.fullNames[currType.typTypMod] = wxT("(unknown)");
+		if (typeMod != NULL)
+		{
+			currType.fullNames[*typeMod] = wxT("(unknown)");
+		}
+		currType.typeClass = iGetTypeClass(oid);
+		it = types.find(oid);
+	}
+
+	wxASSERT(it != types.end());
+	return it;
+}
+
+// Load one or many type records, depending on whether oid is valid.
+// If one record is loaded, typeMod can point to a custom typmod value.
+// If many are loaded, the result row count can be limited by limit.
+void pgTypeCache::iLoadTypes(int limit, OID oid, int *typeMod)
+{
+	bool useLimit = limit > 0;
+	bool useOid = oid > 0;
+	bool useMod = useOid && typeMod != NULL;
+
+	const wxChar *sqlCommonFields = wxT("typtypmod,typbasetype,")
+			wxT("format_type(oid,NULL) as basic,")
+			wxT("format_type(oid,typtypmod) as def");
+	const wxChar *sqlFrom = wxT(" FROM pg_type");
+
+	wxString sql, tmp;
+	if (useOid)		// load a single type record
+	{
+		sql = wxT("SELECT ");
+		sql += sqlCommonFields;
+		if (useMod)
+		{
+			tmp.Printf(wxT(",format_type(oid,%d) as bymod"), *typeMod);
+			sql += tmp;
+			wxLogDebug(wxString::Format(wxT("pgTypeCache: loading oid %d with typeMod %d"), oid, *typeMod));
+		}
+		else
+			wxLogDebug(wxString::Format(wxT("pgTypeCache: loading oid %d"), oid));
+
+		sql += sqlFrom;
+		tmp.Printf(wxT(" WHERE oid=%d"), oid);
+		sql += tmp;
+	}
+	else
+	{
+		sql = wxT("SELECT oid,");
+		sql += sqlCommonFields;
+		sql += sqlFrom;
+		if (useLimit)
+		{
+			tmp.Printf(wxT(" LIMIT %d"), limit);
+			sql += tmp;
+			wxLogDebug(wxString::Format(wxT("pgTypeCache: loading %d types in a batch"), limit));
+		}
+		else
+			wxLogDebug(wxString::Format(wxT("pgTypeCache: loading entire pg_types table in a batch")));
+	}
+
+	pgSet *result = conn->ExecuteSet(sql);
+	if (result)
+	{
+		while (!result->Eof())
+		{
+			OID currOid = useOid? oid : result->GetOid(wxT("oid"));
+			CachedTypeDetails &currType = types[currOid];
+
+			currType.typTypMod = result->GetLong(wxT("typtypmod"));
+			currType.basicName = result->GetVal(wxT("basic"));
+			currType.fullNames[currType.typTypMod] = result->GetVal(wxT("def"));
+			if (useMod)
+			{
+				currType.fullNames[*typeMod] = result->GetVal(wxT("bymod"));
+			}
+			OID baseType = result->GetOid(wxT("typbasetype"));
+			currType.typeClass = iGetTypeClass(baseType == 0? currOid : baseType);
+
+			result->MoveNext();
+		}
+		delete result;
+	}
+	else
+		wxLogError(wxString::Format(wxT("pgTypeCache: failed to load type details")));
+}
+
+// Load a typmod-modified name for a type that is already cached.
+void pgTypeCache::iLoadModName(oidTypeMap::iterator existingType, int typeMod)
+{
+	wxASSERT(existingType != types.end());
+	wxString szSQL;
+	szSQL.Printf(wxT("SELECT format_type(%d,%d)"), (*existingType).first, typeMod);
+	(*existingType).second.fullNames[typeMod] = conn->ExecuteScalar(szSQL);
+}
-- 
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers

Reply via email to