001package gudusoft.gsqlparser.sqlcmds; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.stmt.*; 005import gudusoft.gsqlparser.stmt.mysql.*; 006 007/** 008 * ClickHouse SQL command resolver. 009 * Handles ClickHouse-specific statement detection and command resolution. 010 * Based on MySQL command resolver since ClickHouse grammar is derived from MySQL. 011 * 012 * @since 3.2.0.0 013 */ 014public class TSqlCmdsClickhouse extends AbstractSqlCmds { 015 016 public TSqlCmdsClickhouse() { 017 super(EDbVendor.dbvclickhouse); 018 } 019 020 @Override 021 protected void initializeCommands() { 022 // ClickHouse commands - based on MySQL with ClickHouse-specific adaptations 023 024 // ALTER commands 025 addCmd(TBaseType.rrw_alter, "database", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlalterdatabase); 026 addCmd(TBaseType.rrw_alter, "table", " ", " ", " ", " ", " ", ESqlStatementType.sstaltertable); 027 addCmd(TBaseType.rrw_alter, "view", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlalterview); 028 029 // CREATE commands 030 addCmd(TBaseType.rrw_create, "database", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlcreatedatabase); 031 addCmd(TBaseType.rrw_create, "function", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlcreatefunction); 032 addCmd(TBaseType.rrw_create, "index", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlcreateindex); 033 addCmd(TBaseType.rrw_create, "or", "replace", "table", " ", " ", " ", ESqlStatementType.sstcreatetable); 034 addCmd(TBaseType.rrw_create, "or", "replace", "*", "*", "*", "view", ESqlStatementType.sstcreateview); 035 addCmd(TBaseType.rrw_create, "or", "replace", "view", " ", " ", " ", ESqlStatementType.sstcreateview); 036 addCmd(TBaseType.rrw_create, "materialized", "view", " ", " ", " ", " ", ESqlStatementType.sstcreatematerializedview); 037 addCmd(TBaseType.rrw_create, "window", "view", " ", " ", " ", " ", ESqlStatementType.sstClickhouseCreateWindowView); 038 addCmd(TBaseType.rrw_create, "temporary", "table", " ", " ", " ", " ", ESqlStatementType.sstcreatetable); 039 addCmd(TBaseType.rrw_create, "temp", "table", " ", " ", " ", " ", ESqlStatementType.sstcreatetable); 040 addCmd(TBaseType.rrw_create, "table", " ", " ", " ", " ", " ", ESqlStatementType.sstcreatetable); 041 addCmd(TBaseType.rrw_create, "*", "*", "*", "*", "*", "view", ESqlStatementType.sstcreateview); 042 addCmd(TBaseType.rrw_create, "view", " ", " ", " ", " ", " ", ESqlStatementType.sstcreateview); 043 044 // DELETE 045 addCmd(TBaseType.rrw_delete, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstdelete); 046 047 // DESCRIBE / DESC 048 addCmd(TBaseType.rrw_describe, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstdescribe); 049 addCmd(TBaseType.rrw_mysql_desc, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstdescribe); 050 051 // DROP commands 052 addCmd(TBaseType.rrw_drop, "database", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqldropdatabase); 053 addCmd(TBaseType.rrw_drop, "function", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqldropfunction); 054 addCmd(TBaseType.rrw_drop, "index", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqldropindex); 055 addCmd(TBaseType.rrw_drop, "table", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqldroptable); 056 addCmd(TBaseType.rrw_drop, "temporary", "table", " ", " ", " ", " ", ESqlStatementType.sstmysqldroptable); 057 addCmd(TBaseType.rrw_drop, "view", " ", " ", " ", " ", " ", ESqlStatementType.sstdropview); 058 059 // EXPLAIN 060 addCmd(TBaseType.rrw_explain, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstExplain); 061 062 // GRANT / REVOKE 063 addCmd(TBaseType.rrw_grant, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlgrant); 064 addCmd(TBaseType.rrw_revoke, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlrevoke); 065 066 // INSERT 067 addCmd(TBaseType.rrw_insert, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstinsert); 068 069 // OPTIMIZE 070 addCmd(TBaseType.rrw_optimize, "table", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqloptimizetable); 071 072 // RENAME 073 addCmd(TBaseType.rrw_rename, "table", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlrenametable); 074 075 // SELECT 076 addCmd(TBaseType.rrw_select, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstselect); 077 078 // SET 079 addCmd(TBaseType.rrw_set, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlset); 080 081 // SHOW commands (ClickHouse supports a subset of MySQL SHOW) 082 addCmd(TBaseType.rrw_show, "columns", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlshowcolumns); 083 addCmd(TBaseType.rrw_show, "create", "database", " ", " ", " ", " ", ESqlStatementType.sstmysqlshowcreatedatabase); 084 addCmd(TBaseType.rrw_show, "create", "table", " ", " ", " ", " ", ESqlStatementType.sstmysqlshowcreatetable); 085 addCmd(TBaseType.rrw_show, "create", "view", " ", " ", " ", " ", ESqlStatementType.sstmysqlshowcreateview); 086 addCmd(TBaseType.rrw_show, "databases", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlshowdatabases); 087 addCmd(TBaseType.rrw_show, "processlist", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlshowprocesslist); 088 addCmd(TBaseType.rrw_show, "tables", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqlshowtables); 089 090 // TRUNCATE 091 addCmd(TBaseType.rrw_truncate, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqltruncate); 092 093 // UPDATE 094 addCmd(TBaseType.rrw_update, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstupdate); 095 096 // USE 097 addCmd(TBaseType.rrw_use, " ", " ", " ", " ", " ", " ", ESqlStatementType.sstmysqluse); 098 } 099 100 @Override 101 protected String getToken1Str(int token1) { 102 // Handle ClickHouse vendor-specific reserved words 103 switch (token1) { 104 case TBaseType.rrw_mysql_desc: 105 return "desc"; 106 default: 107 return null; 108 } 109 } 110 111 @Override 112 public TCustomSqlStatement issql(TSourceToken pcst, EFindSqlStateType pstate, TCustomSqlStatement psqlstatement) { 113 TCustomSqlStatement ret = null; 114 int k; 115 boolean lcisnewsql; 116 TSourceToken lcpprevsolidtoken, lcnextsolidtoken; 117 118 gnewsqlstatementtype = ESqlStatementType.sstinvalid; 119 120 if ((pcst.tokencode == TBaseType.cmtdoublehyphen) 121 || (pcst.tokencode == TBaseType.cmtslashstar) 122 || (pcst.tokencode == TBaseType.lexspace) 123 || (pcst.tokencode == TBaseType.lexnewline) 124 || (pcst.tokentype == ETokenType.ttsemicolon)) { 125 return ret; 126 } 127 128 int lcpos = pcst.posinlist; 129 TSourceTokenList lcsourcetokenlist = pcst.container; 130 TCustomSqlStatement lccurrentsqlstatement = psqlstatement; 131 132 // subquery after semicolon || at first line 133 if ((pstate == EFindSqlStateType.stnormal) && (pcst.tokentype == ETokenType.ttleftparenthesis)) { 134 k = lcsourcetokenlist.solidtokenafterpos(lcpos, TBaseType.rrw_select, 1, "("); 135 if (k > 0) { 136 ret = new TSelectSqlStatement(vendor); 137 } 138 return ret; 139 } 140 141 // cte 142 if ((pstate == EFindSqlStateType.stnormal) && (pcst.tokencode == TBaseType.rrw_with)) { 143 ret = findcte(pcst); 144 if ((ret != null)) return ret; 145 } 146 147 gnewsqlstatementtype = getStatementTypeForToken(pcst); 148 149 TSourceToken lcprevsolidtoken = lcsourcetokenlist.solidtokenbefore(lcpos); 150 151 if (pcst.tokencode == TBaseType.rrw_create) { 152 TSourceToken nextToken = lcsourcetokenlist.nextsolidtoken(lcpos, 1, false); 153 if (TBaseType.assigned(nextToken) && nextToken.toString().equalsIgnoreCase("window")) { 154 TSourceToken viewAfterWindow = lcsourcetokenlist.nextsolidtoken(nextToken.posinlist, 1, false); 155 if (TBaseType.assigned(viewAfterWindow) && viewAfterWindow.toString().equalsIgnoreCase("view")) { 156 gnewsqlstatementtype = ESqlStatementType.sstClickhouseCreateWindowView; 157 } 158 } 159 } 160 161 if (pcst.toString().equalsIgnoreCase("SYSTEM")) { 162 gnewsqlstatementtype = ESqlStatementType.sstClickhouseSystem; 163 } 164 165 if (pcst.toString().equalsIgnoreCase("DETACH")) { 166 gnewsqlstatementtype = ESqlStatementType.sstClickhouseDetach; 167 } 168 169 if (pcst.toString().equalsIgnoreCase("ATTACH")) { 170 gnewsqlstatementtype = ESqlStatementType.sstClickhouseAttach; 171 } 172 173 if (pcst.tokencode == TBaseType.rrw_kill) { 174 gnewsqlstatementtype = ESqlStatementType.sstClickhouseKill; 175 } 176 177 if (pcst.toString().equalsIgnoreCase("WATCH")) { 178 gnewsqlstatementtype = ESqlStatementType.sstClickhouseWatch; 179 } 180 181 if ((gnewsqlstatementtype == ESqlStatementType.sstinvalid) && (pcst.tokencode == TBaseType.rrw_create)) { 182 TSourceToken viewToken = pcst.container.searchToken(TBaseType.rrw_view, "", pcst, 15); 183 if (viewToken != null) { 184 gnewsqlstatementtype = ESqlStatementType.sstcreateview; 185 } 186 } 187 188 switch (gnewsqlstatementtype) { 189 case sstinvalid: { 190 ret = null; 191 break; 192 } 193 case sstselect: { 194 lcisnewsql = true; 195 196 if (pstate != EFindSqlStateType.stnormal) { 197 if (TBaseType.assigned(lcprevsolidtoken)) { 198 if (lcprevsolidtoken.tokentype == ETokenType.ttleftparenthesis) 199 lcisnewsql = false; 200 else if (lcprevsolidtoken.tokencode == TBaseType.rrw_union) 201 lcisnewsql = false; 202 else if (lcprevsolidtoken.tokencode == TBaseType.rrw_intersect) 203 lcisnewsql = false; 204 else if (lcprevsolidtoken.tokencode == TBaseType.rrw_except) 205 lcisnewsql = false; 206 else if (lcprevsolidtoken.tokencode == TBaseType.rrw_as) { 207 if (lccurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatetable) 208 lcisnewsql = false; 209 if (lccurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreateview) 210 lcisnewsql = false; 211 if (lccurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstcreatematerializedview) 212 lcisnewsql = false; 213 if (lccurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstClickhouseCreateWindowView) 214 lcisnewsql = false; 215 } 216 217 if (lcisnewsql && (lcprevsolidtoken.tokencode == TBaseType.rrw_all)) { 218 lcpprevsolidtoken = lcsourcetokenlist.solidtokenbefore(lcprevsolidtoken.posinlist); 219 if (TBaseType.assigned(lcpprevsolidtoken)) { 220 if (lcpprevsolidtoken.tokencode == TBaseType.rrw_union) 221 lcisnewsql = false; 222 } 223 } 224 } 225 226 if (TBaseType.assigned(lccurrentsqlstatement)) { 227 if (lccurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstinsert) 228 lcisnewsql = false; 229 } 230 } 231 232 if (lcisnewsql) 233 ret = new TSelectSqlStatement(vendor); 234 break; 235 } 236 case sstinsert: { 237 lcisnewsql = true; 238 if (pstate != EFindSqlStateType.stnormal) { 239 if (TBaseType.assigned(lccurrentsqlstatement)) { 240 // ClickHouse doesn't have stored procedures 241 } 242 } 243 244 if (lcisnewsql) 245 ret = new TInsertSqlStatement(vendor); 246 ret.sqlstatementtype = gnewsqlstatementtype; 247 break; 248 } 249 case sstupdate: { 250 lcisnewsql = true; 251 if (pstate != EFindSqlStateType.stnormal) { 252 lcprevsolidtoken = lcsourcetokenlist.solidtokenbefore(lcpos); 253 if (TBaseType.assigned(lcprevsolidtoken)) { 254 if (lcprevsolidtoken.tokencode == TBaseType.rrw_on) 255 lcisnewsql = false; 256 else if (lcprevsolidtoken.tokencode == TBaseType.rrw_for) 257 lcisnewsql = false; 258 } 259 260 lcnextsolidtoken = lcsourcetokenlist.nextsolidtoken(lcpos, 1, false); 261 if (TBaseType.assigned(lcnextsolidtoken)) { 262 if (lcnextsolidtoken.tokentype == ETokenType.ttleftparenthesis) { 263 k = lcsourcetokenlist.solidtokenafterpos(lcnextsolidtoken.posinlist, TBaseType.rrw_select, 1, "("); 264 if (k == 0) lcisnewsql = false; 265 } 266 } 267 } 268 269 if (lcisnewsql) { 270 ret = new TUpdateSqlStatement(vendor); 271 ret.dummytag = 1; 272 } 273 break; 274 } 275 case sstdelete: { 276 lcisnewsql = true; 277 278 if (pstate != EFindSqlStateType.stnormal) { 279 lcprevsolidtoken = lcsourcetokenlist.solidtokenbefore(lcpos); 280 if (TBaseType.assigned(lcprevsolidtoken)) { 281 if (lcprevsolidtoken.tokencode == TBaseType.rrw_on) 282 lcisnewsql = false; 283 } 284 } 285 286 if (lcisnewsql) 287 ret = new TDeleteSqlStatement(vendor); 288 break; 289 } 290 case sstcreatetable: { 291 ret = new TCreateTableSqlStatement(vendor); 292 break; 293 } 294 case sstcreateview: { 295 ret = new TCreateViewSqlStatement(vendor); 296 break; 297 } 298 case sstcreatematerializedview: { 299 ret = new TCreateMaterializedSqlStatement(vendor); 300 break; 301 } 302 case sstClickhouseCreateWindowView: { 303 ret = new TCreateViewSqlStatement(vendor); 304 ret.sqlstatementtype = ESqlStatementType.sstClickhouseCreateWindowView; 305 break; 306 } 307 case sstmysqlcreateindex: { 308 ret = new TCreateIndexSqlStatement(vendor); 309 break; 310 } 311 case sstcreatedatabase: 312 case sstmysqlcreatedatabase: { 313 ret = new TCreateDatabaseSqlStatement(vendor); 314 break; 315 } 316 case sstmysqldroptable: 317 case sstdroptable: { 318 ret = new TDropTableSqlStatement(vendor); 319 break; 320 } 321 case sstdropview: { 322 ret = new TDropViewSqlStatement(vendor); 323 break; 324 } 325 case sstdropindex: 326 case sstmysqldropindex: { 327 ret = new TDropIndexSqlStatement(vendor); 328 break; 329 } 330 case sstaltertable: { 331 ret = new TAlterTableStatement(vendor); 332 break; 333 } 334 case sstmysqlset: { 335 ret = new TSetStmt(vendor); 336 break; 337 } 338 case sstmysqlcreatefunction: { 339 ret = new TCreateFunctionStmt(vendor); 340 break; 341 } 342 case sstmysqltruncate: { 343 ret = new TTruncateStatement(vendor); 344 break; 345 } 346 case sstdescribe: { 347 ret = new TDescribeStmt(vendor); 348 break; 349 } 350 case sstExplain: { 351 ret = new TExplainPlan(vendor); 352 break; 353 } 354 case sstClickhouseSystem: { 355 ret = new TUnknownSqlStatement(vendor); 356 ret.sqlstatementtype = ESqlStatementType.sstClickhouseSystem; 357 break; 358 } 359 case sstClickhouseDetach: { 360 ret = new TUnknownSqlStatement(vendor); 361 ret.sqlstatementtype = ESqlStatementType.sstClickhouseDetach; 362 break; 363 } 364 case sstClickhouseAttach: { 365 ret = new TUnknownSqlStatement(vendor); 366 ret.sqlstatementtype = ESqlStatementType.sstClickhouseAttach; 367 break; 368 } 369 case sstClickhouseKill: { 370 ret = new TUnknownSqlStatement(vendor); 371 ret.sqlstatementtype = ESqlStatementType.sstClickhouseKill; 372 break; 373 } 374 case sstClickhouseWatch: { 375 ret = new TUnknownSqlStatement(vendor); 376 ret.sqlstatementtype = ESqlStatementType.sstClickhouseWatch; 377 break; 378 } 379 case sstmysqloptimizetable: { 380 ret = new TMySQLOptimizeTableStmt(vendor); 381 break; 382 } 383 case sstmysqlalterview: { 384 ret = new TAlterViewStatement(vendor); 385 break; 386 } 387 case sstmysqldropfunction: { 388 ret = new TDropFunctionStmt(vendor); 389 break; 390 } 391 case sstmysqlrenametable: { 392 ret = new TRenameStmt(vendor); 393 break; 394 } 395 case sstmysqluse: { 396 ret = new TUseDatabase(vendor); 397 break; 398 } 399 case sstmysqlshowcolumns: 400 case sstmysqlshowcreatedatabase: 401 case sstmysqlshowcreatetable: 402 case sstmysqlshowcreateview: 403 case sstmysqlshowdatabases: 404 case sstmysqlshowprocesslist: 405 case sstmysqlshowtables: 406 ret = new TMySQLShowStmt(vendor); 407 ret.sqlstatementtype = gnewsqlstatementtype; 408 break; 409 default: { 410 ret = new TUnknownSqlStatement(vendor); 411 ret.sqlstatementtype = gnewsqlstatementtype; 412 break; 413 } 414 } 415 416 return ret; 417 } 418}