mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 14:15:49 -06:00
Add sql formatter
Добавлено встроенное форматирование Sql запросов. Доработано автодополнение колонок. Добавлено раскрытие <alias>.* в список колонок.
This commit is contained in:
parent
2d3f87edaa
commit
282cf08716
5 changed files with 1582 additions and 2 deletions
|
|
@ -27,6 +27,7 @@
|
|||
#include <wx/aui/aui.h>
|
||||
#include "utils/align/AlignWrap.h"
|
||||
#include "utils/popuphelp.h"
|
||||
#include "utils/FormatterSQL.h"
|
||||
|
||||
wxString ctlSQLBox::sqlKeywords;
|
||||
static const wxString s_leftBrace(_T("([{"));
|
||||
|
|
@ -1038,6 +1039,20 @@ wxString ctlSQLBox::ExternalFormat(int typecmd)
|
|||
|
||||
return _("" + msgword + "ing complete.");
|
||||
}
|
||||
if (typecmd == 0) {
|
||||
FSQL::FormatterSQL f(processInput);
|
||||
int rez = f.ParseSql(0);
|
||||
if (rez >= 0) {
|
||||
wxRect rr(0, 0, 120, 2000);
|
||||
wxString processOutput = f.Formating(rr);
|
||||
if (isSelected)
|
||||
ReplaceSelection(processOutput);
|
||||
else
|
||||
SetText(processOutput);
|
||||
return _("Formatting Ok");
|
||||
} else
|
||||
return wxString::Format("Error parse sql %d",rez);
|
||||
}
|
||||
return _("You need to setup a "+msgword+"ing command");
|
||||
}
|
||||
|
||||
|
|
@ -1479,8 +1494,8 @@ void ctlSQLBox::OnAutoComplete(wxCommandEvent &rev)
|
|||
return;
|
||||
if (m_autocompDisabled)
|
||||
return;
|
||||
|
||||
wxString what = GetCurLine().Left(GetCurrentPos() - PositionFromLine(GetCurrentLine()));;
|
||||
int pos = GetCurrentPos();
|
||||
wxString what = GetCurLine().Left(pos - PositionFromLine(GetCurrentLine()));;
|
||||
int spaceidx = what.Find(' ', true);
|
||||
|
||||
char *tab_ret;
|
||||
|
|
@ -1490,6 +1505,77 @@ void ctlSQLBox::OnAutoComplete(wxCommandEvent &rev)
|
|||
tab_ret = tab_complete(what.mb_str(wxConvUTF8), spaceidx + 1, what.Len() + 1, m_database);
|
||||
wxString wxRet;
|
||||
if ((tab_ret == NULL || tab_ret[0] == '\0')&&(what.Right(1)>' ')){
|
||||
long p = SelectQuery(pos);
|
||||
int s = p >> 16;
|
||||
|
||||
wxString sql = GetTextRange(s, p & 65535);
|
||||
FSQL::FormatterSQL f(sql);
|
||||
int rez = f.ParseSql(0);
|
||||
if (rez >= 0) {
|
||||
// ok query
|
||||
f.BuildAutoComplite(0, 0);
|
||||
int sqlPos = CountCharacters(s,pos);
|
||||
int ItemPos=f.GetIndexItemNextSqlPosition(sqlPos);
|
||||
FSQL::view_item vi;
|
||||
f.GetItem(ItemPos, vi);
|
||||
if (vi.type == FSQL::spaces) {
|
||||
ItemPos--;
|
||||
f.GetItem(ItemPos, vi);
|
||||
}
|
||||
wxString field;
|
||||
bool ast = false;
|
||||
if (vi.type == FSQL::separation) {
|
||||
ast=vi.txt == ".*";
|
||||
while (f.GetItem(--ItemPos, vi)) {
|
||||
if (vi.type == FSQL::identifier || vi.type == FSQL::name) {
|
||||
field = vi.txt;
|
||||
break;
|
||||
}
|
||||
if (vi.srcpos != -1) break;
|
||||
};
|
||||
}
|
||||
else if (vi.type == FSQL::identifier) {
|
||||
field = vi.txt;
|
||||
}
|
||||
if (!field.IsEmpty()) {
|
||||
wxString lf;
|
||||
wxString tabn;
|
||||
|
||||
wxString r=f.GetColsList(field, lf, tabn);
|
||||
int l2 = 0;
|
||||
wxString flt = "";
|
||||
wxString prev=tabn;
|
||||
wxString fld = field.AfterFirst('.');
|
||||
if (fld.Len()>0) l2 = fld.Len();
|
||||
if (tabn.Len() > 0 && r.Len()==0) {
|
||||
if (!field.AfterFirst('.').IsEmpty()) flt = " and a.attname ~* " + qtConnString(fld);
|
||||
wxString sch;
|
||||
if (tabn.Find('.') != -1) sch = tabn.BeforeFirst('.');
|
||||
if (sch.Len() > 0) {
|
||||
tabn = tabn.AfterFirst('.');
|
||||
if (sch[0] == '"') sch.Replace("\"", ""); else sch = sch.Lower();
|
||||
sch = " and relnamespace =" + qtConnString(sch) + "::regnamespace";
|
||||
}
|
||||
if (tabn[0] == '"') tabn.Replace("\"", ""); else tabn = tabn.Lower();
|
||||
wxString sql2 = wxT("select string_agg(a.attname,E'\t' ORDER BY attname) from pg_attribute a where a.attrelid = (select oid from pg_class p where relname=") + qtConnString(tabn) + sch
|
||||
+ wxT(") and a.attisdropped IS FALSE and a.attnum>=0 ") + flt
|
||||
+ wxT("");
|
||||
//pgSet *res = m_database->ExecuteSet(sql);
|
||||
r = m_database->ExecuteScalar(sql2);
|
||||
|
||||
}
|
||||
if (ast) {
|
||||
// replace name.*
|
||||
r.Replace("\t", ", "+ field +".");
|
||||
int npos = pos - 2 - field.Len();
|
||||
DeleteRange(npos, field.Len() + 2);
|
||||
InsertText(npos, field + "."+r);
|
||||
} else
|
||||
AutoCompShow(l2, r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int l=0;
|
||||
wxString alias;
|
||||
wxString fld,tmp;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef PGADMIN3_H
|
||||
#define PGADMIN3_H
|
||||
#include "../utils/diff_match_patch.h"
|
||||
#include "utils/FormatterSQL.h"
|
||||
|
||||
// wxWindows headers
|
||||
#include <wx/wx.h>
|
||||
|
|
|
|||
178
include/utils/FormatterSQL.h
Normal file
178
include/utils/FormatterSQL.h
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
|
||||
#pragma once
|
||||
#include <wx/wx.h>
|
||||
namespace FSQL {
|
||||
/// <summary>
|
||||
/// Formatter SQL
|
||||
/// </summary>
|
||||
enum type_item {
|
||||
unknown
|
||||
, spaces
|
||||
, keyword
|
||||
, literal
|
||||
, separation
|
||||
, bracket
|
||||
, identifier
|
||||
, name
|
||||
, numeric
|
||||
, bindarg
|
||||
, comment
|
||||
};
|
||||
struct view_item {
|
||||
type_item type = unknown;
|
||||
int srcpos = -1; // start position sql text -1 needed ignore
|
||||
int width = 0; //
|
||||
int height = 0;
|
||||
int endlevel = -1; // end bracet or home
|
||||
bool newline = false;
|
||||
int x = 0, y = 0, flags = 0;
|
||||
wxString txt;
|
||||
};
|
||||
enum f_key {
|
||||
none,
|
||||
new_line_align_no_pad = 1,
|
||||
new_line_align_next = 2,
|
||||
newLineComma = 4,
|
||||
newLineXPrevValue = 8,
|
||||
isCASE = 16,
|
||||
special = 32,
|
||||
newLineBracet = 64,
|
||||
HorizontalAlign = 128,
|
||||
isFUNCTION = 256,
|
||||
end_from = 256 << 1,
|
||||
limit = 256 << 2,
|
||||
fetch = 256 << 3,
|
||||
for_up = 256 << 4,
|
||||
fix_position_new_line = 256 << 5,
|
||||
};
|
||||
const struct KEYWORDEntity
|
||||
{
|
||||
const char* name;
|
||||
int len; // == strlen(name)
|
||||
int flags;
|
||||
} keyEntities[] =
|
||||
{
|
||||
{ "as", 2, none },
|
||||
{ "is", 2, none },
|
||||
{ "by", 2, none },
|
||||
{ "in", 2, none },
|
||||
{ "on", 2, HorizontalAlign },
|
||||
{ "of", 2, none },
|
||||
{ "or", 2, newLineXPrevValue },
|
||||
{ "and", 3, newLineXPrevValue},
|
||||
{ "not", 3, none},
|
||||
{ "asc", 3, none},
|
||||
{ "set", 3, none},
|
||||
{ "all", 3, none},
|
||||
{ "end", 3, special},
|
||||
{ "desc", 4, none },
|
||||
{ "like", 4, none},
|
||||
{ "null", 4, none},
|
||||
{ "from", 4, new_line_align_no_pad },
|
||||
{ "case", 4, isCASE },
|
||||
{ "when", 4, new_line_align_no_pad },
|
||||
{ "else", 4, new_line_align_no_pad },
|
||||
{ "with", 4, special },
|
||||
{ "join", 4, new_line_align_next },
|
||||
{ "left", 4, new_line_align_next },
|
||||
{ "full", 4, new_line_align_next },
|
||||
{ "then", 4, none},
|
||||
{ "into", 4, none},
|
||||
{ "last", 4, none},
|
||||
{ "next", 4, none},
|
||||
{ "only", 4, none},
|
||||
{ "cube", 4, none},
|
||||
{ "rows", 4, none},
|
||||
{ "sets", 4, none},
|
||||
{ "where", 5, new_line_align_no_pad | end_from},
|
||||
{ "outer", 5, none},
|
||||
{ "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},
|
||||
{ "group", 5, new_line_align_no_pad | end_from},
|
||||
{ "count", 5, none},
|
||||
{ "using", 5, none},
|
||||
{ "first", 5, none},
|
||||
{ "inner", 5, none},
|
||||
{ "nulls", 5, none},
|
||||
{ "cross", 5, none},
|
||||
|
||||
{ "select", 6, newLineComma | new_line_align_no_pad},
|
||||
{ "update", 6, newLineComma | new_line_align_no_pad},
|
||||
{ "insert", 6, newLineComma | new_line_align_no_pad},
|
||||
{ "values", 6, newLineComma | new_line_align_no_pad},
|
||||
{ "window", 6, new_line_align_no_pad | end_from},
|
||||
{ "having", 6, new_line_align_no_pad | end_from},
|
||||
{ "except", 6, new_line_align_no_pad | end_from},
|
||||
{ "offset", 6, none | end_from},
|
||||
{ "nothing", 7, none},
|
||||
{ "lateral", 7, none},
|
||||
{ "between", 7, none},
|
||||
|
||||
{ "nothing", 7, none},
|
||||
{ "default", 7, none},
|
||||
{ "current", 7, none},
|
||||
{ "distinct", 8, none},
|
||||
{ "conflict", 8, none},
|
||||
{ "recursive", 9, none},
|
||||
{ "intersect", 9, new_line_align_no_pad | end_from},
|
||||
{ "returning", 9, none},
|
||||
{ "ordinality", 10, none},
|
||||
{ "materialized", 12, none},
|
||||
};
|
||||
struct complite_element {
|
||||
wxString table;
|
||||
wxString alias;
|
||||
wxString columnList;
|
||||
int startIndex = -1;
|
||||
int endIndex = -1;
|
||||
};
|
||||
struct bits {
|
||||
unsigned int from : 1;
|
||||
unsigned int select_list : 1;
|
||||
unsigned int with : 1;
|
||||
unsigned int skip : 1;
|
||||
};
|
||||
union Byte {
|
||||
unsigned char byte;
|
||||
struct bits b;
|
||||
};
|
||||
|
||||
class FormatterSQL {
|
||||
public:
|
||||
FormatterSQL(const wxString& sqlsrc) {
|
||||
sql = sqlsrc;
|
||||
}
|
||||
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 GetColsList(wxString what, wxString& listfieldOut, wxString& nameTableOut);
|
||||
//
|
||||
int ParseSql(int flags);
|
||||
wxString printParseArray();
|
||||
void SetSql(const wxString& sqlsrc) { sql = sqlsrc; }
|
||||
int GetIndexItemNextSqlPosition(int sqlPosition);
|
||||
bool GetItem(int index, FSQL::view_item& item);
|
||||
private:
|
||||
wxString get_list_columns(int startindex, union FSQL::Byte zone);
|
||||
|
||||
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);
|
||||
int next_item_no_space(int& index, int direction = 1);
|
||||
wxSize max_width_size(int index); // index bracet
|
||||
wxSize best_sizeAndDraw(wxDC& dc, wxPoint& pos, FSQL::view_item& vi, int mode);
|
||||
int maxYheightLine = 0;
|
||||
int max_exp_bracet_width = 200;
|
||||
int pad = 16;
|
||||
int casepad = 8;
|
||||
wxPoint neededNewLine; // добавляет новую строку перед первым встреченным не пробельным символом
|
||||
wxRect rect;
|
||||
wxString sql;
|
||||
std::vector<FSQL::view_item> items;
|
||||
std::vector<FSQL::complite_element> listTable; // перечень таблиц синонимов, подзапросов и функций с колонками
|
||||
//int recurse(int level);
|
||||
};
|
||||
}
|
||||
|
|
@ -1035,6 +1035,7 @@
|
|||
<ClCompile Include="utils\align\AlignWrap.cpp" />
|
||||
<ClCompile Include="utils\align\Item.cpp" />
|
||||
<ClCompile Include="utils\csvfiles.cpp" />
|
||||
<ClCompile Include="utils\FormatterSQL.cpp" />
|
||||
<ClCompile Include="utils\diff_match_patch.cc">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
@ -1613,8 +1614,11 @@
|
|||
<ClInclude Include="include\utils\registr.h" />
|
||||
<ClInclude Include="include\utils\registry.h" />
|
||||
<ClInclude Include="include\utils\sysLogger.h" />
|
||||
<ClInclude Include="include\utils\FormatterSQL.h" />
|
||||
<ClInclude Include="include\utils\sysProcess.h" />
|
||||
<ClInclude Include="include\utils\sysSettings.h" />
|
||||
<ClInclude Include="include\utils\popuphelp.h" />
|
||||
<ClInclude Include="include\utils\FunctionPGHelper.h" />
|
||||
<ClInclude Include="include\utils\utffile.h" />
|
||||
<ClInclude Include="include\ctl\calbox.h" />
|
||||
<ClInclude Include="include\ctl\ctlAuiNotebook.h" />
|
||||
|
|
|
|||
1311
utils/FormatterSQL.cpp
Normal file
1311
utils/FormatterSQL.cpp
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue