mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
Added the possibility of contextual help on user functions.
Добавлена возможность просмотра скриптов создания пользовательских объектов в контестной помощи. В скриптах имена других объектов заменяются на ссылки. Описание Readme.md
This commit is contained in:
parent
560bf4c080
commit
1f7decd73f
18 changed files with 1016 additions and 159 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -5,7 +5,8 @@
|
|||
"*.inc": "c",
|
||||
"vector": "cpp",
|
||||
"string.h": "c",
|
||||
"libpq-fe.h": "c"
|
||||
"libpq-fe.h": "c",
|
||||
"new": "cpp"
|
||||
},
|
||||
"cmake.configureArgs": [
|
||||
|
||||
|
|
|
|||
|
|
@ -98,18 +98,21 @@ endif()
|
|||
if(CROSS_COMPILE STREQUAL "Windows")
|
||||
#add_compile_definitions(_CRT_SECURE_NO_DEPRECATE=1 NDEBUG WIN32 _WINDOWS __WINDOWS__ __WIN95__ __WIN32__ WINVER=0x0500 STRICT __WXMSW__ WXUSINGDLL wxUSE_UNICODE=1 PG_SSL)
|
||||
add_compile_definitions(NDEBUG WIN32 WXPRECOMP WINVER=0x0600 STRICT wxUSE_UNICODE=1 PG_SSL)
|
||||
set(WXWIN /home/sergey/k/wxMSW-3.2.2 )
|
||||
set(PGDIR /home/sergey/k/pg10 )
|
||||
set(PGBUILD /home/sergey/k )
|
||||
##set(WXWIN /home/sergey/k/wxMSW-3.2.2 )
|
||||
##set(PGDIR /home/sergey/k/pg17 )
|
||||
##set(PGBUILD /home/sergey/k )
|
||||
#set(/home/sergey/k/openssl )
|
||||
#set(PROJECTDIR /home/sergey/k/openssl )
|
||||
include_directories(${WXWIN}/include ${PGDIR}/include ${PGDIR}/include/server )
|
||||
include_directories(${PGBUILD}/libxml2/include ${PGBUILD}/libxslt/include ${PGBUILD}/iconv/include )
|
||||
# include_directories(${PGBUILD}/openssl/include
|
||||
# include_directories( ./include/libssh2 ./include/libssh2/Win32 )
|
||||
else()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -402,3 +402,13 @@ English version issue #18
|
|||
Выделеный текст в окне подсказки при нажатии правой кнопки используется как строка поиска.
|
||||
* Исправлен запрос получения информации о серверах и теперь он работает быстрее.
|
||||
Добавлена информация в строку статуса о времени работы запроса.
|
||||
|
||||
21.11.2025
|
||||
|
||||
- Контекстная справка по функциям доросла до гипертекстовой навигации по функция, таблицам, триггерам.
|
||||
Выделенное выражение будет проверятся по именам объектов БД и если такие будут найдены то
|
||||
скрипт создания будет выдаваться как справка по объекту. Скрипт анализируется на вызовы функций,
|
||||
имена таблиц и представлений, которые заменяются ссылки. Анализ не точный поэтому возможны
|
||||
не корректные ссылки. Переход назад по правой кнопке мыши.
|
||||
|
||||
- Добавлен каталог для тестов, но они будут работать только при компиляции в linux.
|
||||
|
|
|
|||
|
|
@ -643,8 +643,11 @@ void ctlSQLBox::OnFuncHelp(wxCommandEvent& ev) {
|
|||
wxPoint p = ClientToScreen( PointFromPosition(pos));
|
||||
wxString current = GetSelectedText();
|
||||
wxString key = "";
|
||||
fh->setDbConn(m_database);
|
||||
if (!current.IsEmpty())
|
||||
{
|
||||
key = current;
|
||||
}
|
||||
else {
|
||||
wxChar ch;
|
||||
wxString tmp;
|
||||
|
|
@ -660,12 +663,12 @@ void ctlSQLBox::OnFuncHelp(wxCommandEvent& ev) {
|
|||
}
|
||||
delete m_PopupHelp;
|
||||
wxSize rr(450, 370);
|
||||
m_PopupHelp = new popuphelp(this->GetParent(), key.Lower(), fh,p,rr);
|
||||
m_PopupHelp = new popuphelp(this->GetParent(), key, fh,p,rr);
|
||||
if (m_PopupHelp && m_PopupHelp->IsValid() && rr != m_PopupHelp->GetSizePopup()) {
|
||||
// recreate with new size
|
||||
rr = m_PopupHelp->GetSizePopup();
|
||||
delete m_PopupHelp;
|
||||
m_PopupHelp = new popuphelp(this->GetParent(), key.Lower(), fh, p, rr);
|
||||
m_PopupHelp = new popuphelp(this->GetParent(), key, fh, p, rr);
|
||||
|
||||
}
|
||||
if (m_PopupHelp && m_PopupHelp->IsValid()) {
|
||||
|
|
@ -1766,7 +1769,7 @@ void ctlSQLBox::OnMarginClick(wxStyledTextEvent &event)
|
|||
|
||||
event.Skip();
|
||||
}
|
||||
wxString ctlSQLBox::TextToHtml(int start, int end,bool isAddNewLine) {
|
||||
wxString ctlSQLBox::TextToHtml(int start, int end,bool isAddNewLine, const std::vector<FSQL::complite_element> &listobj) {
|
||||
wxColor frColor[40];
|
||||
wxString str;
|
||||
wxColour frc = settings->GetSQLBoxColourForeground();
|
||||
|
|
@ -1807,6 +1810,12 @@ wxString ctlSQLBox::TextToHtml(int start, int end,bool isAddNewLine) {
|
|||
//if (isAddNewLine) newline = L"⤶<br>";
|
||||
//if (isAddNewLine) newline = L"<br>\x0b78";
|
||||
int lenstr = selText.Length();
|
||||
int IndexObj=0;
|
||||
int pos=999999999;
|
||||
wxString obj;
|
||||
int lenobj;
|
||||
if (listobj.size()>0) {pos=listobj[IndexObj].startIndex; obj=listobj[IndexObj].table;lenobj=obj.Len();}
|
||||
wxString lstr;
|
||||
while (k<lenstr) {
|
||||
int st = GetStyleAt(startp);
|
||||
if (st < 34) tColor = frColor[st].GetAsString(wxC2S_HTML_SYNTAX);
|
||||
|
|
@ -1817,20 +1826,36 @@ wxString ctlSQLBox::TextToHtml(int start, int end,bool isAddNewLine) {
|
|||
//str.append(str[k].GetValue());
|
||||
l = 1;
|
||||
wxUniChar c = selText[k];
|
||||
|
||||
if (!c.IsAscii()) l++;
|
||||
int s = 0;
|
||||
//wxUniChar c = selText[k].GetValue();
|
||||
if (c == '\r') { startp = startp + l; k++; continue; };
|
||||
|
||||
if (c == '\n') { str += newline; startp = startp + l; k++; continue; };
|
||||
if (c == '\n') { lstr += newline; startp = startp + l; k++; continue; };
|
||||
if (c == 9) s = 5;
|
||||
if (c == 32) s = 1;
|
||||
if (c == '<') { str+="<"; startp = startp + l; k++; continue; };
|
||||
if (c == '>') { str+=">"; startp = startp + l; k++; continue; };
|
||||
if (c == '&') { str+="&"; startp = startp + l; k++; continue; };
|
||||
if (s > 0) for (int tt = 0; tt < s; tt++) str += wxT(" ");
|
||||
else str += c;
|
||||
if (c == '<') { lstr+="<"; startp = startp + l; k++; continue; };
|
||||
if (c == '>') { lstr+=">"; startp = startp + l; k++; continue; };
|
||||
if (c == '&') { lstr+="&"; startp = startp + l; k++; continue; };
|
||||
if (s > 0) for (int tt = 0; tt < s; tt++) lstr += " ";
|
||||
else lstr += c;
|
||||
startp = startp + l; k++;
|
||||
if ((k-1)>=pos) {
|
||||
lenobj--;
|
||||
if (lenobj==0) {
|
||||
wxString s,n;
|
||||
make_identifier(obj,s,n,true);
|
||||
if (!s.IsEmpty()) obj=s+'.'+n; else obj=n;
|
||||
lstr=wxString::Format("<a href=\"%s\">%s</a>", obj, lstr);
|
||||
IndexObj++;
|
||||
if (listobj.size()>IndexObj) { pos=listobj[IndexObj].startIndex; obj=listobj[IndexObj].table; lenobj=obj.Len();}
|
||||
else pos=999999999;
|
||||
} else
|
||||
continue; // link not ready
|
||||
}
|
||||
str += lstr;
|
||||
lstr="";
|
||||
}
|
||||
str = str + wxT("</font></div>");
|
||||
return str;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public:
|
|||
void Create(wxWindow *parent, wxWindowID id = -1, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 0);
|
||||
void HighlightBrace(int start, int len,int indicator);
|
||||
void SetDatabase(pgConn *db);
|
||||
wxString TextToHtml(int start, int end, bool isAddNewLine=false);
|
||||
wxString TextToHtml(int start, int end, bool isAddNewLine=false, const std::vector<FSQL::complite_element> &listobj = {});
|
||||
void Copy();
|
||||
void OnKeyDown(wxKeyEvent &event);
|
||||
void OnAutoComplete(wxCommandEvent &event);
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@
|
|||
#include "schema/gpExtTable.h"
|
||||
#include "schema/gpPartition.h"
|
||||
#include "schema/gpResQueue.h"
|
||||
#include "schema/pgPartition.h"
|
||||
|
||||
#include "slony/dlgRepCluster.h"
|
||||
#include "slony/dlgRepListen.h"
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ namespace FSQL {
|
|||
{ "left", 4, new_line_align_next },
|
||||
{ "full", 4, new_line_align_next },
|
||||
{ "then", 4, none},
|
||||
{ "loop", 4, none}, // for plpgsql
|
||||
{ "into", 4, none},
|
||||
{ "last", 4, none},
|
||||
{ "next", 4, none},
|
||||
|
|
@ -86,6 +87,9 @@ namespace FSQL {
|
|||
{ "sets", 4, none},
|
||||
{ "where", 5, new_line_align_no_pad | end_from},
|
||||
{ "outer", 5, none},
|
||||
{ "grant", 5, none},
|
||||
{ "begin", 5, none}, //plpgsql
|
||||
{ "while", 5, none}, //plpgsql
|
||||
{ "union", 5, new_line_align_no_pad | end_from},
|
||||
{ "order", 5, new_line_align_no_pad | end_from},
|
||||
{ "limit", 5, new_line_align_no_pad | end_from},
|
||||
|
|
@ -106,9 +110,11 @@ namespace FSQL {
|
|||
{ "except", 6, new_line_align_no_pad | end_from},
|
||||
{ "offset", 6, none | end_from},
|
||||
{ "cursor", 6, none},
|
||||
{ "create", 6, none},
|
||||
{ "nothing", 7, none},
|
||||
{ "lateral", 7, none},
|
||||
{ "between", 7, none},
|
||||
{ "comment", 7, none},
|
||||
|
||||
{ "nothing", 7, none},
|
||||
{ "default", 7, none},
|
||||
|
|
@ -149,11 +155,13 @@ namespace FSQL {
|
|||
FormatterSQL(const wxString& sqlsrc) {
|
||||
sql = sqlsrc;
|
||||
}
|
||||
std::vector<complite_element> ParsePLpgsql();
|
||||
void Formating(wxDC& d, wxRect re, bool isTest = false); // draw
|
||||
wxString Formating(wxRect re); //
|
||||
//
|
||||
wxString BuildAutoComplite(int startIndex, int level);
|
||||
wxString GetListTable(int cursorPos);
|
||||
wxString GetListTable(const std::vector<complite_element> &list);
|
||||
wxString GetColsList(wxString what, wxString& listfieldOut, wxString& nameTableOut);
|
||||
/// <summary>
|
||||
/// Возращает количество таблиц слева от курсора и заполняет их имена и псевдонимы.
|
||||
|
|
@ -166,11 +174,13 @@ namespace FSQL {
|
|||
void SetSql(const wxString& sqlsrc) { sql = sqlsrc; lastposition = 0; }
|
||||
int GetIndexItemNextSqlPosition(int sqlPosition);
|
||||
int GetNextPositionSqlParse();
|
||||
|
||||
bool GetItem(int index, FSQL::view_item& item);
|
||||
int next_item_no_space(int& index, int direction = 1);
|
||||
private:
|
||||
wxString get_list_columns(int startindex, union FSQL::Byte zone);
|
||||
|
||||
void _addfunc(const view_item *vi);
|
||||
void _addfunc_in_braket(int start,int end);
|
||||
wxPoint align_level(int start_i, int level, int Xpos, int Ypos, int flag);
|
||||
int check_bracket(int index);
|
||||
int get_prev_value(int indx, wxString keyword);
|
||||
|
|
@ -185,8 +195,10 @@ namespace FSQL {
|
|||
wxRect rect;
|
||||
wxString sql;
|
||||
int lastposition = 0;
|
||||
int errorposition=-1;
|
||||
std::vector<FSQL::view_item> items;
|
||||
std::vector<FSQL::complite_element> listTable; // перечень таблиц синонимов, подзапросов и функций с колонками
|
||||
std::vector<FSQL::complite_element> listFunction; // перечень функций используемых в запросе
|
||||
//int recurse(int level);
|
||||
};
|
||||
}
|
||||
|
|
@ -5,16 +5,11 @@
|
|||
#include <wx/regex.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/textfile.h>
|
||||
#include <wx/filename.h>
|
||||
|
||||
extern sysSettings* settings;
|
||||
|
||||
class FunctionPGHelper
|
||||
{
|
||||
public:
|
||||
FunctionPGHelper() {};
|
||||
FunctionPGHelper() {dblast=NULL;};
|
||||
/// <summary>
|
||||
/// Создать только переданный в конструкторе html текст с именем "content"
|
||||
/// </summary>
|
||||
|
|
@ -23,6 +18,7 @@ public:
|
|||
body.clear();
|
||||
Add("content", content);
|
||||
isload = true;
|
||||
dblast=NULL;
|
||||
};
|
||||
int Size() {
|
||||
return body.size();
|
||||
|
|
@ -30,126 +26,23 @@ public:
|
|||
void SetTimerClose(int ms) { m_interval = ms; }
|
||||
int GetTimerClose() { return m_interval; }
|
||||
void Add(const wxString& key, const wxString& v) { body.emplace(key, v); }
|
||||
wxString getHelpString(wxString fnd, bool isPart = true) {
|
||||
if (!isValid()) return wxEmptyString;
|
||||
auto search = body.find(fnd);
|
||||
wxString txt;
|
||||
|
||||
if (search != body.end())
|
||||
txt = search->second;
|
||||
else
|
||||
{
|
||||
std::vector<wxString> list;
|
||||
int l = fnd.Len();
|
||||
wxString b;
|
||||
for (const auto& e : body) {
|
||||
if (e.first.Len() > l && e.first.StartsWith(fnd)) {
|
||||
list.push_back(e.first);
|
||||
b = e.second;
|
||||
}
|
||||
}
|
||||
if (list.size() == 1) txt = b;
|
||||
else {
|
||||
for (const auto& s : list) {
|
||||
txt += wxString::Format("<a href=\"%s\">%s</a><br>", s, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (i == wxNOT_FOUND) return wxEmptyString;
|
||||
return txt;
|
||||
}
|
||||
wxString getSqlCommandHelp(wxString fnd) {
|
||||
wxUniChar sep = wxFileName::GetPathSeparator();
|
||||
fnd.Replace(" ", "");
|
||||
wxString f = wxFindFirstFile(path + sep + "sql-" + fnd + "*.html");
|
||||
wxString last, txt;
|
||||
|
||||
int c = 0;
|
||||
while (!f.empty())
|
||||
{
|
||||
f = f.AfterLast(sep);
|
||||
last = f;
|
||||
txt += wxString::Format("<a href=\"%s\">%s</a><br>", f, f);
|
||||
f = wxFindNextFile();
|
||||
c++;
|
||||
}
|
||||
if (last.empty()) {
|
||||
return wxEmptyString;
|
||||
}
|
||||
else if (c == 1) {
|
||||
return getHelpFile(last);
|
||||
}
|
||||
else {
|
||||
return txt;
|
||||
}
|
||||
|
||||
}
|
||||
wxString getHelpFile(wxString filename) {
|
||||
wxString tempDir = path + wxFileName::GetPathSeparator() + filename;
|
||||
if (!wxFileExists(tempDir)) return wxEmptyString;
|
||||
wxTextFile tfile;
|
||||
tfile.Open(tempDir);
|
||||
// read the first line
|
||||
wxString str, sbody;
|
||||
sbody = tfile.GetFirstLine();
|
||||
bool flag = true;
|
||||
wxRegEx b("(<body .*?>)");
|
||||
while (!tfile.Eof())
|
||||
{
|
||||
str = tfile.GetNextLine();
|
||||
if (flag && b.Matches(str)) {
|
||||
size_t start, len;
|
||||
b.GetMatch(&start, &len, 0);
|
||||
str = str.Mid(start + len);
|
||||
sbody = "<body>";
|
||||
flag = false;
|
||||
}
|
||||
sbody += str;
|
||||
}
|
||||
return sbody;
|
||||
|
||||
}
|
||||
bool isValid() {
|
||||
if (!isload) loadfile();
|
||||
return isload;
|
||||
}
|
||||
wxString getHelpString(wxString fnd, bool isPart = true) ;
|
||||
wxString getHelpFile(wxString filename);
|
||||
wxString getSqlCommandHelp(wxString fnd);
|
||||
bool isValid();
|
||||
void setDbConn(pgConn *db);
|
||||
// Ищем ключевое слово в объектах БД
|
||||
wxString getDBinfoKeyword(wxString objname,bool islower);
|
||||
// Ищем файлы справки для команд sql
|
||||
private:
|
||||
bool isload = false;
|
||||
int m_interval = -1;
|
||||
wxString path;
|
||||
std::map<wxString, wxString> body;
|
||||
void loadfile() {
|
||||
if (isload) return;
|
||||
body.clear();
|
||||
path = settings->GetPgHelpPath();
|
||||
wxString tempDir = path + "_func.txt";
|
||||
//tempDir="C:\\Users\\lsv\\Source\\Repos\\wxHtmlhint\\1";
|
||||
if (!wxFileExists(tempDir)) return;
|
||||
wxTextFile tfile;
|
||||
tfile.Open(tempDir);
|
||||
|
||||
// read the first line
|
||||
wxString str, sbody;
|
||||
wxString name = tfile.GetFirstLine();
|
||||
|
||||
//wxSortedArrayString names;
|
||||
name = name.AfterFirst('#');
|
||||
// read all lines one by one
|
||||
// until the end of the file
|
||||
while (!tfile.Eof())
|
||||
{
|
||||
str = tfile.GetNextLine();
|
||||
if (str.Left(1) == '#') {
|
||||
body.emplace(name, sbody);
|
||||
sbody = "";
|
||||
name = str.AfterFirst('#');
|
||||
}
|
||||
else sbody += str;
|
||||
}
|
||||
body.emplace(name, sbody);
|
||||
isload = true;
|
||||
};
|
||||
// db connect
|
||||
pgConn *dblast;
|
||||
|
||||
void loadfile();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -279,5 +279,7 @@ wxString commandLineCleanOption(const wxString &option, bool schemaObject = fals
|
|||
wxString qtIdent(const wxString &value); // add " if necessary
|
||||
wxString qtTypeIdent(const wxString &value); // add " if necessary
|
||||
|
||||
bool make_identifier(const wxString &strname, wxString &s, wxString &n, bool islower);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -60,13 +60,17 @@ public:
|
|||
|
||||
htmlWindow->SetRelatedStatusBar(0);
|
||||
//htmlWindow->SetPage("<html><body><h1>TEST</h1><span fgcolor=\"#332233\">Set Page Works</span></body></hmtl>");
|
||||
wxString txt = hhelper->getHelpString(keyword);
|
||||
|
||||
wxString txt;
|
||||
txt=hhelper->getDBinfoKeyword(keyword,true);
|
||||
if (txt.IsEmpty()) {
|
||||
|
||||
txt = hhelper->getSqlCommandHelp(keyword);
|
||||
txt = hhelper->getHelpString(keyword.Lower());
|
||||
if (txt.empty()) {
|
||||
isvalid = false;
|
||||
return;
|
||||
txt = hhelper->getSqlCommandHelp(keyword.Lower());
|
||||
if (txt.empty()) {
|
||||
isvalid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
SetPage(txt);
|
||||
|
|
@ -131,9 +135,13 @@ public:
|
|||
this->Bind(wxEVT_HTML_LINK_CLICKED, [&](wxHtmlLinkEvent& event) {
|
||||
wxHtmlLinkInfo i = event.GetLinkInfo();
|
||||
wxString name = i.GetHref();
|
||||
wxString body=this->hhelper->getHelpString(name);
|
||||
wxString body;
|
||||
body=this->hhelper->getDBinfoKeyword(name,false);
|
||||
if (body.IsEmpty()) {
|
||||
body = this->hhelper->getHelpFile(name);
|
||||
body=this->hhelper->getHelpString(name);
|
||||
if (body.IsEmpty()) {
|
||||
body = this->hhelper->getHelpFile(name);
|
||||
}
|
||||
}
|
||||
SetPage(body);
|
||||
//ctext=htmlWindow->SelectionToText();
|
||||
|
|
@ -153,12 +161,15 @@ public:
|
|||
//wxString body = this->hhelper->getHelpString(name);
|
||||
wxString ctext = htmlWindow->SelectionToText();
|
||||
if (!ctext.IsEmpty()) {
|
||||
wxClipboardLocker clip;
|
||||
if (!clip ||
|
||||
!wxTheClipboard->AddData(new wxTextDataObject(ctext)))
|
||||
if (wxTheClipboard->Open())
|
||||
{
|
||||
|
||||
wxDataObjectComposite* dataobj = new wxDataObjectComposite();
|
||||
dataobj->Add(new wxTextDataObject(ctext));
|
||||
//dataobj->Add(new wxHTMLDataObject(str));
|
||||
wxTheClipboard->SetData(dataobj);
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
|
||||
wxString wname = GetParent()->GetName();
|
||||
if (wname == "frmStatus") {
|
||||
//CMD_EVENT_FIND_STR
|
||||
|
|
@ -203,6 +214,7 @@ private:
|
|||
wxSize sizew;
|
||||
FunctionPGHelper* hhelper;
|
||||
std::vector<wxString> hist;
|
||||
std::vector<wxPoint> hist_viewp;
|
||||
void SetPage(wxString innerbody,bool gethistory=false) {
|
||||
wxString h;
|
||||
int p = innerbody.Find("<body>");
|
||||
|
|
@ -224,9 +236,22 @@ private:
|
|||
h = hist[hist.size()-1];
|
||||
}
|
||||
else {
|
||||
if (hist.size()>0) {
|
||||
wxPoint ps=htmlWindow->GetViewStart();
|
||||
hist_viewp.push_back(ps);
|
||||
}
|
||||
hist.push_back(h);
|
||||
}
|
||||
htmlWindow->SetPage(h);
|
||||
if (gethistory && hist_viewp.size()>0) {
|
||||
wxPoint ps=hist_viewp[hist_viewp.size()-1];
|
||||
hist_viewp.pop_back();
|
||||
htmlWindow->Scroll(ps);
|
||||
} else {
|
||||
//
|
||||
wxPoint ps(0,0);
|
||||
htmlWindow->Scroll(ps);
|
||||
}
|
||||
}
|
||||
private:
|
||||
wxTimer *closeTimer=NULL;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(WXWIN_LIB /home/sergey/wxWidgets-3.2.2.1/msw-build/lib )
|
||||
set(WXWIN /home/sergey/k/wxMSW-3.2.2 )
|
||||
set(PGDIR /home/sergey/k/pg10 )
|
||||
set(PGDIR /home/sergey/k/pg17 )
|
||||
set(PGBUILD /home/sergey/k )
|
||||
set(wxWidgets_LIBRARIES "-L${WXWIN_LIB} -lwx_mswu_xrc-3.2-x86_64-w64-mingw32.dll -lwx_mswu_qa-3.2-x86_64-w64-mingw32.dll -lwx_baseu_net-3.2-x86_64-w64-mingw32.dll -lwx_mswu_html-3.2-x86_64-w64-mingw32.dll -lwx_mswu_core-3.2-x86_64-w64-mingw32.dll -lwx_baseu_xml-3.2-x86_64-w64-mingw32.dll -lwx_baseu-3.2-x86_64-w64-mingw32.dll -lwx_mswu_aui-3.2-x86_64-w64-mingw32.dll -lwx_baseu_xml-3.2-x86_64-w64-mingw32.dll -lwx_mswu_stc-3.2-x86_64-w64-mingw32.dll")
|
||||
set(PGLIB "-L${PGDIR}/lib -lpq -lxml2")
|
||||
|
|
|
|||
|
|
@ -490,6 +490,7 @@
|
|||
<ClCompile Include="utils\sysLogger.cpp" />
|
||||
<ClCompile Include="utils\sysProcess.cpp" />
|
||||
<ClCompile Include="utils\sysSettings.cpp" />
|
||||
<ClInclude Include="utils\FunctionPGHelper.cpp" />
|
||||
<ClCompile Include="utils\tabcomplete.c">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</PrecompiledHeader>
|
||||
|
|
|
|||
|
|
@ -808,6 +808,9 @@
|
|||
<ClCompile Include="utils\csvfiles.cpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="utils\FunctionPGHelper.cpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="utils\factory.cpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
|||
17
tests/CMakeLists.txt
Normal file
17
tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
find_package(Catch2)
|
||||
add_executable(test_Formatter test_Formatter.cpp ../utils/FormatterSQL.cpp)
|
||||
#target_include_directories(test_Formatter PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
#target_link_libraries(test_Formatter Catch2::Catch2)
|
||||
|
||||
|
||||
#add_library(test_sources test_Formatter.cpp )
|
||||
#target_link_libraries(test_sources Catch2::Catch2)
|
||||
|
||||
#add_executable(tests test.cpp)
|
||||
#target_link_libraries(tests -Wl,--whole-archive test_sources -Wl,--no-whole-archive)
|
||||
#target_link_libraries(tests Catch2::Catch2)
|
||||
|
||||
#include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(test_Formatter)
|
||||
325
tests/test_Formatter.cpp
Normal file
325
tests/test_Formatter.cpp
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
||||
#include <catch2/catch.hpp>
|
||||
#include "utils/FormatterSQL.h"
|
||||
|
||||
using namespace FSQL;
|
||||
|
||||
TEST_CASE( "FormatterSQL build autocomplite", "[fmtsql]" ) {
|
||||
wxString s = "select a.* from a aa,b";
|
||||
FormatterSQL f(s);
|
||||
wxString act1;
|
||||
wxString act,cl,t,exp;
|
||||
SECTION( "Простой запрос" ) {
|
||||
int e = f.ParseSql(0);
|
||||
act1=f.BuildAutoComplite(0, 0);
|
||||
wxString act2 = f.GetListTable(0);
|
||||
exp = "[ a,aa] \n[ b,] \n";
|
||||
CHECK(act2==exp);
|
||||
}
|
||||
SECTION( "GetColsList cols" ) {
|
||||
int e = f.ParseSql(0);
|
||||
act1=f.BuildAutoComplite(0, 0);
|
||||
act1 = f.GetColsList("aa.f1",cl, t);
|
||||
CHECK(act1.ToStdWstring().length()==0 );
|
||||
}
|
||||
SECTION( "GetColsList table" ) {
|
||||
int e = f.ParseSql(0);
|
||||
act1=f.BuildAutoComplite(0, 0);
|
||||
act1 = f.GetColsList("aa.f1", cl, t);
|
||||
CHECK( t=="a");
|
||||
}
|
||||
SECTION( "GetColsList cols 2" ) {
|
||||
int e = f.ParseSql(0);
|
||||
act1=f.BuildAutoComplite(0, 0);
|
||||
act1 = f.GetColsList("b.*", cl, t);
|
||||
CHECK(act1.ToStdWstring().length()==0);
|
||||
}
|
||||
SECTION( "GetColsList table 2" ) {
|
||||
int e = f.ParseSql(0);
|
||||
act1 = f.BuildAutoComplite(0, 0);
|
||||
act1 = f.GetColsList("b.*", cl, t);
|
||||
CHECK(t=="b");
|
||||
}
|
||||
SECTION( "Функция 1" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from f() a");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ @,a] \n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "func2" ) {
|
||||
int e;
|
||||
FSQL::FormatterSQL f3(L"select now() from f() a(f1,\"ф2\")");
|
||||
wxString act3;
|
||||
e = f3.ParseSql(0);
|
||||
CHECK(e==0);
|
||||
act = f3.BuildAutoComplite(0, 0); act = f3.GetListTable(0);
|
||||
exp=R"([ @,a] f1,"ф2"
|
||||
)";
|
||||
CHECK(act3==exp);
|
||||
act3 = f3.GetListTable(1);
|
||||
//act3=f3.printParseArray();
|
||||
//act3=wxString::Format(" len: %d",act3.Len());
|
||||
exp = "[ now,] \n[ f,] \n[ a,] \n";
|
||||
//std::cerr << act3;
|
||||
CHECK(act3==exp);
|
||||
}
|
||||
SECTION( "Функция 2a" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from f(p1,(1+2)) a(f1 int,\"ф2\" text)");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ @,a] f1,\"ф2\"\n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "Функция 2b" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from f(p1,(1+2)) a(f1 int,\"ф2\" text), t2");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ @,a] f1,\"ф2\"\n[ t2,] \n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "Подзапрос 1" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from (select it.* from it) t1, t2");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ it,] \n[ @,t1] it.*\n[ t2,] \n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "Подзапрос 2" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from (select it.* from it) t1(f1,f2), t2 al(f3,f4)");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ it,] \n[ @,t1] f1,f2\n[ t2,al] f3,f4\n";
|
||||
CHECK(act==exp);
|
||||
act = f.GetListTable(1);
|
||||
exp = "[ t1,] \n[ al,] \n";
|
||||
CHECK(act==exp);
|
||||
|
||||
}
|
||||
SECTION( "Подзапрос 3" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from (select it.dt::time at zone Ndt,it.col2 from it) t1, t2 al(f3,f4)");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ it,] \n[ @,t1] Ndt,it.col2\n[ t2,al] f3,f4\n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "GetColsList cols 3" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from (select it.dt::time at zone Ndt,it.col2 from it) t1, t2 al(f3,f4)");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ it,] \n[ @,t1] Ndt,it.col2\n[ t2,al] f3,f4\n";
|
||||
act = f.GetColsList("t1.n", cl, t);
|
||||
exp = "Ndt";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "GetColsList table" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from (select it.dt::time at zone Ndt,it.col2 from it) t1, t2 al(f3,f4)");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
act1 = f.GetColsList("t1.n", cl, t);
|
||||
exp = "t1";
|
||||
CHECK(t==exp);
|
||||
}
|
||||
SECTION( "GetColsList cols 4" ) {
|
||||
int e;
|
||||
f.SetSql("select 2 from (select it.dt::time at zone Ndt,it.col2 from it) t1, t2 al(f3,f4)");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ it,] \n[ @,t1] Ndt,it.col2\n[ t2,al] f3,f4\n";
|
||||
CHECK(act==exp);
|
||||
act1 = f.GetColsList("t1.*", cl, t);
|
||||
exp = "Ndt\tcol2";
|
||||
CHECK(act1==exp);
|
||||
}
|
||||
SECTION( "Join 1" ) {
|
||||
int e;
|
||||
// join
|
||||
f.SetSql("select * from def join param on def.id=param.def join inv_type c on c.id=param.type limit 5");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ def,] \n[ param,] \n[ inv_type,c] \n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "Join 1.1" ) {
|
||||
int e;
|
||||
f.SetSql("select * from def d join param p on d.id=p.def join inv_type c on c.id=p.type where");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = L"[ def,d] \n[ param,p] \n[ inv_type,c] \n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "Join 2" ) {
|
||||
int e;
|
||||
f.SetSql("select def.*,param.* from def join ( select f2,f3 from a) param on def.id=param.def join inv_type c on c.id=param.type");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ def,] \n[ a,] \n[ @,param] f2,f3\n[ inv_type,c] \n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
SECTION( "with 1" ) {
|
||||
int e;
|
||||
// with
|
||||
f.SetSql("with a as (select in1,i2 from def), b(b1,b2) as (select t3 from z2) select * from b");
|
||||
e = f.ParseSql(0);
|
||||
act = f.BuildAutoComplite(0, 0); act = f.GetListTable(0);
|
||||
exp = "[ def,] \n[ @,a] in1,i2\n[ z2,] \n[ @,b] b1,b2\n[ b,] \n";
|
||||
CHECK(act==exp);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "FormatterSQL parse", "[parsesql]" ) {
|
||||
int e;
|
||||
FormatterSQL f2("()");
|
||||
wxString exp,o,s;
|
||||
SECTION( "simple 1" ) {
|
||||
wxString s = "select * from table t1,table t2 where t1.f=t2.f order by 1 desc limit 2";
|
||||
FormatterSQL f(s);
|
||||
int e=f.ParseSql(0);
|
||||
CHECK(e==0);
|
||||
}
|
||||
SECTION( "empty braket" ) {
|
||||
e = f2.ParseSql(0);
|
||||
CHECK(e==0);
|
||||
o = f2.printParseArray();
|
||||
exp = "Index: 0 Jump 1 Type: 5 widt: 1 Flag: 0 Val : (\nIndex: 1 Jump 0 Type: 5 widt: 1 Flag: 0 Val : )\n";
|
||||
CHECK(o==exp);
|
||||
}
|
||||
SECTION( "variant1" ) {
|
||||
f2.SetSql("a.* 0:1 b::t (m).c 2~!@6"); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 7 widt: 1 Flag: 0 Val : a\nIndex: 1 Type: 4 widt: 2 Flag: 0 Val : .*\nIndex: 2 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 3 Type: 8 widt: 1 Flag: 0 Val : 0\nIndex: 4 Type: 4 widt: 1 Flag: 0 Val : :\nIndex: 5 Type: 8 widt: 1 Flag: 0 Val : 1\nIndex: 6 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 7 Type: 7 widt: 1 Flag: 0 Val : b\nIndex: 8 Type: 4 widt: 2 Flag: 0 Val : ::\nIndex: 9 Type: 7 widt: 1 Flag: 256 Val : t\nIndex: 10 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 11 Jump 13 Type: 5 widt: 1 Flag: 0 Val : (\nIndex: 12 Type: 7 widt: 1 Flag: 0 Val : m\nIndex: 13 Jump 11 Type: 5 widt: 1 Flag: 0 Val : )\nIndex: 14 Type: 4 widt: 1 Flag: 0 Val : .\nIndex: 15 Type: 7 widt: 1 Flag: 0 Val : c\nIndex: 16 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 17 Type: 8 widt: 1 Flag: 0 Val : 2\nIndex: 18 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 19 Type: 4 widt: 3 Flag: 0 Val : ~!@\nIndex: 20 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 21 Type: 8 widt: 1 Flag: 0 Val : 6\n";
|
||||
CHECK(o==exp);
|
||||
}
|
||||
|
||||
SECTION( "many variantns" ) {
|
||||
f2.SetSql( "--1" ); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 10 widt: 3 Flag: 0 Val : --1\n";
|
||||
CHECK(o==exp);
|
||||
|
||||
f2.SetSql("$$ fsdf "); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 3 widt: 8 Flag: 0 Val : $$ fsdf \n";
|
||||
CHECK(o==exp);
|
||||
|
||||
f2.SetSql("E' "); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "";
|
||||
CHECK(o==exp);
|
||||
|
||||
f2.SetSql("/*"); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 10 widt: 2 Flag: 0 Val : /*\n";
|
||||
CHECK(o==exp);
|
||||
|
||||
s = "a.b"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 6 widt: 3 Flag: 0 Val : a.b\n";
|
||||
CHECK(o==exp);
|
||||
s = "a::b"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 7 widt: 1 Flag: 0 Val : a\nIndex: 1 Type: 4 widt: 2 Flag: 0 Val : ::\nIndex: 2 Type: 7 widt: 1 Flag: 0 Val : b\n";
|
||||
CHECK(o==exp);
|
||||
s = "is not null"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 2 widt: 11 Flag: 0 Val : is not null\n";
|
||||
CHECK(o==exp);
|
||||
s = "*,+:%@!~"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 4 widt: 1 Flag: 0 Val : *\nIndex: 1 Type: 4 widt: 1 Flag: 0 Val : ,\nIndex: 2 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 3 Type: 4 widt: 6 Flag: 0 Val : +:%@!~\n";
|
||||
CHECK(o==exp);
|
||||
|
||||
s = "1||2"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 8 widt: 1 Flag: 0 Val : 1\nIndex: 1 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 2 Type: 4 widt: 2 Flag: 0 Val : ||\nIndex: 3 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 4 Type: 8 widt: 1 Flag: 0 Val : 2\n";
|
||||
CHECK(o==exp);
|
||||
|
||||
s = "1+2"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 8 widt: 1 Flag: 0 Val : 1\nIndex: 1 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 2 Type: 4 widt: 1 Flag: 0 Val : +\nIndex: 3 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 4 Type: 8 widt: 1 Flag: 0 Val : 2\n";
|
||||
CHECK(o==exp);
|
||||
s = "e'\\n'"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 3 widt: 5 Flag: 0 Val : e'\\n'\n";
|
||||
CHECK(o==exp);
|
||||
|
||||
s = "u&'d\\0061t\\+000061'"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 3 widt: 19 Flag: 0 Val : u&'d\\0061t\\+000061'\n";
|
||||
CHECK(o==exp);
|
||||
s = "$$ $$"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 3 widt: 5 Flag: 0 Val : $$ $$\n";
|
||||
CHECK(o==exp);
|
||||
s = "$a$ $ $a$"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 3 widt: 9 Flag: 0 Val : $a$ $ $a$\n";
|
||||
CHECK(o==exp);
|
||||
s = "$0"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "\n";
|
||||
//Assert::AreEqual(exp.ToStdWstring(), o.ToStdWstring(), s);
|
||||
s = "f(a,b)"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 7 widt: 1 Flag: 256 Val : f\nIndex: 1 Jump 6 Type: 5 widt: 1 Flag: 0 Val : (\nIndex: 2 Type: 7 widt: 1 Flag: 0 Val : a\nIndex: 3 Type: 4 widt: 1 Flag: 0 Val : ,\nIndex: 4 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 5 Type: 7 widt: 1 Flag: 0 Val : b\nIndex: 6 Jump 1 Type: 5 widt: 1 Flag: 0 Val : )\n";
|
||||
//Assert::AreEqual(exp.ToStdWstring(), o.ToStdWstring(), s);
|
||||
s = ")"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "\n";
|
||||
CHECK(e==-1);
|
||||
s = "("; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
CHECK(e==-1);
|
||||
exp = "\n";
|
||||
//Assert::AreEqual(exp.ToStdWstring(), o.ToStdWstring(), s);
|
||||
s = "like"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 2 widt: 4 Flag: 0 Val : like\n";
|
||||
CHECK(o==exp);
|
||||
|
||||
s = "("; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "\n";
|
||||
//Assert::AreEqual(exp.ToStdWstring(), o.ToStdWstring(), s);
|
||||
|
||||
s = "x=ANY([1,2,3])"; f2.SetSql(s); e = f2.ParseSql(0); o = f2.printParseArray();
|
||||
exp = "Index: 0 Type: 7 widt: 1 Flag: 0 Val : x\nIndex: 1 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 2 Type: 4 widt: 1 Flag: 0 Val : =\nIndex: 3 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 4 Type: 7 widt: 3 Flag: 256 Val : ANY\nIndex: 5 Jump 15 Type: 5 widt: 1 Flag: 0 Val : (\nIndex: 6 Jump 14 Type: 5 widt: 1 Flag: 0 Val : [\nIndex: 7 Type: 8 widt: 1 Flag: 0 Val : 1\nIndex: 8 Type: 4 widt: 1 Flag: 0 Val : ,\nIndex: 9 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 10 Type: 8 widt: 1 Flag: 0 Val : 2\nIndex: 11 Type: 4 widt: 1 Flag: 0 Val : ,\nIndex: 12 Type: 1 widt: 1 Flag: 0 Val : \nIndex: 13 Type: 8 widt: 1 Flag: 0 Val : 3\nIndex: 14 Jump 6 Type: 5 widt: 1 Flag: 0 Val : ]\nIndex: 15 Jump 5 Type: 5 widt: 1 Flag: 0 Val : )\n";
|
||||
CHECK(o==exp);
|
||||
}
|
||||
}
|
||||
TEST_CASE( "FormatterSQL parsePlpgsql", "[parsesql]" ) {
|
||||
int e;
|
||||
wxString exp,o,s;
|
||||
SECTION( "variant1" ) {
|
||||
FormatterSQL f2(R"(
|
||||
declare
|
||||
begin
|
||||
end
|
||||
)");
|
||||
std::vector<complite_element> list = f2.ParsePLpgsql(); o=f2.GetListTable(list);
|
||||
exp = "";
|
||||
CHECK(o==exp);
|
||||
}
|
||||
SECTION( "plpgsql 1" ) {
|
||||
FormatterSQL f2(R"(
|
||||
declare
|
||||
x record;
|
||||
iobj varchar(50) :=add_part(now(),'1 month');
|
||||
begin
|
||||
for i in 11..22
|
||||
loop
|
||||
end loop;
|
||||
end
|
||||
)");
|
||||
std::vector<complite_element> list = f2.ParsePLpgsql(); o=f2.GetListTable(list);
|
||||
exp = "[ add_part,] \n[ now,] \n";
|
||||
CHECK(o==exp);
|
||||
}
|
||||
SECTION( "plpgsql 2" ) {
|
||||
FormatterSQL f2(R"(
|
||||
declare
|
||||
x record;
|
||||
begin
|
||||
for i in 11..22
|
||||
loop
|
||||
case f1() when f2() else
|
||||
select a into ii from tab1 t where f3() and f4() in ('a');
|
||||
case end;
|
||||
delete from t2 using t4,t5 where t4.id=t5 and t2.id=t4.id returning t2.id;
|
||||
end loop;
|
||||
end
|
||||
)");
|
||||
std::vector<complite_element> list = f2.ParsePLpgsql(); o=f2.GetListTable(list);
|
||||
exp = "[ f1,] \n[ f2,] \n[ tab1,] \n[ f3,] \n[ f4,] \n[ t2,] \n[ t5,] \n";
|
||||
CHECK(o==exp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -67,14 +67,20 @@ wxString FormatterSQL::get_list_columns(int startindex, union Byte zone) {
|
|||
}
|
||||
return cols;
|
||||
}
|
||||
wxString FormatterSQL::GetListTable(int cursorPos) {
|
||||
wxString FormatterSQL::GetListTable(const std::vector<complite_element> &list) {
|
||||
int s = 0;
|
||||
wxString r = "";
|
||||
while (s < listTable.size()) {
|
||||
complite_element* el = &listTable[s++];
|
||||
r += wxString::Format("[ %s,%s] %s\n", el->table, el->alias, el->columnList);
|
||||
complite_element el;
|
||||
while (s < list.size()) {
|
||||
el = list[s++];
|
||||
r += wxString::Format("[ %s,%s] %s\n", el.table, el.alias, el.columnList);
|
||||
}
|
||||
return r;
|
||||
|
||||
}
|
||||
wxString FormatterSQL::GetListTable(int cursorPos) {
|
||||
if (cursorPos==0) return GetListTable(listTable);
|
||||
else return GetListTable(listFunction);
|
||||
}
|
||||
int FormatterSQL::GetTableListBeforePosition(int positem, wxArrayString& listtable, wxArrayString& listalias) {
|
||||
int s = 0;
|
||||
|
|
@ -198,6 +204,15 @@ iteration2:
|
|||
}
|
||||
return r;
|
||||
}
|
||||
void FormatterSQL::_addfunc(const view_item *vi) {
|
||||
if (vi->flags & f_key::isFUNCTION ) {
|
||||
complite_element ff;
|
||||
ff.table=vi->txt;
|
||||
ff.startIndex=vi->srcpos;
|
||||
listFunction.push_back(ff);
|
||||
}
|
||||
|
||||
}
|
||||
wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
||||
int len_items = items.size();
|
||||
int n_element = startIndex;
|
||||
|
|
@ -214,8 +229,12 @@ wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
|||
wxString cols_name;
|
||||
bool isfunction = false;
|
||||
bool isskipnext = false;
|
||||
bool isinsert = false;
|
||||
el.columnList = ""; el.alias = ""; el.table = ""; el.level = level;
|
||||
if (level == 0) listTable.clear();
|
||||
if (level == 0) {
|
||||
listTable.clear();
|
||||
listFunction.clear();
|
||||
}
|
||||
while (next_item_no_space(found_index) != -1) {
|
||||
view_item* vi = &items[found_index];
|
||||
if (vi->type == comment) {
|
||||
|
|
@ -224,7 +243,7 @@ wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
|||
}
|
||||
if (vi->type == keyword) {
|
||||
union Byte z = zone;
|
||||
if (vi->txt.Lower() == "from" && vi->flags != 0) {
|
||||
if ((vi->txt.Lower() == "from" && vi->flags != 0) ) {
|
||||
if (zone.b.select_list) {
|
||||
if (!lastname.IsEmpty())cols.Add(lastname);
|
||||
}
|
||||
|
|
@ -241,12 +260,29 @@ wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
|||
cols.Clear();
|
||||
//el.startIndex = found_index + 1;
|
||||
}
|
||||
if (vi->txt.Lower().Find("join") > -1) {
|
||||
if ((vi->txt.Lower().Find("join") > -1) || vi->txt.Lower() == "using") {
|
||||
goto close_element_from;
|
||||
}
|
||||
if (vi->txt.Lower() == "on") {
|
||||
goto close_element_from;
|
||||
}
|
||||
if (vi->txt.Lower() == "insert") {
|
||||
found_index++;
|
||||
if ((next_item_no_space(found_index)!=-1) && items[found_index].txt.Lower()=="into") {
|
||||
found_index++;
|
||||
if ((next_item_no_space(found_index)!=-1) && (items[found_index].type==FSQL::type_item::identifier ||items[found_index].type==FSQL::type_item::name)) {
|
||||
// table name
|
||||
|
||||
complite_element el2;
|
||||
el2.table=items[found_index].txt;
|
||||
el2.startIndex=el.endIndex=found_index;
|
||||
el2.level=level;
|
||||
found_index++;
|
||||
listTable.push_back(el2);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((vi->flags & end_from) != 0) {
|
||||
zone.b.from = 0;
|
||||
|
|
@ -320,9 +356,19 @@ wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
|||
|
||||
}
|
||||
else if (isskipnext) {
|
||||
// пропускаем всё до следующей запятой
|
||||
// пропускаем всё до следующей запятой но проверим наличие функций
|
||||
if (vi->txt=='(') {
|
||||
int jump = vi->endlevel;
|
||||
_addfunc_in_braket(found_index,jump);
|
||||
found_index = jump + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vi->type == identifier || vi->type == name) _addfunc(vi);
|
||||
}
|
||||
else if (vi->type == identifier || vi->type == name) {
|
||||
if (zone.b.with==0)
|
||||
_addfunc(vi);
|
||||
int i = found_index - 1;
|
||||
if (next_item_no_space(i) != -1) {
|
||||
if (items[i].type == separation && items[i].txt == "::") {
|
||||
|
|
@ -352,6 +398,7 @@ wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
|||
else if (vi->txt == '(') {
|
||||
int jump = vi->endlevel;
|
||||
if (zone.b.select_list) {
|
||||
_addfunc_in_braket(found_index,jump);
|
||||
found_index = jump + 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -392,6 +439,7 @@ wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
|||
}
|
||||
// это функция с аргументами
|
||||
if (!isfunction) {
|
||||
_addfunc_in_braket(found_index,jump);
|
||||
isfunction = true;
|
||||
found_index = jump + 1;
|
||||
continue;
|
||||
|
|
@ -407,13 +455,15 @@ wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
|||
if (isfunction)
|
||||
el.table = "@";
|
||||
else
|
||||
if (objName.Count() > 0) el.table = objName[0];
|
||||
if (objName.Count() > 0) {el.table = objName[0]; el.startIndex=indexlastID; }
|
||||
else
|
||||
el.table = "-";
|
||||
el.alias = lastname;
|
||||
el.columnList = cols_name;
|
||||
listTable.push_back(el);
|
||||
}
|
||||
// check run functions
|
||||
_addfunc_in_braket(found_index,jump);
|
||||
isskipnext = true;
|
||||
found_index = jump + 1;
|
||||
continue;
|
||||
|
|
@ -461,9 +511,118 @@ wxString FormatterSQL::BuildAutoComplite(int startIndex, int level) {
|
|||
else
|
||||
return wxJoin(cols, ',');
|
||||
}
|
||||
void FormatterSQL::_addfunc_in_braket(int start,int end) {
|
||||
while (++start <= end) {
|
||||
if (items[start].txt=='(') {
|
||||
int tmp=start-1;
|
||||
if (next_item_no_space(tmp,-1) != -1) {
|
||||
view_item *v2=&items[tmp];
|
||||
if (v2->type == identifier || v2->type == name ) _addfunc(v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
int FormatterSQL::GetNextPositionSqlParse() {
|
||||
return lastposition;
|
||||
}
|
||||
/// Анализируем исходный текст процедуры или функции
|
||||
/// Находим все функции таблицы и представления
|
||||
///
|
||||
std::vector<complite_element> FormatterSQL::ParsePLpgsql(){
|
||||
int e;
|
||||
int maxlen=sql.Len();
|
||||
std::vector<complite_element> listdbobject;
|
||||
complite_element i;
|
||||
// Глобальный цикл по тексту
|
||||
while (lastposition<maxlen) {
|
||||
int start=lastposition;
|
||||
e=ParseSql(1);
|
||||
if (e<0) {
|
||||
// встретили оператор case
|
||||
//wxTrap();
|
||||
lastposition=errorposition;
|
||||
}
|
||||
wxString currentsql=sql.substr(start,lastposition-start);
|
||||
if (currentsql.Len()>0) {
|
||||
//std::cout << currentsql << std::endl ;
|
||||
}
|
||||
// извлечем информацию о таблицах и функциях
|
||||
BuildAutoComplite(0,0);
|
||||
//
|
||||
for(int i=0;i<listTable.size();i++) {
|
||||
wxString t=listTable[i].table;
|
||||
// Удалим из функций синонимы таблиц
|
||||
for(int j=0;j<listFunction.size();j++) {
|
||||
if (listTable[i].alias==listFunction[j].table)
|
||||
listFunction[j].table="";
|
||||
}
|
||||
if (t=="@") continue;
|
||||
if (t.Len()>0) {
|
||||
bool add=true;
|
||||
for(int k=0;k<i;k++) {
|
||||
if (listTable[k].table=="@" && listTable[k].alias==t) {
|
||||
add=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
complite_element it;
|
||||
it.table=t;
|
||||
wxString lt=t.Lower();
|
||||
bool ignore=(lt=="alter"||lt=="trigger"||lt=="index");
|
||||
if (ignore) break;
|
||||
if (!ignore) {
|
||||
int itempos=listTable[i].startIndex;
|
||||
int epos=listTable[i].endIndex;
|
||||
while (itempos<=epos) {
|
||||
if (items[itempos].txt==t) break;
|
||||
itempos++;
|
||||
}
|
||||
it.startIndex=items[itempos].srcpos;
|
||||
listdbobject.push_back(it);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// add functions
|
||||
for(int j=0;j<listFunction.size();j++) {
|
||||
if (listFunction[j].table.Len()>0) {
|
||||
complite_element it;
|
||||
wxString fn=listFunction[j].table;
|
||||
if (
|
||||
fn.Lower()=="varchar"||
|
||||
fn.Lower()=="char"||
|
||||
fn.Lower()=="chr"||
|
||||
fn.Lower()=="btree"||
|
||||
fn.Lower()=="numeric"||
|
||||
fn.Lower()=="bit"||
|
||||
fn.Lower()=="return"||
|
||||
fn.Lower()=="varying"||
|
||||
fn.Lower()=="key"||
|
||||
fn.Lower()=="range"||
|
||||
fn.Lower()=="varbit"
|
||||
) continue;
|
||||
it.table=fn;
|
||||
it.startIndex=listFunction[j].startIndex;
|
||||
wxString check=sql.substr(it.startIndex,fn.Len());
|
||||
if (check!=fn) {
|
||||
std::cout << fn << std::endl;
|
||||
}
|
||||
listdbobject.push_back(it);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// sort startIndex
|
||||
std::sort(listdbobject.begin(),listdbobject.end(),
|
||||
[](const complite_element& a, const complite_element& b) {
|
||||
return a.startIndex < b.startIndex;
|
||||
});
|
||||
|
||||
return listdbobject;
|
||||
}
|
||||
/// <summary>
|
||||
/// <c>ParseSql</c> Выполнение разбора текста как SQL выражения
|
||||
/// </summary>
|
||||
|
|
@ -471,6 +630,7 @@ int FormatterSQL::GetNextPositionSqlParse() {
|
|||
/// <returns>Возвращает код ошибки если SQL выражение было не полное или не корректное</returns>
|
||||
int FormatterSQL::ParseSql(int flags) {
|
||||
int i = lastposition;
|
||||
errorposition=-1;
|
||||
int lhome = 0;
|
||||
bool str_literal = false;
|
||||
bool ext = false;
|
||||
|
|
@ -662,6 +822,11 @@ int FormatterSQL::ParseSql(int flags) {
|
|||
int pos = tmp.Find(dollarSep);
|
||||
if (pos != -1) {
|
||||
vi.txt = sql.substr(i - l, l + l + pos);
|
||||
if (flags == 1 && dollarSep=="$BODY$") {
|
||||
vi.txt=dollarSep;
|
||||
pos=0;l=0;
|
||||
}
|
||||
|
||||
i += pos + l;
|
||||
}
|
||||
else {
|
||||
|
|
@ -677,6 +842,7 @@ int FormatterSQL::ParseSql(int flags) {
|
|||
if (c == '\'' || c == '"') {
|
||||
qt = c;
|
||||
str_literal = true;
|
||||
vi.srcpos=i-1;
|
||||
cons = qt;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -815,11 +981,20 @@ int FormatterSQL::ParseSql(int flags) {
|
|||
bracket.pop();
|
||||
}
|
||||
else {
|
||||
errorposition=i+tmp.Len()-1;
|
||||
return -1; //braket no parent
|
||||
}
|
||||
vi.endlevel = idx;
|
||||
if (idx != -1) items[idx].endlevel = items.size();
|
||||
|
||||
} else if (keyEntities[n].name == "then"||
|
||||
keyEntities[n].name == "loop" ) { // for plpgsql
|
||||
// if ... then
|
||||
// while ... loop or for .. in query loop
|
||||
if (bracket.size() == 0) {
|
||||
i=i+tmp.Len()-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += tmp.Len() - 1;
|
||||
|
|
@ -837,7 +1012,7 @@ int FormatterSQL::ParseSql(int flags) {
|
|||
int pp2 = items.size() - 1;
|
||||
int pp3 = next_item_no_space(pp2, -1);
|
||||
if (pp3 != -1 && (items[pp3].type == name || items[pp3].type == identifier)) {
|
||||
vi.flags = isFUNCTION;
|
||||
items[pp3].flags = isFUNCTION;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
|
@ -850,6 +1025,7 @@ int FormatterSQL::ParseSql(int flags) {
|
|||
bracket.pop();
|
||||
}
|
||||
else {
|
||||
errorposition=i;
|
||||
return -1; //braket no parent
|
||||
}
|
||||
vi.txt = c;
|
||||
|
|
@ -866,6 +1042,7 @@ int FormatterSQL::ParseSql(int flags) {
|
|||
if (matches) {
|
||||
tmp = regident.GetMatch(tmp, 0);
|
||||
vi.txt = tmp;
|
||||
vi.srcpos=i;
|
||||
vi.type = name;
|
||||
i += tmp.Len();
|
||||
continue;
|
||||
|
|
@ -930,15 +1107,19 @@ int FormatterSQL::ParseSql(int flags) {
|
|||
}
|
||||
// no sql command
|
||||
if (ex) break;
|
||||
errorposition=i;
|
||||
return -3;
|
||||
|
||||
}
|
||||
// end big loop
|
||||
if (str_literal) {
|
||||
errorposition=i;
|
||||
return -2; // literal no close
|
||||
}
|
||||
if (bracket.size() > 0)
|
||||
if (bracket.size() > 0) {
|
||||
errorposition=i;
|
||||
return -1; // bracet no close
|
||||
}
|
||||
lastposition = i;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
341
utils/FunctionPGHelper.cpp
Normal file
341
utils/FunctionPGHelper.cpp
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
#include "pgAdmin3.h"
|
||||
#include <utils/FunctionPGHelper.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/textfile.h>
|
||||
#include <wx/filename.h>
|
||||
#include "db/pgSet.h"
|
||||
#include "frm/frmMain.h"
|
||||
#include "ctl/ctlSQLBox.h"
|
||||
|
||||
extern sysSettings* settings;
|
||||
extern frmMain *winMain;
|
||||
|
||||
|
||||
wxString FunctionPGHelper::getHelpString(wxString fnd, bool isPart)
|
||||
{
|
||||
if (!isValid()) return wxEmptyString;
|
||||
auto search = body.find(fnd);
|
||||
wxString txt;
|
||||
|
||||
if (search != body.end())
|
||||
txt = search->second;
|
||||
else
|
||||
{
|
||||
std::vector<wxString> list;
|
||||
int l = fnd.Len();
|
||||
wxString b;
|
||||
for (const auto& e : body) {
|
||||
if (e.first.Len() > l && e.first.StartsWith(fnd)) {
|
||||
list.push_back(e.first);
|
||||
b = e.second;
|
||||
}
|
||||
}
|
||||
if (list.size() == 1) txt = b;
|
||||
else {
|
||||
for (const auto& s : list) {
|
||||
txt += wxString::Format("<a href=\"%s\">%s</a><br>", s, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (i == wxNOT_FOUND) return wxEmptyString;
|
||||
return txt;
|
||||
}
|
||||
void FunctionPGHelper::setDbConn(pgConn *db) {
|
||||
dblast=db;
|
||||
}
|
||||
#include "schema/pgDatabase.h"
|
||||
#include "schema/pgSchema.h"
|
||||
#include "schema/pgTable.h"
|
||||
#include "schema/pgView.h"
|
||||
#include "schema/pgFunction.h"
|
||||
#include "schema/pgTrigger.h"
|
||||
|
||||
extern pgDatabaseFactory databaseFactory;
|
||||
extern pgSchemaFactory schemaFactory;
|
||||
extern pgTableFactory tableFactory;
|
||||
extern pgViewFactory viewFactory;
|
||||
extern pgFunctionFactory functionFactory;
|
||||
extern pgProcedureFactory procedureFactory;
|
||||
extern pgTriggerFunctionFactory triggerFunctionFactory;
|
||||
wxString FunctionPGHelper::getDBinfoKeyword(wxString objname, bool islower) {
|
||||
if (dblast) {
|
||||
wxString s,n,a,tmp;
|
||||
tmp=objname;
|
||||
a=objname.AfterFirst('(');
|
||||
if (!a.IsEmpty()) {
|
||||
tmp=objname.BeforeFirst('(');
|
||||
a=a.substr(0,a.Len()-1);
|
||||
} else a="%";
|
||||
make_identifier(tmp,s,n,islower);
|
||||
if (s.IsEmpty()) {
|
||||
s="%";
|
||||
}
|
||||
wxString querytemplate=R"(
|
||||
select p.oid,p.relnamespace::regnamespace nsp,p.relname objname, p.relkind::text,
|
||||
case when p.relkind in ('v','m')
|
||||
then
|
||||
--pg_get_viewdef(p.oid,true)
|
||||
''
|
||||
else
|
||||
''
|
||||
end
|
||||
define , '' args, obj_description(oid,'pg_class') comment from pg_class p
|
||||
where p.relkind in ('r','p','m','v') and p.relnamespace::regnamespace::text not in ('pg_catalog','information_schema')
|
||||
and p.relnamespace::regnamespace::text like '%s' and p.relname like '%s'
|
||||
and (select count(*) from pg_partition_ancestors(oid) ) <=1
|
||||
union all
|
||||
select p.oid,p.pronamespace::regnamespace nsp,p.proname objname,
|
||||
case when pg_get_function_result(p.oid) is null then 'P'
|
||||
when pg_get_function_result(p.oid) = 'trigger' then 't' else 'f' end,
|
||||
'' prosrc ,pg_get_function_arguments(oid), obj_description(oid,'pg_proc') from pg_proc p
|
||||
where p.pronamespace::regnamespace::text like '%s' and p.proname like '%s' and pg_get_function_arguments(oid) like '%s'
|
||||
and p.pronamespace::regnamespace::text not in ('pg_catalog','information_schema')
|
||||
order by objname;
|
||||
)";
|
||||
wxString es=s;
|
||||
wxString en=n;
|
||||
es.Replace("'","''");
|
||||
en.Replace("'","''");
|
||||
wxString sql=wxString::Format(querytemplate
|
||||
,es,en,es,en,a);
|
||||
pgSet *res = dblast->ExecuteSet(sql);
|
||||
wxString txt,ns,on,kind,args,def,oid;
|
||||
bool isfunc=false;
|
||||
int c=0;
|
||||
while (!res->Eof())
|
||||
{
|
||||
ns = res->GetVal("nsp");
|
||||
oid = res->GetVal("oid");
|
||||
on = res->GetVal("objname");
|
||||
kind = res->GetVal("relkind");
|
||||
args = res->GetVal("args");
|
||||
def = res->GetVal("define");
|
||||
wxString link=ns+"."+on;
|
||||
if (kind=="f" || kind=="p") {
|
||||
link+="("+args+")";
|
||||
isfunc=true;
|
||||
} else isfunc=false;
|
||||
txt += wxString::Format("<a href=\"%s\">%s</a><br>", link, link);
|
||||
c++;
|
||||
res->MoveNext();
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
delete res;
|
||||
res = NULL;
|
||||
}
|
||||
if (c>1) return txt;
|
||||
if (c==1)
|
||||
{
|
||||
wxString html;
|
||||
if (def.IsEmpty())
|
||||
{
|
||||
wxTreeItemIdValue foldercookie;
|
||||
ctlTree *browser=winMain->GetBrowser();
|
||||
wxTreeItemId folderitem = browser->GetFirstChild(browser->GetRootItem(), foldercookie);
|
||||
|
||||
while (folderitem)
|
||||
{
|
||||
if (browser->ItemHasChildren(folderitem))
|
||||
{
|
||||
wxTreeItemIdValue servercookie;
|
||||
wxTreeItemId serveritem = browser->GetFirstChild(folderitem, servercookie);
|
||||
wxString host=dblast->GetHost();
|
||||
wxString db=dblast->GetDbname();
|
||||
int port=dblast->GetPort();
|
||||
wxString fullid=on;
|
||||
if (!args.IsEmpty()) fullid+="("+args+")";
|
||||
wxString idf=wxString::Format("%s:%d",host,port);
|
||||
while (serveritem)
|
||||
{
|
||||
pgServer *server = (pgServer *)browser->GetItemData(serveritem);
|
||||
if (server != NULL && server->IsCreatedBy(serverFactory)) {
|
||||
if (server->GetIdentifier()==idf ) {
|
||||
if (server->connection()) {
|
||||
// is open connect
|
||||
//wxTreeItemId serveritemc1 = browser->GetFirstChild(folderitem, servercookie);
|
||||
pgCollection *coll=browser->FindCollection(databaseFactory,serveritem);
|
||||
wxTreeItemId dbssId;
|
||||
if (coll) dbssId=coll->GetId();
|
||||
wxCookieType cookie2;
|
||||
wxTreeItemId item = browser->GetFirstChild(dbssId, cookie2);
|
||||
|
||||
while (item && item.IsOk())
|
||||
{
|
||||
//wxString tt=browser->GetItemText(item);
|
||||
pgObject *obj = browser->GetObject(item);
|
||||
if (obj && obj->IsCreatedBy(databaseFactory) && db==obj->GetName() )
|
||||
{
|
||||
pgCollection *coll=browser->FindCollection(schemaFactory,item);
|
||||
wxTreeItemId schemasId;
|
||||
if (coll) schemasId=coll->GetId();
|
||||
if (schemasId) {
|
||||
pgObject *obj2 = browser->GetObject(item);
|
||||
//obj2->expandedKids
|
||||
wxCookieType cookie4;
|
||||
item = browser->GetFirstChild(schemasId, cookie4);
|
||||
while (item)
|
||||
{
|
||||
pgSchema *obj3 = (pgSchema *)browser->GetObject(item);
|
||||
if (obj3 && obj3->IsCreatedBy(schemaFactory) && ns==obj3->GetName() ) {
|
||||
obj3->ShowTreeDetail(browser);
|
||||
wxTreeItemId objcollId;
|
||||
pgCollection *coll=NULL;
|
||||
if (kind=='r'||kind=='p' ) coll = browser->FindCollection(tableFactory,item);
|
||||
if (kind=='v'||kind=='m') coll = browser->FindCollection(viewFactory,item);
|
||||
if (kind=='f') coll = browser->FindCollection(functionFactory,item);
|
||||
if (kind=='P') coll = browser->FindCollection(procedureFactory,item);
|
||||
//if (kind=='p') coll = browser->FindCollection(pg_partitionFactory,item);
|
||||
if (kind=='t') coll = browser->FindCollection(triggerFunctionFactory,item);
|
||||
if (coll) {
|
||||
objcollId=coll->GetId();
|
||||
pgObject *obj4 = browser->GetObject(objcollId);
|
||||
obj4->ShowTreeDetail(browser);
|
||||
}
|
||||
wxCookieType cookie5;
|
||||
item = browser->GetFirstChild(objcollId, cookie5);
|
||||
while (item)
|
||||
{
|
||||
pgObject *obj5 = browser->GetObject(item);
|
||||
//wxString soid=obj5->GetOidStr();
|
||||
if (obj5 && NumToStr(obj5->GetOid())==oid) {
|
||||
pgObject *obj5 = browser->GetObject(item);
|
||||
obj5->ShowTreeDetail(browser);
|
||||
def=obj5->GetSql(browser);
|
||||
if (kind=='r'|| kind=='m' || kind=='v' || kind=='f') {
|
||||
//pgTable *o=(pgTable *)(obj5);
|
||||
//brower->FindObject(tableFactory,)
|
||||
//o->AppendStuff(def,browser,tableFactory);
|
||||
}
|
||||
goto exitloop;
|
||||
}
|
||||
item = browser->GetNextChild(objcollId, cookie5);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
item = browser->GetNextChild(schemasId, cookie4);
|
||||
}
|
||||
}
|
||||
goto exitloop;
|
||||
}
|
||||
item = browser->GetNextChild(dbssId, cookie2);
|
||||
} // next
|
||||
|
||||
}
|
||||
|
||||
goto exitloop;
|
||||
}
|
||||
}
|
||||
serveritem = browser->GetNextChild(folderitem, servercookie);
|
||||
}
|
||||
}
|
||||
folderitem = browser->GetNextChild(browser->GetRootItem(), foldercookie);
|
||||
}
|
||||
}
|
||||
exitloop:
|
||||
FSQL::FormatterSQL f(def);
|
||||
std::vector<FSQL::complite_element> listobj=f.ParsePLpgsql();
|
||||
ctlSQLBox* box = new ctlSQLBox((wxWindow*) winMain, CTL_SQLQUERY, wxDefaultPosition, wxSize(0, 0), wxTE_MULTILINE | wxTE_RICH2);
|
||||
box->SetText(def);
|
||||
int l = def.Length();
|
||||
box->Colourise(0, box->GetLength());
|
||||
//bg = box->SetSQLBoxColourBackground(false).GetAsString(wxC2S_CSS_SYNTAX);
|
||||
html = box->TextToHtml(0, box->GetLength(),false,listobj);
|
||||
wxColour cbg=box->GetBackgroundColour();
|
||||
wxString bg=cbg.GetAsString(wxC2S_HTML_SYNTAX);
|
||||
delete box;
|
||||
html = "<html><body BGCOLOR=\"" + bg + "\">" + html + "</body></html>";
|
||||
return html;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return wxEmptyString;
|
||||
}
|
||||
wxString FunctionPGHelper::getSqlCommandHelp(wxString fnd) {
|
||||
wxUniChar sep = wxFileName::GetPathSeparator();
|
||||
fnd.Replace(" ", "");
|
||||
wxString f = wxFindFirstFile(path + sep + "sql-" + fnd + "*.html");
|
||||
wxString last, txt;
|
||||
|
||||
int c = 0;
|
||||
while (!f.empty())
|
||||
{
|
||||
f = f.AfterLast(sep);
|
||||
last = f;
|
||||
txt += wxString::Format("<a href=\"%s\">%s</a><br>", f, f);
|
||||
f = wxFindNextFile();
|
||||
c++;
|
||||
}
|
||||
if (last.empty()) {
|
||||
return wxEmptyString;
|
||||
}
|
||||
else if (c == 1) {
|
||||
return getHelpFile(last);
|
||||
}
|
||||
else {
|
||||
return txt;
|
||||
}
|
||||
|
||||
}
|
||||
wxString FunctionPGHelper::getHelpFile(wxString filename) {
|
||||
wxString tempDir = path + wxFileName::GetPathSeparator() + filename;
|
||||
if (!wxFileExists(tempDir)) return wxEmptyString;
|
||||
wxTextFile tfile;
|
||||
tfile.Open(tempDir);
|
||||
// read the first line
|
||||
wxString str, sbody;
|
||||
sbody = tfile.GetFirstLine();
|
||||
bool flag = true;
|
||||
wxRegEx b("(<body .*?>)");
|
||||
while (!tfile.Eof())
|
||||
{
|
||||
str = tfile.GetNextLine();
|
||||
if (flag && b.Matches(str)) {
|
||||
size_t start, len;
|
||||
b.GetMatch(&start, &len, 0);
|
||||
str = str.Mid(start + len);
|
||||
sbody = "<body>";
|
||||
flag = false;
|
||||
}
|
||||
sbody += str;
|
||||
}
|
||||
return sbody;
|
||||
|
||||
}
|
||||
bool FunctionPGHelper::isValid() {
|
||||
if (!isload) loadfile();
|
||||
return isload;
|
||||
}
|
||||
void FunctionPGHelper::loadfile() {
|
||||
if (isload) return;
|
||||
body.clear();
|
||||
path = settings->GetPgHelpPath();
|
||||
wxString tempDir = path + "_func.txt";
|
||||
//tempDir="C:\\Users\\lsv\\Source\\Repos\\wxHtmlhint\\1";
|
||||
if (!wxFileExists(tempDir)) return;
|
||||
wxTextFile tfile;
|
||||
tfile.Open(tempDir);
|
||||
|
||||
// read the first line
|
||||
wxString str, sbody;
|
||||
wxString name = tfile.GetFirstLine();
|
||||
|
||||
//wxSortedArrayString names;
|
||||
name = name.AfterFirst('#');
|
||||
// read all lines one by one
|
||||
// until the end of the file
|
||||
while (!tfile.Eof())
|
||||
{
|
||||
str = tfile.GetNextLine();
|
||||
if (str.Left(1) == '#') {
|
||||
body.emplace(name, sbody);
|
||||
sbody = "";
|
||||
name = str.AfterFirst('#');
|
||||
}
|
||||
else sbody += str;
|
||||
}
|
||||
body.emplace(name, sbody);
|
||||
isload = true;
|
||||
};
|
||||
|
|
@ -1465,4 +1465,21 @@ bool getArrayFromCommaSeparatedList(const wxString &str, wxArrayString &res)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool make_identifier(const wxString &strname, wxString &s, wxString &n, bool islower) {
|
||||
s=strname.BeforeFirst('.');
|
||||
if (s==strname) {
|
||||
n=strname;
|
||||
s="";
|
||||
} else {
|
||||
// full name
|
||||
n=strname.AfterFirst('.');
|
||||
}
|
||||
//
|
||||
if (n.Find('"')>=0) {
|
||||
n.Replace("\"","");
|
||||
} else {if (islower) n=n.MakeLower();}
|
||||
if (s.Find('"')>=0) {
|
||||
s.Replace("\"","");
|
||||
} else {if (islower) s=s.MakeLower();}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue