Fix generate Insert SQL instruction. Copying result lines based on a template.

1. При некоторых настройках при генерации Insert инструкций, пустые строки заменялись на null.
   Этот коммит исправлет проблему.
2. Результаты запросов можно оформить произвольным образом используя шаблоны указанные в однострочных
   коментариях.
   Формат шаблона: --@gen:Имя шаблона в контестном меню результата:Тут текст шаблона - cols = @colname@,@colname2,a@\n
   Для добавлнения перевода строк в вывод можно использовать \n.
   Коментарии указывается в теле запроса (можно указать перед запросом).
   Можно указать строку из которой нужно сделать выбрать содержимое:
       @colname[-1]@ - содержимое колонки colname предыдущей строки(относительная адресация).
       @colname[0]@  - содержимое колонки colname 1 строки (или выделенного диапазона строк).
                       Адресация с начинается с 0. Это абсолютная адресация строк.
       @colname2,a@  - Указание что результат нужно будет выровнять.
                       Флаг "а" глобальный его можно указать у любой колонки.
       Флаги указываются в самом конце определения колонки после запятой. Пример: @col1[-1],a@

   Если перечень имен колонок запроса не совпадает со списком полей шаблона то шаблон не будет добавлен
   в контекстное меню Generate.
   Полученный текст копируется в буфер обмена.
   При генерации текста используются настройки "Вид кавычек" и "Что брать в кавычки".
   Шаблоны сохраняются перед выполнением SQL команды и после редактирования шаблона
   запрос нужно выполнить повторно.
This commit is contained in:
lsv 2026-01-14 17:17:08 +05:00
parent 087ad55c34
commit a8ddbc4999
8 changed files with 235 additions and 10 deletions

View file

@ -284,6 +284,7 @@ wxString ctlSQLGrid::GetExportLine(int row, wxArrayInt cols)
if (GetNumberCols() == 0 || GetRowSize(row) == 0)
return str;
sqlResultTable *t=(sqlResultTable *)GetTable();
wxString colsep = settings->GetCopyColSeparator();
if (generatesql == 2 || generatesql == 1) colsep = wxT(",");
if (generatesql == 3) colsep = wxT(" and ");
@ -297,7 +298,14 @@ wxString ctlSQLGrid::GetExportLine(int row, wxArrayInt cols)
str.Append(colsep);
if (col > 0) head.Append(colsep);
head = head + GetColumnName(cols[col]);
wxString text = GetCellValue(row, cols[col]);
wxString text;
bool isnull=false;
if ( t && generatesql > 0)
{
// only insert , in_list and where list
text = t->GetValueWithNull( row, cols[col] , &isnull );
} else text = GetCellValue(row, cols[col]);
wxString cname = GetColumnName(cols[col]);
bool needQuote = false;
if (settings->GetCopyQuoting() == 1)
@ -307,12 +315,12 @@ wxString ctlSQLGrid::GetExportLine(int row, wxArrayInt cols)
else if (settings->GetCopyQuoting() == 2)
/* Quote everything */
needQuote = true;
if (text.Length() == 0 && generatesql > 0) { needQuote = false; }
if (isnull && generatesql > 0) { needQuote = false; }
else
if (generatesql > 0) needQuote = IsColText(cols[col]);
if (generatesql > 0) {
if (text.Length() != 0) {
if (!isnull) {
text.Replace(wxT("'"), wxT("''"));
}
else
@ -320,7 +328,7 @@ wxString ctlSQLGrid::GetExportLine(int row, wxArrayInt cols)
}
if (generatesql == 3) {
if (text == "null")
if (isnull)
str.Append(cname).Append(" is ");
else
str.Append(cname).Append("=");

View file

@ -23,7 +23,7 @@
#include "frm/mathplot.h"
#include "frm/frmPlot.h"
#include "ctl/SourceViewDialog.h"
#include "utils/align/AlignWrap.h"
ctlSQLResult::ctlSQLResult(wxWindow *parent, pgConn *_conn, wxWindowID id, const wxPoint &pos, const wxSize &size)
: ctlSQLGrid(parent, id, pos, size)
@ -339,6 +339,160 @@ wxString ctlSQLResult::OnGetItemText(long item, long col) const
}
return wxEmptyString;
}
struct type_temp_flag {
uint8_t colvalue:1;
uint8_t colname:1;
uint8_t indexrow:1;
};
struct ElementTempl {
wxString txt;
type_temp_flag flags = {0};
int column=-1;
int row=-1;
};
wxString ctlSQLResult::GenerateTemplate(wxString &templ,int action)
{
std::vector<ElementTempl> tmplvector;
wxString rez;
int qt=settings->GetCopyQuoting();
wxString qtsimbol = settings->GetCopyQuoteChar();
wxString qtsimbol2=qtsimbol+qtsimbol;
// Parse and prepare template string
wxChar c;
int isalign=false;
int len=templ.Len();
int pos=0;
ElementTempl e;
bool isvar=false;
wxString col;
while (pos<len)
{
c=templ[pos++];
if (c=='\\' && pos<len) {
c=templ[pos++];
if (c=='n') c='\n';
}
if (isvar) {
if (c==',') {
while (pos<len && ((c=templ[pos++])!='@'))
{
//if (c=='n') e.flags.colname=true;
if (c=='a') isalign=true;
}
}
if (c=='[') {
wxString strrow;
while (pos<len && ((c=templ[pos++])!=']'))
{
strrow.Append(c);
}
if (strrow.Len()>0) {
long rr=StrToLong(strrow);
e.row=rr;
e.flags.indexrow=true;
}
continue;
}
if (c=='@') {
isvar=false;
int idx=colNames.Index(col);
if (idx==wxNOT_FOUND) {
if (action == 0) wxMessageBox(wxString::Format("Not found col name %s in result query.",col));
return wxEmptyString;
}
e.column=idx;
tmplvector.push_back(e);
e.flags={0};
} else
col.Append(c);
continue;
}
if (c!='@') {
e.txt.Append(c);
} else {
isvar=true;
tmplvector.push_back(e);
e.txt.Clear();
col.Clear();
e.flags.colvalue=true;
}
}
if (isvar )
{
if (action == 0) wxMessageBox(wxString::Format("No close col name %s",col));
return wxEmptyString;
}
else
{
if (e.txt.Len()>0) tmplvector.push_back(e);
}
//
if (action==1) return "OK"; // only correct parse
wxArrayInt rows = GetSelectedRows();
size_t numRows = GetNumberRows();
size_t numRows2 = GetNumberRows();
if (rows.Count()>0) numRows=rows.Count();
size_t row=0;
sqlResultTable *t=(sqlResultTable *)GetTable();
while (row < numRows)
{
int r=0;
if (rows.Count()>0) r=rows[row++]; else r=row++;
wxString strrow;
for (auto e:tmplvector)
{
if (e.flags.colvalue==false) {
strrow.Append(e.txt);
continue;
}
if (e.flags.indexrow) {
int dr=e.row;
if (dr<0) dr=row+dr-1;
if (dr>=0 && dr<numRows) r=dr;
if (rows.Count()>0) r=rows[r]; else r=r;
}
bool isnull=false;
wxString text = t->GetValueWithNull( r, e.column , &isnull );
bool needQuote = false;
if (qt == 1)
{
needQuote = IsColText(e.column);
}
else if (qt == 2)
/* Quote everything */
needQuote = true;
if (needQuote) text.Replace(qtsimbol, qtsimbol2);
if (isnull) strrow.Append("null");
else
{
if (needQuote)
strrow.Append(qtsimbol);
strrow.Append(text);
if (needQuote)
strrow.Append(qtsimbol);
}
}
rez.Append(strrow);
}
if (isalign) {
int cfg = AlignWrap::ALL_LINES| AlignWrap::FIRST_LINE;
AlignWrap a;
wxString lineEnd = wxT("\n");
rez=a.build(rez,cfg,lineEnd);
}
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(rez));
wxTheClipboard->Close();
}
return rez;
}
wxString ctlSQLResult::CopySelColumnNameType(bool onlyname)
{
wxString ss = wxEmptyString;
@ -1151,6 +1305,24 @@ wxString sqlResultTable::GetValueFast(int row, int col)
}
return "";
}
wxString sqlResultTable::GetValueWithNull(int row, int col, bool *isnull) {
wxString s;
if (thread && thread->DataValid())
{
if (col >= 0)
{
if (use_map) row=maplines[row];
thread->DataSet()->Locate(row + 1);
wxString s = thread->DataSet()->GetVal(col);
*isnull = thread->DataSet()->IsNull(col);
return s;
}
}
return "";
}
wxString sqlResultTable::GetValue(int row, int col)
{
if (thread && thread->DataValid())