Skip to content

Commit 368a60e

Browse files
Cybsogerdwagner
authored andcommitted
Feature: Pull request: #51
To change the statement separator during SQL execution, use the following command on a separate line: --#SET TERMINATOR <separator> This command does not change the separator permanently but for a single SQL execution only. See also menu File --> New Session Properties --> tab SQL --> section "Statement separator" Thanks to Roland Tapken for the pull request
1 parent 384023f commit 368a60e

File tree

9 files changed

+222
-57
lines changed

9 files changed

+222
-57
lines changed

sql12/core/doc/changes.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ Not yet released, available in our GIT repository, snapshots and future releases
66

77
Enhancements:
88

9+
Pull request: https://github.com/squirrel-sql-client/squirrel-sql-code/pull/51
10+
To change the statement separator during SQL execution, use the following command on a separate line:
11+
--#SET TERMINATOR <separator>
12+
This command does not change the separator permanently but for a single SQL execution only.
13+
See also menu File --> New Session Properties --> tab SQL --> section "Statement separator"
14+
Thanks to Roland Tapken for the pull request
15+
916
Find function in cell data popup and Object tree's text detail tabs:
1017
The "Mark all" toggle button now writes the number of occurrences to SQuirreL's message panel.
1118

sql12/core/src/net/sourceforge/squirrel_sql/client/session/mainpanel/resulttabheader/ResultTabMatchingCurrentSqlHandler.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
package net.sourceforge.squirrel_sql.client.session.mainpanel.resulttabheader;
22

3-
import java.util.ArrayList;
4-
import java.util.Collections;
5-
import java.util.Comparator;
6-
import java.util.List;
7-
import javax.swing.JTabbedPane;
8-
import javax.swing.Timer;
9-
103
import net.sourceforge.squirrel_sql.client.Main;
114
import net.sourceforge.squirrel_sql.client.session.ISQLEntryPanel;
125
import net.sourceforge.squirrel_sql.client.session.editorpaint.TextAreaPaintListener;
136
import net.sourceforge.squirrel_sql.client.session.mainpanel.IResultTab;
147
import net.sourceforge.squirrel_sql.client.session.mainpanel.SQLResultExecutorPanel;
158
import net.sourceforge.squirrel_sql.client.session.sqlbounds.BoundsOfSqlHandler;
169
import net.sourceforge.squirrel_sql.fw.sql.querytokenizer.IQueryTokenizer;
10+
import net.sourceforge.squirrel_sql.fw.sql.querytokenizer.QueryTokenizePurpose;
1711
import org.apache.commons.lang3.StringUtils;
1812

13+
import javax.swing.JTabbedPane;
14+
import javax.swing.Timer;
15+
import java.util.ArrayList;
16+
import java.util.Collections;
17+
import java.util.Comparator;
18+
import java.util.List;
19+
1920
public class ResultTabMatchingCurrentSqlHandler
2021
{
2122
private boolean _resultTabHeaderMarkingActive;
@@ -84,7 +85,7 @@ private void onTextAreaPaint(boolean activateLastMarked)
8485
{
8586

8687
IQueryTokenizer qt = _entryPanel.getSession().getNewQueryTokenizer();
87-
qt.setScriptToTokenize(sqlToBeExecuted);
88+
qt.setScriptToTokenize(sqlToBeExecuted, QueryTokenizePurpose.OTHER);
8889

8990
if(false == qt.hasQuery())
9091
{

sql12/core/src/net/sourceforge/squirrel_sql/client/session/properties/I18NStrings.properties

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,9 @@ NullValuesSortingPanel.sort.null.highest=Highest
156156
NullValuesSortingPanel.sort.null.lowest=Lowest
157157

158158

159-
SQLPropertiesPanel.separators.info=Multiple character separators must be surrounded by white spaces.\nSingle character separators can be used without surrounding white spaces.
159+
SQLPropertiesPanel.separators.info=Multiple character separators must be surrounded by white spaces.\nSingle character separators can be used without surrounding white spaces.
160+
161+
SQLPropertiesPanel.separators.set.statement.separator.info.begin=Info:\nTo change the statement separator during SQL execution, use the following command on a separate line:
162+
SQLPropertiesPanel.separators.set.statement.separator.info.command=--#SET TERMINATOR <separator>
163+
SQLPropertiesPanel.separators.set.statement.separator.info.end=Note this command does not change the separator permanently but for a single SQL execution only.
164+
SQLPropertiesPanel.separators.title=Statement separator

sql12/core/src/net/sourceforge/squirrel_sql/client/session/properties/SQLPropertiesPanel.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,31 @@
33
import net.sourceforge.squirrel_sql.client.mainframe.action.findprefs.AddressablePrefJPanel;
44
import net.sourceforge.squirrel_sql.client.mainframe.action.findprefs.PreferencesAddressBook;
55
import net.sourceforge.squirrel_sql.client.session.ISession;
6-
import net.sourceforge.squirrel_sql.fw.gui.*;
6+
import net.sourceforge.squirrel_sql.fw.gui.FontChooser;
7+
import net.sourceforge.squirrel_sql.fw.gui.FontInfo;
8+
import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
9+
import net.sourceforge.squirrel_sql.fw.gui.IntegerField;
10+
import net.sourceforge.squirrel_sql.fw.gui.MultipleLineLabel;
711
import net.sourceforge.squirrel_sql.fw.sql.querytokenizer.IQueryTokenizer;
812
import net.sourceforge.squirrel_sql.fw.sql.querytokenizer.TokenizerSessPropsInteractions;
913
import net.sourceforge.squirrel_sql.fw.util.StringManager;
1014
import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
1115

12-
import javax.swing.*;
16+
import javax.swing.BorderFactory;
17+
import javax.swing.JButton;
18+
import javax.swing.JCheckBox;
19+
import javax.swing.JLabel;
20+
import javax.swing.JPanel;
21+
import javax.swing.JTextField;
22+
import javax.swing.SwingConstants;
23+
import javax.swing.UIManager;
1324
import javax.swing.event.ChangeEvent;
1425
import javax.swing.event.ChangeListener;
15-
import java.awt.*;
26+
import java.awt.Color;
27+
import java.awt.Font;
28+
import java.awt.GridBagConstraints;
29+
import java.awt.GridBagLayout;
30+
import java.awt.Insets;
1631
import java.awt.event.ActionEvent;
1732
import java.awt.event.ActionListener;
1833

@@ -397,7 +412,19 @@ private JPanel createStatementSeparatorPanel()
397412
gbc = new GridBagConstraints(1,1,1,1,0,0,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5,3,2,2), 0,0);
398413
ret.add(_stmtSepField, gbc);
399414

400-
ret.setBorder(BorderFactory.createEtchedBorder());
415+
416+
gbc = new GridBagConstraints(0,2,2,1,0,0,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10,3,0,2), 0,0);
417+
ret.add(new MultipleLineLabel(s_stringMgr.getString("SQLPropertiesPanel.separators.set.statement.separator.info.begin")), gbc);
418+
419+
gbc = new GridBagConstraints(0,3,2,1,0,0,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0,3,0,2), 0,0);
420+
MultipleLineLabel lblSepCommand = new MultipleLineLabel(s_stringMgr.getString("SQLPropertiesPanel.separators.set.statement.separator.info.command"));
421+
lblSepCommand.setFont(new Font(Font.MONOSPACED, lblSepCommand.getFont().getStyle(), lblSepCommand.getFont().getSize()));
422+
ret.add(lblSepCommand, gbc);
423+
424+
gbc = new GridBagConstraints(0,4,2,1,0,0,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0,3,2,2), 0,0);
425+
ret.add(new MultipleLineLabel(s_stringMgr.getString("SQLPropertiesPanel.separators.set.statement.separator.info.end")), gbc);
426+
427+
ret.setBorder(BorderFactory.createTitledBorder(s_stringMgr.getString("SQLPropertiesPanel.separators.title")));
401428

402429
return ret;
403430
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package net.sourceforge.squirrel_sql.fw.sql.querytokenizer;
2+
3+
import net.sourceforge.squirrel_sql.fw.sql.commentandliteral.SQLCommentAndLiteralHandler;
4+
import org.apache.commons.lang3.StringUtils;
5+
6+
public class ChangeStatementSeparatorSupport
7+
{
8+
private static final String SET_TERMINATOR_COMMAND = "#SET TERMINATOR ";
9+
private final String _script;
10+
private final String _lineCommentBegin;
11+
private String _terminatorCommandInclLineCommentPrefix;
12+
13+
private final boolean _scriptContainsTerminatorActive;
14+
15+
public ChangeStatementSeparatorSupport(QueryTokenizePurpose queryTokenizePurpose, String script, String lineCommentBegin)
16+
{
17+
_script = script;
18+
_lineCommentBegin = lineCommentBegin;
19+
_terminatorCommandInclLineCommentPrefix = _lineCommentBegin + SET_TERMINATOR_COMMAND;
20+
21+
_scriptContainsTerminatorActive =
22+
queryTokenizePurpose == QueryTokenizePurpose.STATEMENT_EXECUTION
23+
&& StringUtils.containsIgnoreCase(script, _terminatorCommandInclLineCommentPrefix);
24+
}
25+
26+
/**
27+
* Check for a line that contains '--#SET TERMINATOR x' to change the current new statement separator
28+
* The line may start by spaces or tabs. Other characters are not allowed.
29+
*/
30+
public String findSetTerminatorInstruction(final int searchStartPos, SQLCommentAndLiteralHandler commentAndLiteralHandler)
31+
{
32+
if(false == isActive())
33+
{
34+
return null;
35+
}
36+
37+
if(commentAndLiteralHandler.isInLiteral() || commentAndLiteralHandler.isInMultiLineComment())
38+
{
39+
return null;
40+
}
41+
42+
if(false == StringUtils.startsWithIgnoreCase(_script.substring(searchStartPos), _terminatorCommandInclLineCommentPrefix))
43+
{
44+
return null;
45+
}
46+
47+
if(isCommandPrecededBySpacesOrTabsOnly(_script, searchStartPos))
48+
{
49+
return null;
50+
}
51+
52+
// Only when the comment starts on a new line
53+
int newLinePos = _script.indexOf('\n', searchStartPos);
54+
if(newLinePos > searchStartPos + _terminatorCommandInclLineCommentPrefix.length())
55+
{
56+
String terminator = _script.substring(searchStartPos + _terminatorCommandInclLineCommentPrefix.length(), newLinePos).trim();
57+
if(!terminator.isEmpty())
58+
{
59+
return terminator;
60+
}
61+
}
62+
63+
64+
return null;
65+
}
66+
67+
private static boolean isCommandPrecededBySpacesOrTabsOnly(String script, int searchStartPos)
68+
{
69+
// Check if the comment is only preceded by spaces or tabs
70+
int j = searchStartPos;
71+
while(j-- > 0)
72+
{
73+
char c = script.charAt(j);
74+
if(c == '\n')
75+
{
76+
// Found the start of the line, break the loop
77+
break;
78+
}
79+
else if(c != ' ' && c != '\t')
80+
{
81+
// Found non-whitespace character
82+
return true;
83+
}
84+
}
85+
return false;
86+
}
87+
88+
public boolean isActive()
89+
{
90+
return _scriptContainsTerminatorActive;
91+
}
92+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
QueryTokenizer.change.statement.separator.message=Changing statement separator for current execution from statement #{0} on to {1}

sql12/core/src/net/sourceforge/squirrel_sql/fw/sql/querytokenizer/IQueryTokenizer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ public interface IQueryTokenizer
3535
* @param script a string representing one or more SQL statements.
3636
*/
3737
void setScriptToTokenize(String script);
38-
38+
39+
void setScriptToTokenize(String script, QueryTokenizePurpose queryTokenizePurpose);
40+
3941
/**
4042
* Returns the number of queries that the tokenizer found in the script
4143
* given in the last call to setScriptToTokenize, or 0 if
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package net.sourceforge.squirrel_sql.fw.sql.querytokenizer;
2+
3+
public enum QueryTokenizePurpose
4+
{
5+
STATEMENT_EXECUTION,
6+
OTHER
7+
}

sql12/core/src/net/sourceforge/squirrel_sql/fw/sql/querytokenizer/QueryTokenizer.java

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1919
*/
2020

21+
import net.sourceforge.squirrel_sql.client.Main;
2122
import net.sourceforge.squirrel_sql.client.session.action.sqlscript.SQLScriptServices;
2223
import net.sourceforge.squirrel_sql.fw.preferences.IQueryTokenizerPreferenceBean;
2324
import net.sourceforge.squirrel_sql.fw.sql.commentandliteral.NextPositionAction;
2425
import net.sourceforge.squirrel_sql.fw.sql.commentandliteral.SQLCommentAndLiteralHandler;
26+
import net.sourceforge.squirrel_sql.fw.util.StringManager;
27+
import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
2528
import net.sourceforge.squirrel_sql.fw.util.StringUtilities;
2629
import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
2730
import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
@@ -35,7 +38,11 @@
3538

3639
public class QueryTokenizer implements IQueryTokenizer
3740
{
38-
protected ArrayList<QueryHolder> _queries = new ArrayList<>();
41+
private final static ILogger s_log = LoggerController.createLogger(QueryTokenizer.class);
42+
StringManager s_stringMgr = StringManagerFactory.getStringManager(QueryTokenizer.class);
43+
44+
45+
protected ArrayList<QueryHolder> _queries = new ArrayList<>();
3946

4047
protected Iterator<QueryHolder> _queryIterator;
4148

@@ -48,7 +55,6 @@ public class QueryTokenizer implements IQueryTokenizer
4855

4956
protected ITokenizerFactory _tokenizerFactory = null;
5057

51-
private final static ILogger s_log = LoggerController.createLogger(QueryTokenizer.class);
5258

5359
public QueryTokenizer(String querySep,
5460
String lineCommentBegin,
@@ -151,62 +157,79 @@ public QueryHolder nextQuery()
151157

152158
public void setScriptToTokenize(String script)
153159
{
154-
_queries.clear();
155-
156-
script = script.replace('\r', ' ');
160+
setScriptToTokenize(script, QueryTokenizePurpose.STATEMENT_EXECUTION);
161+
}
162+
163+
public void setScriptToTokenize(String script, QueryTokenizePurpose queryTokenizePurpose)
164+
{
165+
_queries.clear();
157166

158-
StringBuffer curQuery = new StringBuffer();
159-
StringBuffer curOriginalQuery = new StringBuffer();
167+
script = script.replace('\r', ' ');
160168

169+
StringBuffer curQuery = new StringBuffer();
170+
StringBuffer curOriginalQuery = new StringBuffer();
161171

162172
SQLCommentAndLiteralHandler commentAndLiteralHandler = new SQLCommentAndLiteralHandler(script, _lineCommentBegin, _removeMultiLineComment, _removeLineComment);
173+
ChangeStatementSeparatorSupport changeStatementSeparatorSupport = new ChangeStatementSeparatorSupport(queryTokenizePurpose, script, _lineCommentBegin);
163174

164-
for (int i = 0; i < script.length(); ++i)
165-
{
166-
final NextPositionAction nextPositionAction = commentAndLiteralHandler.nextPosition(i);
175+
for(int i = 0; i < script.length(); ++i)
176+
{
177+
final NextPositionAction nextPositionAction = commentAndLiteralHandler.nextPosition(i);
167178

168-
curOriginalQuery.append(script.charAt(i));
179+
if(changeStatementSeparatorSupport.isActive())
180+
{
181+
String newQuerySep = changeStatementSeparatorSupport.findSetTerminatorInstruction(i, commentAndLiteralHandler);
182+
if(newQuerySep != null)
183+
{
184+
String msg = s_stringMgr.getString("QueryTokenizer.change.statement.separator.message", _queries.size() + 1, newQuerySep);
185+
Main.getApplication().getMessageHandler().showMessage(msg);
186+
s_log.info(msg);
187+
setQuerySep(newQuerySep);
188+
}
189+
}
169190

170-
if(NextPositionAction.APPEND == nextPositionAction)
171-
{
172-
curQuery.append(script.charAt(i));
173-
}
174-
else
175-
{
176-
continue;
177-
}
191+
curOriginalQuery.append(script.charAt(i));
178192

179-
int querySepLen = getLenOfQuerySepIfAtLastCharOfQuerySep(script, i, _querySep, commentAndLiteralHandler.isInLiteral());
193+
if(NextPositionAction.APPEND == nextPositionAction)
194+
{
195+
curQuery.append(script.charAt(i));
196+
}
197+
else
198+
{
199+
continue;
200+
}
180201

181-
if(-1 < querySepLen && !commentAndLiteralHandler.isInMultiLineComment())
182-
{
183-
int newLength = curQuery.length() - querySepLen;
184-
if(-1 < newLength && curQuery.length() > newLength)
185-
{
186-
curQuery.setLength(newLength);
202+
int querySepLen = getLenOfQuerySepIfAtLastCharOfQuerySep(script, i, _querySep, commentAndLiteralHandler.isInLiteral());
203+
204+
if(-1 < querySepLen && !commentAndLiteralHandler.isInMultiLineComment())
205+
{
206+
int newLength = curQuery.length() - querySepLen;
207+
if(-1 < newLength && curQuery.length() > newLength)
208+
{
209+
curQuery.setLength(newLength);
187210

188-
String newQuery = curQuery.toString().trim();
189-
if(0 < newQuery.length())
190-
{
191-
_queries.add(new QueryHolder(curQuery.toString().trim(), curOriginalQuery.toString().trim()));
192-
}
211+
String newQuery = curQuery.toString().trim();
212+
if(0 < newQuery.length())
213+
{
214+
_queries.add(new QueryHolder(curQuery.toString().trim(), curOriginalQuery.toString().trim()));
193215
}
194-
curQuery.setLength(0);
195-
curOriginalQuery.setLength(0);
196-
}
197-
}
216+
}
217+
curQuery.setLength(0);
218+
curOriginalQuery.setLength(0);
219+
}
220+
}
198221

199-
String lastQuery = curQuery.toString().trim();
200-
String lastOriginalQuery = curOriginalQuery.toString().trim();
201-
if(0 < lastQuery.length())
202-
{
203-
_queries.add(new QueryHolder(lastQuery, lastOriginalQuery));
204-
}
222+
String lastQuery = curQuery.toString().trim();
223+
String lastOriginalQuery = curOriginalQuery.toString().trim();
224+
if(0 < lastQuery.length())
225+
{
226+
_queries.add(new QueryHolder(lastQuery, lastOriginalQuery));
227+
}
205228

206-
_queryIterator = _queries.iterator();
229+
_queryIterator = _queries.iterator();
207230
}
208231

209-
/**
232+
/**
210233
* Returns the number of queries that the tokenizer found in the script
211234
* given in the last call to setScriptToTokenize, or 0 if
212235
* setScriptToTokenize has not yet been called.

0 commit comments

Comments
 (0)