@@ -89,6 +89,8 @@ public class ClickHouseStatementImpl extends ConfigurableApi<ClickHouseStatement
8989
9090 private volatile String queryId ;
9191
92+ protected ClickHouseSqlStatement parsedStmt ;
93+
9294 /**
9395 * Current database name may be changed by {@link java.sql.Connection#setCatalog(String)}
9496 * between creation of this object and query execution, but javadoc does not allow
@@ -101,6 +103,43 @@ public class ClickHouseStatementImpl extends ConfigurableApi<ClickHouseStatement
101103 @ Deprecated
102104 private static final String databaseKeyword = "CREATE DATABASE" ;
103105
106+ @ Deprecated
107+ protected void parseSingleStatement (String sql ) throws SQLException {
108+ this .parsedStmt = null ;
109+ ClickHouseSqlStatement [] stmts = ClickHouseSqlParser .parse (sql , properties );
110+
111+ if (stmts .length == 1 ) {
112+ this .parsedStmt = stmts [0 ];
113+ } else {
114+ this .parsedStmt = new ClickHouseSqlStatement (sql , StatementType .UNKNOWN );
115+ // throw new SQLException("Multiple statements are not supported.");
116+ }
117+
118+ if (this .parsedStmt .isIdemponent ()) {
119+ httpContext .setAttribute ("is_idempotent" , Boolean .TRUE );
120+ } else {
121+ httpContext .removeAttribute ("is_idempotent" );
122+ }
123+ }
124+
125+ @ Deprecated
126+ private void parseSingleStatement (String sql , ClickHouseFormat preferredFormat ) throws SQLException {
127+ parseSingleStatement (sql );
128+
129+ if (parsedStmt .isQuery () && !parsedStmt .hasFormat ()) {
130+ String format = preferredFormat .name ();
131+ Map <String , Integer > positions = new HashMap <>();
132+ positions .putAll (parsedStmt .getPositions ());
133+ positions .put (ClickHouseSqlStatement .KEYWORD_FORMAT , sql .length ());
134+
135+ sql = new StringBuilder (parsedStmt .getSQL ()).append ("\n FORMAT " ).append (format ).append (';' )
136+ .toString ();
137+ parsedStmt = new ClickHouseSqlStatement (sql , parsedStmt .getStatementType (),
138+ parsedStmt .getCluster (), parsedStmt .getDatabase (), parsedStmt .getTable (),
139+ format , parsedStmt .getOutfile (), parsedStmt .getParameters (), positions );
140+ }
141+ }
142+
104143 public ClickHouseStatementImpl (CloseableHttpClient client , ClickHouseConnection connection ,
105144 ClickHouseProperties properties , int resultSetType ) {
106145 super (null );
@@ -141,21 +180,23 @@ public ResultSet executeQuery(String sql,
141180 }
142181 additionalDBParams .put (ClickHouseQueryParam .EXTREMES , "0" );
143182
144- InputStream is = getInputStream (sql , additionalDBParams , externalData , additionalRequestParams );
183+ parseSingleStatement (sql , ClickHouseFormat .TabSeparatedWithNamesAndTypes );
184+ if (!parsedStmt .isRecognized () && isSelect (sql )) {
185+ Map <String , Integer > positions = new HashMap <>();
186+ String dbName = extractDBName (sql );
187+ String tableName = extractTableName (sql );
188+ if (extractWithTotals (sql )) {
189+ positions .put (ClickHouseSqlStatement .KEYWORD_TOTALS , 1 );
190+ }
191+ parsedStmt = new ClickHouseSqlStatement (sql , StatementType .SELECT ,
192+ null , dbName , tableName , null , null , null , positions );
193+ // httpContext.setAttribute("is_idempotent", Boolean.TRUE);
194+ }
145195
146- ClickHouseSqlStatement parsedStmt = ClickHouseSqlParser .parseSingleStatement (sql , properties );
196+ InputStream is = getInputStream (sql , additionalDBParams , externalData , additionalRequestParams );
197+
147198 try {
148- if (parsedStmt .isQuery () || (!parsedStmt .isRecognized () && isSelect (sql ))) {
149- if (!parsedStmt .isRecognized ()) {
150- Map <String , Integer > positions = new HashMap <>();
151- String dbName = extractDBName (sql );
152- String tableName = extractTableName (sql );
153- if (extractWithTotals (sql )) {
154- positions .put (ClickHouseSqlStatement .KEYWORD_TOTALS , 1 );
155- }
156- parsedStmt = new ClickHouseSqlStatement (sql , StatementType .SELECT ,
157- null , dbName , tableName , null , null , positions );
158- }
199+ if (parsedStmt .isQuery ()) {
159200 currentUpdateCount = -1 ;
160201 currentResult = createResultSet (properties .isCompress ()
161202 ? new ClickHouseLZ4Stream (is ) : is , properties .getBufferSize (),
@@ -193,8 +234,15 @@ public ClickHouseResponse executeQueryClickhouseResponse(String sql, Map<ClickHo
193234 public ClickHouseResponse executeQueryClickhouseResponse (String sql ,
194235 Map <ClickHouseQueryParam , String > additionalDBParams ,
195236 Map <String , String > additionalRequestParams ) throws SQLException {
237+ parseSingleStatement (sql , ClickHouseFormat .JSONCompact );
238+ if (parsedStmt .isRecognized ()) {
239+ sql = parsedStmt .getSQL ();
240+ } else {
241+ sql = addFormatIfAbsent (sql , ClickHouseFormat .JSONCompact );
242+ }
243+
196244 InputStream is = getInputStream (
197- addFormatIfAbsent ( sql , properties , ClickHouseFormat . JSONCompact ) ,
245+ sql ,
198246 additionalDBParams ,
199247 null ,
200248 additionalRequestParams
@@ -223,15 +271,27 @@ public ClickHouseRowBinaryInputStream executeQueryClickhouseRowBinaryStream(Stri
223271
224272 @ Override
225273 public ClickHouseRowBinaryInputStream executeQueryClickhouseRowBinaryStream (String sql , Map <ClickHouseQueryParam , String > additionalDBParams , Map <String , String > additionalRequestParams ) throws SQLException {
274+ parseSingleStatement (sql , ClickHouseFormat .RowBinary );
275+ if (parsedStmt .isRecognized ()) {
276+ sql = parsedStmt .getSQL ();
277+ } else {
278+ sql = addFormatIfAbsent (sql , ClickHouseFormat .RowBinary );
279+ if (isSelect (sql )) {
280+ parsedStmt = new ClickHouseSqlStatement (sql , StatementType .SELECT );
281+ // httpContext.setAttribute("is_idempotent", Boolean.TRUE);
282+ } else {
283+ parsedStmt = new ClickHouseSqlStatement (sql , StatementType .UNKNOWN );
284+ }
285+ }
286+
226287 InputStream is = getInputStream (
227- addFormatIfAbsent ( sql , properties , ClickHouseFormat . RowBinary ) ,
288+ sql ,
228289 additionalDBParams ,
229290 null ,
230291 additionalRequestParams
231292 );
232- ClickHouseSqlStatement parsedStmt = ClickHouseSqlParser .parseSingleStatement (sql , properties );
233293 try {
234- if (parsedStmt .isQuery () || (! parsedStmt . isRecognized () && isSelect ( sql )) ) {
294+ if (parsedStmt .isQuery ()) {
235295 currentUpdateCount = -1 ;
236296 currentRowBinaryResult = new ClickHouseRowBinaryInputStream (properties .isCompress ()
237297 ? new ClickHouseLZ4Stream (is ) : is , getConnection ().getTimeZone (), properties );
@@ -249,6 +309,8 @@ public ClickHouseRowBinaryInputStream executeQueryClickhouseRowBinaryStream(Stri
249309
250310 @ Override
251311 public int executeUpdate (String sql ) throws SQLException {
312+ parseSingleStatement (sql , ClickHouseFormat .TabSeparatedWithNamesAndTypes );
313+
252314 InputStream is = null ;
253315 try {
254316 is = getInputStream (sql , null , null , null );
@@ -490,24 +552,20 @@ public ClickHouseResponseSummary getResponseSummary() {
490552
491553 @ Deprecated
492554 static String clickhousifySql (String sql ) {
493- return clickhousifySql (sql , null );
494- }
495-
496- static String clickhousifySql (String sql , ClickHouseProperties properties ) {
497- return addFormatIfAbsent (sql , properties , ClickHouseFormat .TabSeparatedWithNamesAndTypes );
555+ return addFormatIfAbsent (sql , ClickHouseFormat .TabSeparatedWithNamesAndTypes );
498556 }
499557
500558 /**
501559 * Adding FORMAT TabSeparatedWithNamesAndTypes if not added
502560 * adds format only to select queries
503561 */
504- private static String addFormatIfAbsent (final String sql , ClickHouseProperties properties , ClickHouseFormat format ) {
562+ @ Deprecated
563+ private static String addFormatIfAbsent (final String sql , ClickHouseFormat format ) {
505564 String cleanSQL = sql .trim ();
506- ClickHouseSqlStatement parsedStmt = ClickHouseSqlParser .parseSingleStatement (cleanSQL , properties );
507- if (!parsedStmt .isQuery () || (!parsedStmt .isRecognized () && !isSelect (cleanSQL ))) {
565+ if (!isSelect (cleanSQL )) {
508566 return cleanSQL ;
509567 }
510- if (parsedStmt . hasFormat () || (! parsedStmt . isRecognized () && ClickHouseFormat .containsFormat (cleanSQL ) )) {
568+ if (ClickHouseFormat .containsFormat (cleanSQL )) {
511569 return cleanSQL ;
512570 }
513571 StringBuilder sb = new StringBuilder ();
@@ -542,6 +600,7 @@ static boolean isSelect(String sql) {
542600 return false ;
543601 }
544602
603+ @ Deprecated
545604 private String extractTableName (String sql ) {
546605 String s = extractDBAndTableName (sql );
547606 if (s .contains ("." )) {
@@ -551,6 +610,7 @@ private String extractTableName(String sql) {
551610 }
552611 }
553612
613+ @ Deprecated
554614 private String extractDBName (String sql ) {
555615 String s = extractDBAndTableName (sql );
556616 if (s .contains ("." )) {
@@ -560,6 +620,7 @@ private String extractDBName(String sql) {
560620 }
561621 }
562622
623+ @ Deprecated
563624 private String extractDBAndTableName (String sql ) {
564625 if (Utils .startsWithIgnoreCase (sql , "select" )) {
565626 String withoutStrings = Utils .retainUnquoted (sql , '\'' );
@@ -582,6 +643,7 @@ private String extractDBAndTableName(String sql) {
582643 return "system.unknown" ;
583644 }
584645
646+ @ Deprecated
585647 private boolean extractWithTotals (String sql ) {
586648 if (Utils .startsWithIgnoreCase (sql , "select" )) {
587649 String withoutStrings = Utils .retainUnquoted (sql , '\'' );
@@ -596,15 +658,23 @@ private InputStream getInputStream(
596658 List <ClickHouseExternalData > externalData ,
597659 Map <String , String > additionalRequestParams
598660 ) throws ClickHouseException {
599- sql = clickhousifySql (sql , properties );
661+ boolean ignoreDatabase = false ;
662+ if (parsedStmt .isRecognized ()) {
663+ sql = parsedStmt .getSQL ();
664+ // TODO consider more scenarios like drop, show etc.
665+ ignoreDatabase = parsedStmt .getStatementType () == StatementType .CREATE
666+ && parsedStmt .containsKeyword (ClickHouseSqlStatement .KEYWORD_DATABASE );
667+ } else {
668+ sql = clickhousifySql (sql );
669+ ignoreDatabase = sql .trim ().regionMatches (true , 0 , databaseKeyword , 0 , databaseKeyword .length ());
670+ }
600671 log .debug ("Executing SQL: {}" , sql );
601672
602673 additionalClickHouseDBParams = addQueryIdTo (
603674 additionalClickHouseDBParams == null
604675 ? new EnumMap <ClickHouseQueryParam , String >(ClickHouseQueryParam .class )
605676 : additionalClickHouseDBParams );
606677
607- boolean ignoreDatabase = sql .trim ().regionMatches (true , 0 , databaseKeyword , 0 , databaseKeyword .length ());
608678 URI uri ;
609679 if (externalData == null || externalData .isEmpty ()) {
610680 uri = buildRequestUri (
0 commit comments