Index: src/ctl/ctlSQLBox.cpp
===================================================================
--- src/ctl/ctlSQLBox.cpp	(revision 4897)
+++ src/ctl/ctlSQLBox.cpp	(working copy)
@@ -15,6 +15,7 @@
 
 // App headers
 #include "pgAdmin3.h"
+#include "pgSet.h"
 #include "ctl/ctlSQLBox.h"
 
 
@@ -276,10 +277,9 @@
 
 
 BEGIN_EVENT_TABLE(ctlSQLBox, wxStyledTextCtrl)
-#ifdef __WXGTK__
     EVT_KEY_DOWN(ctlSQLBox::OnKeyDown)
-#endif
     EVT_MENU(MNU_FIND,ctlSQLBox::OnFind)
+	EVT_MENU(MNU_AUTOCOMPLETE,ctlSQLBox::OnAutoComplete)
     EVT_FIND(-1, ctlSQLBox::OnFindDialog)
     EVT_FIND_NEXT(-1, ctlSQLBox::OnFindDialog)
     EVT_FIND_REPLACE(-1, ctlSQLBox::OnFindDialog)
@@ -304,6 +304,7 @@
 ctlSQLBox::ctlSQLBox(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
 {
     m_dlgFind=0;
+	m_database=NULL;
 #ifndef __WXMSW__
     findDlgLast = false;
 #endif
@@ -362,15 +363,26 @@
     SetLexer(wxSTC_LEX_SQL);
     SetKeyWords(0, sqlKeywords);
 
-    wxAcceleratorEntry entries[1];
+    wxAcceleratorEntry entries[2];
     entries[0].Set(wxACCEL_CTRL, (int)'F', MNU_FIND);
-    wxAcceleratorTable accel(1, entries);
+	entries[1].Set(wxACCEL_CTRL, (int)' ', MNU_AUTOCOMPLETE);
+    wxAcceleratorTable accel(2, entries);
     SetAcceleratorTable(accel);
 
     m_findData.SetFlags(wxFR_DOWN);
 
+	// Autocompletion configuration
+	AutoCompSetSeparator('\t');
+	AutoCompSetChooseSingle(true);
+	AutoCompSetIgnoreCase(true);
+	AutoCompSetFillUps(wxT(" \t"));
+	AutoCompSetDropRestOfWord(true);
 }
 
+void ctlSQLBox::SetDatabase(pgConn *db)
+{
+	m_database = db;
+}
 
 void ctlSQLBox::OnFind(wxCommandEvent& ev)
 {
@@ -525,11 +537,52 @@
 
 void ctlSQLBox::OnKeyDown(wxKeyEvent& event)
 {
-    event.m_metaDown=false;
+#ifdef __WXGTK__
+	event.m_metaDown=false;
     event.Skip();
+#endif
+	if (!AutoCompActive() &&
+		 ( settings->GetTabForCompletion() && /* autocomplete on tab only if specifically configured */
+		  !event.AltDown() && !event.CmdDown() && !event.ControlDown() && event.GetKeyCode() == '\t'
+		 ))
+	{
+		wxCommandEvent e;
+		OnAutoComplete(e);
+	}
+	else
+		wxStyledTextCtrl::OnKeyDown(event);
 }
 
+extern "C" char *tab_complete(const char *allstr, const int startptr, const int endptr, void *dbptr);
+void ctlSQLBox::OnAutoComplete(wxCommandEvent& rev)
+{
+	if (GetReadOnly())
+		return;
+	if (m_database == NULL)
+		return;
 
+	wxString what = GetCurLine().Left(GetCurrentPos()-PositionFromLine(GetCurrentLine()));;
+	int spaceidx = what.Find(' ',true);
+	
+	char *tab_ret;
+	if (spaceidx == -1)
+		tab_ret = tab_complete(what.mb_str(wxConvUTF8), 0, what.Len()+1, m_database);
+	else
+		tab_ret = tab_complete(what.mb_str(wxConvUTF8), spaceidx+1, what.Len()+1, m_database);
+
+	if (tab_ret == NULL || tab_ret[0] == '\0')
+		return; /* No autocomplete available for this string */
+
+	wxString wxRet = wxString(tab_ret, wxConvUTF8);
+	free(tab_ret);
+
+	if (spaceidx == -1)
+		AutoCompShow(what.Len(), wxRet);
+	else
+		AutoCompShow(what.Len()-spaceidx-1, wxRet);
+}
+
+
 ctlSQLBox::~ctlSQLBox()
 {
     wxLogInfo(wxT("Destroying a ctlSQLBox"));
@@ -539,3 +592,36 @@
         delete m_dlgFind;
     }
 }
+
+
+/*
+ * Callback function from tab-complete.c, bridging the gap between C++ and C.
+ * Execute a query using the C++ APIs, returning it as a tab separated
+ * "char*-string"
+ * The query is expected to return only one column, and will have an ORDER BY
+ * clause for this column added automatically.
+ */
+extern "C"
+char *pg_query_to_single_ordered_string(char *query, void *dbptr)
+{
+	pgConn *db = (pgConn *)dbptr;
+	pgSet *res = db->ExecuteSet(wxString(query, wxConvUTF8) + wxT(" ORDER BY 1"));
+	if (!res)
+		return NULL;
+
+	wxString ret = wxString();
+
+	while (!res->Eof())
+	{
+		ret += res->GetVal(0);
+		ret += wxT(" \t");
+		res->MoveNext();
+	}
+
+	ret.Trim();
+	// Trims both space and tab, but we want to keep the space!
+	if (ret.Length() > 0)
+		ret += wxT(" ");
+
+	return strdup(ret.mb_str(wxConvUTF8));
+}
Index: src/frm/frmOptions.cpp
===================================================================
--- src/frm/frmOptions.cpp	(revision 4897)
+++ src/frm/frmOptions.cpp	(working copy)
@@ -51,6 +51,7 @@
 #define cbCopyQuote					CTRL_COMBOBOX("cbCopyQuote")
 #define cbCopyQuoteChar				CTRL_COMBOBOX("cbCopyQuoteChar")
 #define cbCopySeparator				CTRL_COMBOBOX("cbCopySeparator")
+#define chkTabForCompletion			CTRL_CHECKBOX("chkTabForCompletion")
 #define chkStickySql                CTRL_CHECKBOX("chkStickySql")
 #define chkDoubleClickProperties    CTRL_CHECKBOX("chkDoubleClickProperties")
 #define cbLanguage                  CTRL_COMBOBOX("cbLanguage")
@@ -109,6 +110,7 @@
 	cbCopyQuote->SetSelection(settings->GetCopyQuoting());
 	cbCopyQuoteChar->SetValue(settings->GetCopyQuoteChar());
 	cbCopySeparator->SetValue(settings->GetCopyColSeparator());
+	chkTabForCompletion->SetValue(settings->GetTabForCompletion());
     chkStickySql->SetValue(settings->GetStickySql());
     chkDoubleClickProperties->SetValue(settings->GetDoubleClickProperties());
     txtSqlHelpSite->SetValue(settings->GetSqlHelpSite());
@@ -227,6 +229,7 @@
 	settings->SetCopyQuoting(cbCopyQuote->GetCurrentSelection());
 	settings->SetCopyQuoteChar(cbCopyQuoteChar->GetValue());
 	settings->SetCopyColSeparator(cbCopySeparator->GetValue());
+	settings->SetTabForCompletion(chkTabForCompletion->GetValue());
     settings->SetStickySql(chkStickySql->GetValue());
     settings->SetDoubleClickProperties(chkDoubleClickProperties->GetValue());
     settings->SetUnicodeFile(chkUnicodeFile->GetValue());
Index: src/frm/frmQuery.cpp
===================================================================
--- src/frm/frmQuery.cpp	(revision 4897)
+++ src/frm/frmQuery.cpp	(working copy)
@@ -218,6 +218,7 @@
     horizontal->SetMinimumPaneSize(50);
 
     sqlQuery = new ctlSQLBox(horizontal, CTL_SQLQUERY, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxSIMPLE_BORDER | wxTE_RICH2);
+	sqlQuery->SetDatabase(conn);
     sqlQuery->SetMarginWidth(1, 16);
 
     output = new wxNotebook(horizontal, -1, wxDefaultPosition, wxDefaultSize, wxNB_BOTTOM);
Index: src/include/ctl/ctlSQLBox.h
===================================================================
--- src/include/ctl/ctlSQLBox.h	(revision 4897)
+++ src/include/ctl/ctlSQLBox.h	(working copy)
@@ -17,6 +17,7 @@
 #include <wx/stc/stc.h>
 #include <wx/fdrepdlg.h>
 
+#include "pgConn.h"
 
 // Class declarations
 class ctlSQLBox : public wxStyledTextCtrl
@@ -30,7 +31,10 @@
 
     void Create(wxWindow *parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
 
+	void SetDatabase(pgConn *db);
+
     void OnKeyDown(wxKeyEvent& event);
+	void OnAutoComplete(wxCommandEvent& event);
     void OnFind(wxCommandEvent& event);
     void OnReplace(wxCommandEvent& event);
     void OnFindDialog(wxFindDialogEvent& event);
@@ -41,6 +45,7 @@
 private:
 	wxFindReplaceData m_findData;
     wxFindReplaceDialog* m_dlgFind;
+	pgConn *m_database;
 #ifndef __WXMSW__
 	bool findDlgLast;
 #endif
Index: src/include/menu.h
===================================================================
--- src/include/menu.h	(revision 4897)
+++ src/include/menu.h	(working copy)
@@ -66,6 +66,8 @@
 
     MNU_ONLINEUPDATE_NEWDATA,
 
+	MNU_AUTOCOMPLETE, 
+
     MNU_RECENT,
 
     MNU_NEW=MNU_RECENT+15,  // leave space for recent file entries
Index: src/include/sysSettings.h
===================================================================
--- src/include/sysSettings.h	(revision 4897)
+++ src/include/sysSettings.h	(working copy)
@@ -86,6 +86,10 @@
     long GetIndentSpaces() const { return indentSpaces; }
     void SetIndentSpaces(long l) { indentSpaces=l; }
 
+	// Tab for completion
+	bool GetTabForCompletion() const { return tabForCompletion; }
+	void SetTabForCompletion(const bool newval) { tabForCompletion = newval; }
+
     // Sticky SQL
     bool GetStickySql() const { return stickySql; }
     void SetStickySql(const bool newval);
@@ -191,7 +195,7 @@
     bool askSaveConfirmation;
     bool confirmDelete, suppressGuruHints;
     long maxRows, maxColSize, autoRowCountThreshold, indentSpaces;
-    bool stickySql, unicodeFile;
+    bool stickySql, unicodeFile, tabForCompletion;
     bool doubleClickProperties;
     long maxServerLogSize;
 
Index: src/ui/frmOptions.xrc
===================================================================
--- src/ui/frmOptions.xrc	(revision 4897)
+++ src/ui/frmOptions.xrc	(working copy)
@@ -3,7 +3,7 @@
   <object class="wxDialog" name="frmOptions">
     <title>Options</title>
     <pos>0,0d</pos>
-    <size>246,196d</size>
+    <size>246,211d</size>
     <style>wxDEFAULT_DIALOG_STYLE|wxDIALOG_MODAL|wxCAPTION|wxSYSTEM_MENU</style>
     <object class="wxNotebook" name="nbOptions">
       <object class="notebookpage">
@@ -376,6 +376,13 @@
            <style>wxCB_DROPDOWN</style>
           </object>
 
+          <object class="wxCheckBox" name="chkTabForCompletion">
+            <label>Use TAB character for autocompletion</label>
+            <checked>0</checked>
+            <pos>5,127d</pos>
+            <size>226,12d</size>
+          </object>
+          
           <object class="wxCheckBox" name="chkStickySql">
             
             
@@ -385,7 +392,7 @@
             <checked>1</checked>
             
             
-            <pos>5,127d</pos>
+            <pos>5,142d</pos>
             
             
             <size>226,12d</size>
@@ -463,7 +470,7 @@
         </object>
       </object>
       <pos>2,3d</pos>
-      <size>240,171d</size>
+      <size>240,186d</size>
     </object>
     <object class="wxButton" name="wxID_HELP">
       
@@ -471,7 +478,7 @@
       <label>&amp;Help</label>
       
       
-      <pos>2,177d</pos>
+      <pos>2,192d</pos>
       
       
       <tooltip>Accept the current settings and close the dialogue.</tooltip>
@@ -485,7 +492,7 @@
       <default>1</default>
       
       
-      <pos>140,177d</pos>
+      <pos>140,192d</pos>
       
       
       <tooltip>Accept the current settings and close the dialogue.</tooltip>
@@ -499,7 +506,7 @@
       <default>0</default>
       
       
-      <pos>193,177d</pos>
+      <pos>193,192d</pos>
       
       
       <tooltip>Cancel any changes and close the dialogue.</tooltip>
Index: src/utils/sysSettings.cpp
===================================================================
--- src/utils/sysSettings.cpp	(revision 4897)
+++ src/utils/sysSettings.cpp	(working copy)
@@ -141,6 +141,7 @@
     showUsersForPrivileges=StrToBool(Read(wxT("ShowUsersForPrivileges"), wxT("No")));
     Read(wxT("AutoRowCount"), &autoRowCountThreshold, 2000L);
     Read(wxT("IndentSpaces"), &indentSpaces, 0L);
+	Read(wxT("TabForCompletion"), &tabForCompletion, false);
     Read(wxT("StickySql"), &stickySql, false);
     Read(wxT("DoubleClickProperties"), &doubleClickProperties, true);
     Read(wxT("SuppressGuruHints"), &suppressGuruHints, false);
@@ -293,8 +294,8 @@
     Write(wxT("SuppressGuruHints"), suppressGuruHints);
     Write(wxT("SlonyPath"), slonyPath);
     Write(wxT("IndentSpaces"), indentSpaces);
+	Write(wxT("TabForCompletion"), tabForCompletion);
 
-
     Write(wxT("Export/Unicode"), exportUnicode);
     Write(wxT("Export/QuoteChar"), exportQuoteChar);
     Write(wxT("Export/ColSeparator"), exportColSeparator);
Index: src/utils/tab-complete.pl
===================================================================
--- src/utils/tab-complete.pl	(revision 0)
+++ src/utils/tab-complete.pl	(revision 0)
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+##########################################################################
+##
+## pgAdmin III - Tab completion
+## RCS-ID:      $Id$
+## Copyright (C) 2002 - 2006, The pgAdmin Development Team
+## This software is released under the Artistic Licence
+##
+## tab-complete.pl - Script to build tab-complete.inc 
+##
+##########################################################################
+
+
+# This script builds tab-complete.inc from tab-complete.c. The
+# source file (tab-complete.c) should be copied from the latest
+# PostgreSQL sources (src/bin/psql/tab-complete.c), so we don't
+# have to do all the work ourselves...
+
+use strict;
+use warnings;
+
+open(F, "tab-complete.c") || die("Could not open tab-complete.c!");
+undef $/;
+my $alltxt = <F>;
+close(F);
+
+# Get rid of everything before and after the parts we're interested in
+$alltxt =~ /.*(typedef struct SchemaQuery.*)\/\* GENERATOR FUNCTIONS\s+.*/s || die("Failed match 1");
+$alltxt = $1;
+
+# Get rid of forward declarations and initialize_readline
+$alltxt =~ /(.*)\/\*\s+Forward declaration of functions \*\/.*(\/\* The completion function\..*)/s || die("Failed match 2");
+$alltxt = $1 . $2;
+
+# Get rid of completion macros, we define them ourselves
+$alltxt =~ /(.*)\/\* A couple of macros to ease typing.*\*\/\s+#define COMPLETE_WITH_QUERY.*\s+(\/\*\s+\* Assembly instructions.*)/s || die("Failed match 4");
+$alltxt = $1 . $2;
+
+# Rewrite matches that don't use the macros
+$alltxt =~ s/completion_matches\(text, create_command_generator\)/complete_create_command\(text\)/gs || die("Failed match 5");
+$alltxt =~ s/completion_matches\(text, filename_completion_function\)/complete_filename\(\)/gs || die("Failed match 6");
+
+# We're going to return char*, not char**
+$alltxt =~ s/static char \*\*\s+psql_completion/static char \* psql_completion/s || die("Failed match 7");
+$alltxt =~ s/char\s+\*\*matches = NULL/char \*matches = NULL/s || die("Failed match 8");
+
+# Add an extra parameter to psql_completion
+$alltxt =~ s/psql_completion\(char \*text, int start, int end\)/psql_completion\(char \*text, int start, int end, void \*dbptr\)/s || die("Failed match 9");
+
+open(F,">tab-complete.inc") || die("Could not open tab-complete.inc!");
+print F $alltxt;
+print F "\n\n";
+close(F);
+
+print "Done.\n";
Index: src/utils/tabcomplete.c
===================================================================
--- src/utils/tabcomplete.c	(revision 0)
+++ src/utils/tabcomplete.c	(revision 0)
@@ -0,0 +1,394 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - Tab completion
+// RCS-ID:      $Id$
+// Copyright (C) 2002 - 2006, The pgAdmin Development Team
+// This software is released under the Artistic Licence
+//
+// tab-complete.cpp - Functions interfacing with tab-complete from psql
+//
+//////////////////////////////////////////////////////////////////////////
+
+/* 
+ * BUG: Must compile as C and not C++, becase of 
+ * http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B315481
+ * Adds a bit of C<->C++ cruft...
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libpq-fe.h>
+
+/*
+ * Callbacks to the C++ world
+ */
+char *pg_query_to_single_ordered_string(char *query, void *dbptr);
+
+
+/*
+ * Global vars for readline emulation
+ */
+static char *rl_line_buffer;
+
+/*
+ * Macros to ease typing present in psql, rewritten for our API
+ */
+#define COMPLETE_WITH_QUERY(query) \
+	do { matches = complete_from_query(text,query,NULL,dbptr); } while (0)
+#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
+	do { matches = complete_from_schema_query(text,&query, addon, dbptr); } while (0)
+#define COMPLETE_WITH_LIST(list) \
+	do { matches = complete_from_list(text,list); } while (0)
+#define COMPLETE_WITH_CONST(str) \
+	do { matches = complete_from_const(text,str); } while (0)
+#define COMPLETE_WITH_ATTR(table) \
+	do { matches = complete_from_query(text,Query_for_list_of_attributes, table, dbptr); } while (0)
+
+/*
+ * Functions used by the tab completion in psql normally found in pgport
+ */
+static void *pg_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+static int pg_strcasecmp(const char *s1, const char *s2)
+{
+	return stricmp(s1, s2);
+}
+
+static int pg_strncasecmp(const char *s1, const char *s2, int len)
+{
+	return strnicmp(s1, s2, len);
+}
+
+/*
+ * Return the word (space delimited) before point. Set skip > 0 to
+ * skip that many words; e.g. skip=1 finds the word before the
+ * previous one. Return value is NULL or a malloc'ed string.
+ *
+ * Copied directly from psql.
+ */
+static char *
+previous_word(int point, int skip)
+{
+	int			i,
+				start = 0,
+				end = -1,
+				inquotes = 0;
+	char	   *s;
+
+	while (skip-- >= 0)
+	{
+		/* first we look for a space before the current word */
+		for (i = point; i >= 0; i--)
+			if (rl_line_buffer[i] == ' ')
+				break;
+
+		/* now find the first non-space which then constitutes the end */
+		for (; i >= 0; i--)
+			if (rl_line_buffer[i] != ' ')
+			{
+				end = i;
+				break;
+			}
+
+		/*
+		 * If no end found we return null, because there is no word before the
+		 * point
+		 */
+		if (end == -1)
+			return NULL;
+
+		/*
+		 * Otherwise we now look for the start. The start is either the last
+		 * character before any space going backwards from the end, or it's
+		 * simply character 0
+		 */
+		for (start = end; start > 0; start--)
+		{
+			if (rl_line_buffer[start] == '"')
+				inquotes = !inquotes;
+			if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
+				break;
+		}
+
+		point = start;
+	}
+
+	/* make a copy */
+	s = (char *)pg_malloc(end - start + 2);
+
+	strncpy(s, &rl_line_buffer[start], end - start + 1);
+	s[end - start + 1] = '\0';
+
+	return s;
+}
+
+/* Find the parenthesis after the last word */
+/* Copied directly from psql */
+static int find_open_parenthesis(int end)
+{
+	int i = end-1;
+	
+	while((rl_line_buffer[i]!=' ')&&(i>=0))
+	{
+		if (rl_line_buffer[i]=='(') return 1;
+		i--;
+	}
+	while((rl_line_buffer[i]==' ')&&(i>=0))
+	{
+		i--;
+	}
+	if (rl_line_buffer[i]=='(')
+	{
+		return 1;       
+	}
+	return 0;
+
+}
+
+
+/*
+ * Forward declarations
+ */
+static char *complete_from_list(const char *text, const char * const *list);
+static char *complete_from_const(const char *text, const char *string);
+static char *complete_from_query(const char *text, const char *query, const char *addon, void *dbptr);
+static char *complete_from_schema_query(const char *text, const void* query, const char *addon, void *dbptr);
+static char *complete_create_command(char *text);
+static char *complete_filename();
+
+/*
+ * Include the main tab completion functionality from psql
+ */
+#include "tab-complete.inc"
+
+
+/*
+ * Completion functions mimicking those from psql, only returning a single space separated
+ * string instead of being called multiple times by the readline library.
+ */
+static char *_complete_from_list(const char *text, const char * const *list, int casesensitive)
+{
+	 int string_length = strlen(text);
+	 int size = 0;
+	 int i;
+	 char *r;
+
+	 for (i = 0; list[i] != NULL; i++)
+	 {
+		 if (casesensitive && strncmp(text, list[i], string_length) == 0)
+			 size += strlen(list[i]);
+		 if (!casesensitive && pg_strncasecmp(text, list[i], string_length) == 0)
+			 size += strlen(list[i]);
+	 }
+	 
+	 if (size == 0)
+		 return NULL;
+
+	 r = calloc(size + i*2, 1);
+	 for (i = 0; list[i] != NULL; i++)
+	 {
+		 if ((casesensitive && strncmp(text, list[i], string_length) == 0)
+			 ||
+			 (!casesensitive && pg_strncasecmp(text, list[i], string_length) == 0))
+		 {
+			strcat(r,list[i]);
+			strcat(r," \t");
+		 }
+	 }
+	 r[strlen(r)-1] = '\0'; /* Chop of trailing space */
+	 return r;
+}
+
+static char *complete_from_list(const char *text, const char * const *list)
+{
+	 char *r = _complete_from_list(text, list, 1);
+	 if (r)
+		 return r;
+	 return _complete_from_list(text, list, 0);
+}
+
+
+static char *complete_from_const(const char *text, const char *string)
+{
+	return strdup(string);
+}
+
+static char *_complete_from_query(const char *text, const char *query, const SchemaQuery *squery, const char *addon, void *dbptr)
+{
+	int string_length = strlen(text);
+	char *e_text;
+	char *e_addon = NULL;
+	char *complete_query = NULL;
+	char *t;
+
+	e_text = malloc(string_length*2+1);
+	PQescapeString(e_text, text, string_length);
+
+	if (addon) 
+	{
+		e_addon = malloc(strlen(addon)*2+1);
+		PQescapeString(e_addon, addon, strlen(addon));
+	}
+	else 
+		e_addon = strdup("");
+
+	if (query != NULL)
+	{
+		/* Normal query */
+		int bufsize = 1024;
+		while (1)
+		{
+			int r;
+			complete_query = realloc(complete_query, bufsize);
+			r = _snprintf(complete_query, bufsize, query, string_length, e_text, e_addon);
+			if (r < 0 || r >= bufsize)
+				bufsize *= 2;
+			else
+				break;
+		}
+	}
+	else
+	{
+		/* Schema query */
+		char *selcondition = NULL;
+		char *viscondition = NULL;
+		char *suppress_str = NULL;
+		const char *qualresult;
+		int bufsize = 2048;
+
+		if (squery->selcondition)
+		{
+			selcondition = malloc(strlen(squery->selcondition)+10);
+			sprintf(selcondition,"%s AND ",squery->selcondition);
+		}
+		else
+			selcondition = strdup("");
+
+		if (squery->viscondition)
+		{
+			viscondition = malloc(strlen(squery->viscondition)+10);
+			sprintf(viscondition, " AND %s",squery->viscondition);
+		}
+		else
+			viscondition = strdup("");
+
+		if (strcmp(squery->catname,"pg_catalog.pg_class c") == 0 &&
+			strncmp(text, "pg_", 3) != 0)
+			suppress_str = " AND c.relnamespace <> (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = 'pg_catalog')";
+		else
+			suppress_str = "";
+
+		qualresult = squery->qualresult;
+		if (qualresult == NULL)
+			qualresult = squery->result;
+
+		while (1)
+		{
+			int r;
+			complete_query = realloc(complete_query, bufsize);
+			r = _snprintf(complete_query, bufsize, 
+				"SELECT %s FROM %s WHERE %s substring(%s,1,%d)='%s' %s %s "
+				"\nUNION\n"
+				"SELECT pg_catalog.quote_ident(n.nspname) || '.' FROM pg_catalog.pg_namespace n WHERE substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d)='%s' AND (SELECT pg_catalog.count(*) FROM pg_catalog.pg_namespace WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)= substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1))>1"
+				"\nUNION\n"
+				"SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s FROM %s, pg_catalog.pg_namespace n WHERE %s = n.oid AND %s substring(pg_catalog.quote_ident(n.nspname) || '.' || %s,1,%d)='%s' AND substring(pg_catalog.quote_ident(n.nspname) || '.',1,%d) = substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(n.nspname))+1) AND (SELECT pg_catalog.count(*) FROM pg_catalog.pg_namespace WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d) = substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) = 1"
+				"\n%s",
+				squery->result,
+				squery->catname,
+				selcondition,
+				squery->result,
+				string_length,
+				e_text,
+				viscondition,
+				suppress_str,
+				string_length,
+				e_text,
+				string_length,
+				e_text,
+				qualresult,
+				squery->catname,
+				squery->namespace,
+				selcondition,
+				qualresult,
+				string_length,
+				e_text,
+				string_length,
+				e_text,
+				string_length,
+				e_text,
+				e_addon);
+			
+			if (r < 0 || r >= bufsize)
+				bufsize *= 2;
+			else
+				break;
+			
+		}
+		
+		free(viscondition);
+		free(selcondition);
+
+	}
+	t = pg_query_to_single_ordered_string(complete_query, dbptr);
+	if (complete_query)
+		free(complete_query);
+	free(e_addon);
+	free(e_text);
+	return t;
+}
+
+static char *complete_from_query(const char *text, const char *query, const char *addon, void *dbptr)
+{
+	return _complete_from_query(text, query, NULL, addon, dbptr);
+}
+
+static char *complete_from_schema_query(const char *text, const void* query, const char *addon, void *dbptr)
+{
+	/* query really is a SchemaQuery, but we don't know about SchemaQuery early enough. */
+	return _complete_from_query(text, NULL, (SchemaQuery *)query, addon, dbptr);
+}
+
+static char *complete_create_command(char *text)
+{
+	 int string_length = strlen(text);
+	 int size = 0;
+	 int i;
+	 char *r;
+
+	 for (i = 0; words_after_create[i].name != NULL; i++)
+	 {
+		 if (pg_strncasecmp(text, words_after_create[i].name, string_length) == 0)
+			 size += strlen(words_after_create[i].name);
+	 }
+
+	 r = calloc(size + i*2, 1);
+	 for (i = 0; words_after_create[i].name != NULL; i++)
+	 {
+		 if (pg_strncasecmp(text, words_after_create[i].name, string_length) == 0)
+		 {
+			strcat(r,words_after_create[i].name);
+			strcat(r," \t");
+		 }
+	 }
+	 r[strlen(r)-1] = '\0'; /* Chop of trailing space */
+	 return r;
+}
+
+/* Not implemented */
+static char *complete_filename()
+{
+	return NULL;
+}
+
+
+/*
+ * Entrypoint from the C++ world
+ */
+char *tab_complete(const char *allstr, const int startptr, const int endptr, void *dbptr)
+{
+	rl_line_buffer = (char *)allstr;
+	return psql_completion((char *)(allstr + startptr), startptr,endptr,dbptr);
+}
\ No newline at end of file
