From a77fcfcd5aa43ea33aa06001d2ab685ee2cdf084 Mon Sep 17 00:00:00 2001 From: levinsv Date: Mon, 18 Aug 2025 15:53:25 +0500 Subject: [PATCH] Autocomplite, server status, publications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлен контроль прав доступа на select для таблиц и представления при ипользовании автодополнения. Добавлен контроль доступа при пролучении информации о подписках. Добалена совместимость с более ранними версиями при получении информации о публикациях. При получении логов в окне "Статус сервера" добавлена проверка наличия прав на используемые функции при получении файлы логов. Мелкие правки при работе с автодополнениями в окне запросов. --- ctl/ctlSQLBox.cpp | 86 ++++++++++++++++++++------------------- frm/frmStatus.cpp | 8 ++-- schema/pgPublication.cpp | 24 ++++++++++- schema/pgSubscription.cpp | 61 ++++++++++++++------------- utils/tab-complete.inc | 81 +++++++++++++++++++++++++++++++----- utils/tabcomplete.c | 58 ++++++++++++++------------ 6 files changed, 207 insertions(+), 111 deletions(-) diff --git a/ctl/ctlSQLBox.cpp b/ctl/ctlSQLBox.cpp index 725d442..702fd24 100644 --- a/ctl/ctlSQLBox.cpp +++ b/ctl/ctlSQLBox.cpp @@ -800,56 +800,60 @@ void ctlSQLBox::OnKeyDown(wxKeyEvent &event) } if ((uc >= ' ' && uc < 'A')) hint = ""; } - if (m_hint_mode) { - if (event.GetKeyCode() == WXK_RIGHT && event.GetModifiers() == wxMOD_ALT && !hint.IsEmpty()) { - wxString ins = hint.substr(s.length()); - InsertText(GetCurrentPos(), ins); - SetCurrentPos(GetCurrentPos() + ins.Length()); - SetSelection(GetCurrentPos(), GetCurrentPos()); - CallTipCancel(); - m_hint_mode = false; - return; - } - if (hint.IsEmpty() && !(event.GetModifiers() == wxMOD_ALT || event.GetModifiers() == wxMOD_CONTROL)) { - m_hint_mode = false; - CallTipCancel(); + if (!AutoCompActive()) { + // work only hide autocomplite + + if (m_hint_mode) { + if (event.GetKeyCode() == WXK_RIGHT && event.GetModifiers() == wxMOD_ALT && !hint.IsEmpty()) { + wxString ins = hint.substr(s.length()); + InsertText(GetCurrentPos(), ins); + SetCurrentPos(GetCurrentPos() + ins.Length()); + SetSelection(GetCurrentPos(), GetCurrentPos()); + CallTipCancel(); + m_hint_mode = false; + return; + } + if (hint.IsEmpty() && !(event.GetModifiers() == wxMOD_ALT || event.GetModifiers() == wxMOD_CONTROL)) { + m_hint_mode = false; + CallTipCancel(); + } + else { + if (uc != WXK_NONE && !hint.IsEmpty()) { + if (uc == 8 && CallTipActive()) { + //CallTipSetPosAtStart(0); + CallTipSetHighlight(s.length(), hint.length()); + } + else { + CallTipShow(showpos, hint); + CallTipSetPosAtStart(0); + CallTipSetHighlight(s.length(), hint.length()); + m_hint_mode = true; + } + } + } } else { - if (uc != WXK_NONE && !hint.IsEmpty()) { - if (uc == 8 && CallTipActive()) { - //CallTipSetPosAtStart(0); - CallTipSetHighlight(s.length(), hint.length()); - } - else { - CallTipShow(showpos, hint); + if (!CallTipActive() && !hint.IsEmpty() && !(event.GetModifiers() == wxMOD_ALT || event.GetModifiers() == wxMOD_CONTROL)) { + if (uc != WXK_NONE) { + if (uc == 8) { + //showpos--; + showpos = showpos - 1; + } + else showpos += 1; + if (!CallTipActive()) CallTipShow(showpos, hint); CallTipSetPosAtStart(0); CallTipSetHighlight(s.length(), hint.length()); m_hint_mode = true; } - } - } - } - else { - if (!CallTipActive() && !hint.IsEmpty() && !(event.GetModifiers() == wxMOD_ALT || event.GetModifiers() == wxMOD_CONTROL)) { - if (uc != WXK_NONE) { - if (uc == 8) { - //showpos--; - showpos = showpos - 1; - } - else showpos += 1; - if (!CallTipActive()) CallTipShow(showpos, hint); - CallTipSetPosAtStart(0); - CallTipSetHighlight(s.length(), hint.length()); - m_hint_mode = true; - } - else { - if (CallTipActive()) { - CallTipCancel(); - m_hint_mode = false; + else { + if (CallTipActive()) { + CallTipCancel(); + m_hint_mode = false; + } } } - } + } } // } diff --git a/frm/frmStatus.cpp b/frm/frmStatus.cpp index 6606592..c5b76e8 100644 --- a/frm/frmStatus.cpp +++ b/frm/frmStatus.cpp @@ -277,7 +277,7 @@ frmStatus::frmStatus(frmMain *form, const wxString &_title, pgConn *conn) : pgFr (select pg_table_is_visible(viewname::regclass) and has_table_privilege(viewname::regclass,'select') from pg_views where viewname = 'pg_wait_sampling_history') as wsh, \ (select pg_table_is_visible(viewname::regclass) and has_table_privilege(viewname::regclass,'select') from pg_views v where viewname='pgpro_stats_statements') as pro, \ (select pg_table_is_visible(viewname::regclass) and has_table_privilege(viewname::regclass,'select') from pg_views v where viewname='pg_stat_statements') as std, \ - has_function_privilege('pg_read_binary_file(text,bigint,bigint,boolean)','execute') isreadlog \ + has_function_privilege('pg_read_binary_file(text,bigint,bigint,boolean)','execute') and has_function_privilege('pg_stat_file(text,boolean)','execute') and has_function_privilege('pg_ls_logdir()','execute') isreadlog \ "; pgSet* dataSet1 = connection->ExecuteSet(q); @@ -1192,7 +1192,7 @@ void frmStatus::AddLogPane() // if server release is less than 8.0 or if server has no adminpack if (!is_read_log) { logList->InsertColumn(logList->GetColumnCount(), _("Message"), wxLIST_FORMAT_LEFT, 700); - logList->AppendItemLong(-1, _("Function pg_read_binary_file(text,bigint,bigint,boolean) permission denied.")); + logList->AppendItemLong(-1, _("Functions pg_read_binary_file(text,bigint,bigint,boolean), pg_stat_file(text,boolean),pg_ls_logdir() permission denied.")); logList->Enable(false); logTimer = NULL; // We're done @@ -2738,6 +2738,8 @@ void frmStatus::OnRefreshLogTimer(wxTimerEvent &event) if (set->NumCols() == 0) { // error server // continue after + wxString errtext=connection->GetLastError(); + statusBar->SetStatusText("Error db: "+ errtext); return; } if (set->NumCols()>0 && !set->IsNull(0)) newlen = set->GetLong(wxT("len")); @@ -2926,7 +2928,7 @@ void frmStatus::addLogFile(const wxString &filename, const wxDateTime timestamp, #define PG_READ_BUFFER 500000 float pr = 100.0 * read / len; statusBar->SetStatusText(wxString::Format("%s %.2f MB (%.1f %%)", msg, len / 1048576.0, pr)); - wxString readsql = wxString::Format("select %s%s,%s, %d)", funcname, connection->qtDbString(filename), NumToStr(read), PG_READ_BUFFER); + wxString readsql = wxString::Format("select %s%s,%s, %d,true)", funcname, connection->qtDbString(filename), NumToStr(read), PG_READ_BUFFER); pgSet *set = connection->ExecuteSet(readsql); if (!set) { diff --git a/schema/pgPublication.cpp b/schema/pgPublication.cpp index fdce219..defd247 100644 --- a/schema/pgPublication.cpp +++ b/schema/pgPublication.cpp @@ -189,7 +189,8 @@ pgObject *pgPublicationFactory::CreateObjects(pgCollection *collection, ctlTree { wxString sql; pgPublication *publication = 0; - sql=R"(with rel as ( + if (collection->GetDatabase()->BackendMinimumVersion(15, 0)) { + sql = R"(with rel as ( SELECT pr.prpubid,quote_ident(n.nspname)|| '.'||quote_ident(c.relname) fulltable, pg_get_expr(pr.prqual, c.oid) rowfilter, (CASE WHEN pr.prattrs IS NOT NULL THEN pg_catalog.array_to_string( ARRAY(SELECT attname FROM @@ -207,6 +208,27 @@ p.pubviaroot,pt.rowfilter,pt.cols,pn.slist from pg_publication p LEFT JOIN rel pt ON pt.prpubid = p.oid LEFT JOIN shs pn ON p.oid = pn.pnpubid )"; + } + else { + sql = R"(with rel as ( +SELECT pr.prpubid,quote_ident(n.nspname)|| '.'||quote_ident(c.relname) fulltable, ''::text rowfilter, (CASE WHEN pr.prattrs IS NOT NULL THEN + pg_catalog.array_to_string( ARRAY(SELECT attname + FROM + pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s, + pg_catalog.pg_attribute + WHERE attrelid = c.oid AND attnum = prattrs[s]), ', ') + ELSE NULL END) cols +FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid + JOIN (select oid, prpubid, prrelid, ''::text prqual, null::int2vector prattrs from pg_catalog.pg_publication_rel pr ) pr ON c.oid = pr.prrelid +), shs as ( +select 0 pnpubid,''::text slist +) +select p.oid,p.pubname,pt.fulltable,pg_get_userbyid(p.pubowner) AS owner, p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, obj_description(p.oid,'pg_publication') AS comment, +p.pubviaroot,pt.rowfilter,pt.cols,pn.slist from pg_publication p + LEFT JOIN rel pt ON pt.prpubid = p.oid + LEFT JOIN shs pn ON p.oid = pn.pnpubid +)"; + } sql = sql + restriction + wxT("\n") wxT(" ORDER BY p.pubname,pt.fulltable"); pgSet *publications = collection->GetDatabase()->ExecuteSet(sql); diff --git a/schema/pgSubscription.cpp b/schema/pgSubscription.cpp index ed107ff..9688331 100644 --- a/schema/pgSubscription.cpp +++ b/schema/pgSubscription.cpp @@ -144,46 +144,49 @@ pgObject *pgSubscriptionFactory::CreateObjects(pgCollection *collection, ctlTree { wxString sql; pgSubscription *subscription = 0; - bool superu=collection->GetDatabase()->GetConnection()->IsSuperuser(); + //bool superu=collection->GetDatabase()->GetConnection()->IsSuperuser(); + bool superu = collection->GetServer()->GetSuperUser(); //wxString dbname=collection->GetDatabase()->GetConnection()->GetDbOid; OID db=collection->GetDatabase()->GetConnection()->GetDbOid(); sql = wxT("select oid,subname,pg_get_userbyid(subowner) AS \"owner\",subenabled,subconninfo,subslotname,subsynccommit,subpublications,obj_description(oid,'pg_subscription') as comment from pg_subscription where subdbid=") +NumToStr(db)+ wxT("\n") + restriction + wxT("\n"); - pgSet *subscriptions = collection->GetDatabase()->ExecuteSet(sql); + if (superu) { + pgSet* subscriptions = collection->GetDatabase()->ExecuteSet(sql); - if (subscriptions) - { - while (!subscriptions->Eof()) + if (subscriptions) { - wxString tmp; - tmp = subscriptions->GetVal(wxT("subpublications")); - tmp.Replace(wxT("{"), wxT("")); - tmp.Replace(wxT("}"), wxT("")); - - subscription = new pgSubscription(subscriptions->GetVal(wxT("subname"))); - subscription->iSetDatabase(collection->GetDatabase()); - subscription->iSetOid(subscriptions->GetOid(wxT("oid"))); - subscription->iSetOwner(subscriptions->GetVal(wxT("owner"))); - subscription->iSetPubStr(tmp); - subscription->iSetConnInfo(subscriptions->GetVal(wxT("subconninfo"))); - subscription->iSetSlotName(subscriptions->GetVal(wxT("subslotname"))); - //subscription->iSetName(subscriptions->GetVal(wxT("subname")); - subscription->iSetIsEnabled(subscriptions->GetBool(wxT("subenabled"))); - subscription->iSetIsSyncCommit(subscriptions->GetVal(wxT("subsynccommit"))); - subscription->iSetComment(subscriptions->GetVal(wxT("comment"))); - - if (browser) + while (!subscriptions->Eof()) { - browser->AppendObject(collection, subscription); + wxString tmp; + tmp = subscriptions->GetVal(wxT("subpublications")); + tmp.Replace(wxT("{"), wxT("")); + tmp.Replace(wxT("}"), wxT("")); - subscriptions->MoveNext(); + subscription = new pgSubscription(subscriptions->GetVal(wxT("subname"))); + subscription->iSetDatabase(collection->GetDatabase()); + subscription->iSetOid(subscriptions->GetOid(wxT("oid"))); + subscription->iSetOwner(subscriptions->GetVal(wxT("owner"))); + subscription->iSetPubStr(tmp); + subscription->iSetConnInfo(subscriptions->GetVal(wxT("subconninfo"))); + subscription->iSetSlotName(subscriptions->GetVal(wxT("subslotname"))); + //subscription->iSetName(subscriptions->GetVal(wxT("subname")); + subscription->iSetIsEnabled(subscriptions->GetBool(wxT("subenabled"))); + subscription->iSetIsSyncCommit(subscriptions->GetVal(wxT("subsynccommit"))); + subscription->iSetComment(subscriptions->GetVal(wxT("comment"))); + + if (browser) + { + browser->AppendObject(collection, subscription); + + subscriptions->MoveNext(); + } + else + break; } - else - break; - } - delete subscriptions; + delete subscriptions; + } } return subscription; } diff --git a/utils/tab-complete.inc b/utils/tab-complete.inc index 1f51254..ea44e35 100644 --- a/utils/tab-complete.inc +++ b/utils/tab-complete.inc @@ -66,6 +66,20 @@ static const SchemaQuery Query_for_list_of_aggregates = { /* qualresult */ NULL }; +static const SchemaQuery Query_for_list_of_publication = { + /* catname */ + "pg_catalog.pg_publication p", + /* selcondition */ + "pg_catalog.has_database_privilege(current_database(),'CREATE')", + /* viscondition */ + NULL, + /* namespace */ + "-", + /* result */ + "pg_catalog.quote_ident(p.pubname)", + /* qualresult */ + NULL +}; static const SchemaQuery Query_for_list_of_datatypes = { /* catname */ @@ -148,7 +162,49 @@ static const SchemaQuery Query_for_list_of_tables = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r')", + "c.relkind IN ('r') and pg_catalog.has_table_privilege(c.oid, 'select')", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL +}; +static const SchemaQuery Query_for_list_of_tables_insert = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "c.relkind IN ('r','v') and pg_catalog.has_table_privilege(c.oid, 'insert')", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL +}; +static const SchemaQuery Query_for_list_of_tables_update = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "c.relkind IN ('r','v') and pg_catalog.has_table_privilege(c.oid, 'update')", + /* viscondition */ + "pg_catalog.pg_table_is_visible(c.oid)", + /* namespace */ + "c.relnamespace", + /* result */ + "pg_catalog.quote_ident(c.relname)", + /* qualresult */ + NULL +}; +static const SchemaQuery Query_for_list_of_tables_delete = { + /* catname */ + "pg_catalog.pg_class c", + /* selcondition */ + "c.relkind IN ('r','v') and pg_catalog.has_table_privilege(c.oid, 'delete')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -178,7 +234,7 @@ static const SchemaQuery Query_for_list_of_tsv = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('r', 'S', 'v','m','f','p')", + "c.relkind IN ('r', 'S', 'v','m','f','p') and pg_catalog.has_table_privilege(c.oid, 'select')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -193,7 +249,7 @@ static const SchemaQuery Query_for_list_of_views = { /* catname */ "pg_catalog.pg_class c", /* selcondition */ - "c.relkind IN ('v')", + "c.relkind IN ('v') and pg_catalog.has_table_privilege(c.oid, 'select')", /* viscondition */ "pg_catalog.pg_table_is_visible(c.oid)", /* namespace */ @@ -249,7 +305,7 @@ static const SchemaQuery Query_for_list_of_views = { #define Query_for_list_of_schemas \ "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\ -" WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'" +" WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' and pg_catalog.has_schema_privilege(oid,'usage')" #define Query_for_list_of_set_vars \ "SELECT name FROM "\ @@ -329,7 +385,8 @@ typedef struct static const pgsql_thing_t words_after_create[] = { {"AGGREGATE", NULL, &Query_for_list_of_aggregates}, - {"PUBLICATION", NULL, NULL}, + {"PUBLICATION", NULL, &Query_for_list_of_publication}, + {"SUBSCRIPTION", NULL, NULL}, {"CAST", NULL, NULL}, /* Casts have complex structures for names, so * skip it */ @@ -428,6 +485,8 @@ static char * psql_completion(char *text, int start, int end, void *dbptr) /* If no previous word, suggest one of the basic sql commands */ else if (!prev_wd) COMPLETE_WITH_LIST(sql_commands); + else if (prev_wd[strlen(prev_wd)-1] == ',') + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* CREATE or DROP but not ALTER (TABLE|DOMAIN|GROUP) sth DROP */ /* complete with something you can create or drop */ @@ -448,9 +507,9 @@ static char * psql_completion(char *text, int start, int end, void *dbptr) pg_strcasecmp(prev3_wd, "TABLE") != 0) { static const char *const list_ALTER[] = - {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION", - "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SEQUENCE", "TABLE", - "TABLESPACE", "TRIGGER", "TYPE", "USER", NULL}; + {"AGGREGATE","CONVERSION","DATABASE","DOMAIN","FUNCTION","GROUP","INDEX","LANGUAGE" + ,"OPERATOR","PUBLICATION","ROLE","SCHEMA","SEQUENCE","SUBSCRIPTION","TABLE" + ,"TABLESPACE","TRIGGER","TYPE","USER", NULL}; COMPLETE_WITH_LIST(list_ALTER); } @@ -1058,7 +1117,7 @@ static char * psql_completion(char *text, int start, int end, void *dbptr) /* Complete DELETE FROM with a list of tables */ else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 && pg_strcasecmp(prev_wd, "FROM") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_delete, NULL); /* Complete DELETE FROM */ else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 && pg_strcasecmp(prev2_wd, "FROM") == 0) @@ -1273,7 +1332,7 @@ static char * psql_completion(char *text, int start, int end, void *dbptr) /* Complete INSERT INTO with table names */ else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 && pg_strcasecmp(prev_wd, "INTO") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_insert, NULL); /* Complete "INSERT INTO
(" with attribute names */ else if (rl_line_buffer[start - 1] == '(' && pg_strcasecmp(prev3_wd, "INSERT") == 0 && @@ -1553,7 +1612,7 @@ static char * psql_completion(char *text, int start, int end, void *dbptr) /* UPDATE */ /* If prev. word is UPDATE suggest a list of tables */ else if (pg_strcasecmp(prev_wd, "UPDATE") == 0) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables_update, NULL); /* Complete UPDATE
with "SET" */ else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0) COMPLETE_WITH_CONST("SET"); diff --git a/utils/tabcomplete.c b/utils/tabcomplete.c index 1d34ec5..26ce491 100644 --- a/utils/tabcomplete.c +++ b/utils/tabcomplete.c @@ -227,26 +227,26 @@ 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) +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 *complete_query = NULL; - char *t; + char* e_text; + char* complete_query = NULL; + char* t; - e_text = malloc(string_length*2+1); + e_text = malloc(string_length * 2 + 1); PQescapeString(e_text, text, string_length); if (query != NULL) { /* Normal query */ int bufsize = 1024; - char *e_addon; + char* e_addon; /* Normal query needs escaped string */ if (addon) { - e_addon = malloc(strlen(addon)*2+1); + e_addon = malloc(strlen(addon) * 2 + 1); PQescapeString(e_addon, addon, strlen(addon)); } else @@ -259,7 +259,7 @@ static char *_complete_from_query(const char *text, const char *query, const Sch #ifdef WIN32 r = _snprintf(complete_query, bufsize, query, string_length, e_text, e_addon); #else - r = snprintf(complete_query, bufsize, query, string_length, e_text, e_addon); + r = snprintf(complete_query, bufsize, query, string_length, e_text, e_addon); #endif if (r < 0 || r >= bufsize) bufsize *= 2; @@ -271,29 +271,29 @@ static char *_complete_from_query(const char *text, const char *query, const Sch else { /* Schema query */ - char *selcondition = NULL; - char *viscondition = NULL; - char *suppress_str = NULL; - const char *qualresult; + 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); + 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); + 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 && + 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 @@ -308,15 +308,15 @@ static char *_complete_from_query(const char *text, const char *query, const Sch int r; complete_query = realloc(complete_query, bufsize); #ifdef WIN32 - r = _snprintf(complete_query, bufsize, + r = _snprintf(complete_query, bufsize, #else - r = snprintf(complete_query, bufsize, + r = snprintf(complete_query, bufsize, #endif "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" + "SELECT pg_catalog.quote_ident(n.nspname) || '.' FROM pg_catalog.pg_namespace n WHERE pg_catalog.has_schema_privilege(n.oid,'usage') and 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" + "SELECT pg_catalog.quote_ident(n.nspname) || '.' || %s FROM %s, pg_catalog.pg_namespace n WHERE pg_catalog.has_schema_privilege(n.oid,'usage') and %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, @@ -341,15 +341,21 @@ static char *_complete_from_query(const char *text, const char *query, const Sch e_text, string_length, e_text, - addon?addon:""); - + addon ? addon : ""); + if (r < 0 || r >= bufsize) bufsize *= 2; else - break; - + { + // namespace=='-' + if (squery->namespace[0] == '-') { + char* newlinePtr = strchr(complete_query, '\n'); + if (newlinePtr != NULL) *newlinePtr = '\0'; + + } + } + break; } - free(viscondition); free(selcondition);