@@ -21,10 +21,7 @@ type tableWriteMetrics struct {
2121}
2222
2323func (c * Connection ) createTableAsSelect (ctx context.Context , name , sql string , outputProps * ModelOutputProperties , beforeCreate , afterCreate string ) (* tableWriteMetrics , error ) {
24- var onClusterClause string
25- if c .config .Cluster != "" {
26- onClusterClause = "ON CLUSTER " + safeSQLName (c .config .Cluster )
27- }
24+ onClusterClause := c .onClusterClause ()
2825
2926 // Execute beforeCreate query
3027 if beforeCreate != "" {
@@ -116,14 +113,7 @@ func (c *Connection) insertTableAsSelect(ctx context.Context, name, sql string,
116113 }
117114
118115 if opts .Strategy == drivers .IncrementalStrategyPartitionOverwrite {
119- _ , onCluster , err := c .entityType (ctx , c .config .Database , name )
120- if err != nil {
121- return nil , err
122- }
123- onClusterClause := ""
124- if onCluster {
125- onClusterClause = "ON CLUSTER " + safeSQLName (c .config .Cluster )
126- }
116+ onClusterClause := c .onClusterClause ()
127117 // Get the engine info of the given table
128118 engine , err := c .getTableEngine (ctx , name )
129119 if err != nil {
@@ -210,13 +200,9 @@ func (c *Connection) insertTableAsSelect(ctx context.Context, name, sql string,
210200 }
211201
212202 if opts .Strategy == drivers .IncrementalStrategyMerge {
213- _ , onCluster , err := c .entityType (ctx , c .config .Database , name )
214- if err != nil {
215- return nil , err
216- }
217203 // get the engine info of the given table - local table for distributed tables
218204 var n string
219- if onCluster {
205+ if c . config . Cluster != "" {
220206 n = localTableName (name )
221207 } else {
222208 n = name
@@ -249,45 +235,46 @@ func (c *Connection) insertTableAsSelect(ctx context.Context, name, sql string,
249235}
250236
251237func (c * Connection ) dropTable (ctx context.Context , name string ) error {
252- typ , onCluster , err := c .entityType (ctx , c .config .Database , name )
238+ typ , err := c .entityType (ctx , c .config .Database , name )
253239 if err != nil {
254240 return err
255241 }
256- var onClusterClause string
257- if onCluster {
258- onClusterClause = "ON CLUSTER " + safeSQLName (c .config .Cluster )
259- }
242+
243+ onClusterClause := c .onClusterClause ()
244+
260245 switch typ {
261246 case "VIEW" :
262247 return c .Exec (ctx , & drivers.Statement {
263- Query : fmt .Sprintf ("DROP VIEW %s %s" , safeSQLName (name ), onClusterClause ),
248+ Query : fmt .Sprintf ("DROP VIEW IF EXISTS %s %s" , safeSQLName (name ), onClusterClause ),
264249 Priority : 100 ,
265250 })
266251 case "DICTIONARY" :
267252 // first drop the dictionary
268253 err := c .Exec (ctx , & drivers.Statement {
269- Query : fmt .Sprintf ("DROP DICTIONARY %s %s" , safeSQLName (name ), onClusterClause ),
254+ Query : fmt .Sprintf ("DROP DICTIONARY IF EXISTS %s %s" , safeSQLName (name ), onClusterClause ),
270255 Priority : 100 ,
271256 })
272257 // then drop the temp table
273258 _ = c .Exec (ctx , & drivers.Statement {
274- Query : fmt .Sprintf ("DROP TABLE %s %s" , safeSQLName (tempTableForDictionary (name )), onClusterClause ),
259+ Query : fmt .Sprintf ("DROP TABLE IF EXISTS %s %s" , safeSQLName (tempTableForDictionary (name )), onClusterClause ),
275260 Priority : 100 ,
276261 })
277262 return err
278263 case "TABLE" :
279264 // drop the main table
265+ // use IF EXISTS so drops succeed in cluster mode even for tables that don't exist on every node,
266+ // e.g. tables created before the cluster was configured or without a `_local` counterpart
280267 err := c .Exec (ctx , & drivers.Statement {
281- Query : fmt .Sprintf ("DROP TABLE %s %s" , safeSQLName (name ), onClusterClause ),
268+ Query : fmt .Sprintf ("DROP TABLE IF EXISTS %s %s" , safeSQLName (name ), onClusterClause ),
282269 Priority : 100 ,
283270 })
284271 if err != nil {
285272 return err
286273 }
287274 // then drop the local table in case of cluster
288- if onCluster && ! strings .HasSuffix (name , "_local" ) {
275+ if c . config . Cluster != "" && ! strings .HasSuffix (name , "_local" ) {
289276 return c .Exec (ctx , & drivers.Statement {
290- Query : fmt .Sprintf ("DROP TABLE %s %s" , safeSQLName (localTableName (name )), onClusterClause ),
277+ Query : fmt .Sprintf ("DROP TABLE IF EXISTS %s %s" , safeSQLName (localTableName (name )), onClusterClause ),
291278 Priority : 100 ,
292279 })
293280 }
@@ -298,22 +285,19 @@ func (c *Connection) dropTable(ctx context.Context, name string) error {
298285}
299286
300287func (c * Connection ) renameEntity (ctx context.Context , oldName , newName string ) error {
301- typ , onCluster , err := c .entityType (ctx , c .config .Database , oldName )
288+ typ , err := c .entityType (ctx , c .config .Database , oldName )
302289 if err != nil {
303290 return err
304291 }
305- var onClusterClause string
306- if onCluster {
307- onClusterClause = "ON CLUSTER " + safeSQLName (c .config .Cluster )
308- }
292+ onClusterClause := c .onClusterClause ()
309293
310294 switch typ {
311295 case "VIEW" :
312296 return c .renameView (ctx , oldName , newName , onClusterClause )
313297 case "DICTIONARY" :
314298 return c .renameTable (ctx , oldName , newName , onClusterClause )
315299 case "TABLE" :
316- if ! onCluster {
300+ if c . config . Cluster == "" {
317301 return c .renameTable (ctx , oldName , newName , onClusterClause )
318302 }
319303 // capture the full engine of the old distributed table
@@ -447,10 +431,7 @@ func (c *Connection) renameTable(ctx context.Context, oldName, newName, onCluste
447431}
448432
449433func (c * Connection ) createTable (ctx context.Context , name , sql string , outputProps * ModelOutputProperties ) error {
450- var onClusterClause string
451- if c .config .Cluster != "" {
452- onClusterClause = "ON CLUSTER " + safeSQLName (c .config .Cluster )
453- }
434+ onClusterClause := c .onClusterClause ()
454435 var create strings.Builder
455436 create .WriteString ("CREATE OR REPLACE TABLE " )
456437 if c .config .Cluster != "" {
@@ -512,7 +493,7 @@ func (c *Connection) createDistributedTable(ctx context.Context, name string, ou
512493 if c .config .Cluster == "" {
513494 return fmt .Errorf ("clickhouse: cannot create distributed table without a cluster" )
514495 }
515- onClusterClause := "ON CLUSTER " + safeSQLName ( c . config . Cluster )
496+ onClusterClause := c . onClusterClause ( )
516497
517498 var distributed strings.Builder
518499 database := "currentDatabase()"
@@ -534,10 +515,7 @@ func (c *Connection) createDistributedTable(ctx context.Context, name string, ou
534515}
535516
536517func (c * Connection ) createDictionary (ctx context.Context , name , sql string , outputProps * ModelOutputProperties ) error {
537- var onClusterClause string
538- if c .config .Cluster != "" {
539- onClusterClause = "ON CLUSTER " + safeSQLName (c .config .Cluster )
540- }
518+ onClusterClause := c .onClusterClause ()
541519 if sql == "" {
542520 if outputProps .Columns == "" {
543521 return fmt .Errorf ("clickhouse: no columns specified for dictionary %q" , name )
@@ -642,7 +620,7 @@ func (c *Connection) getTableEngine(ctx context.Context, name string) (string, e
642620 return "" , err
643621 }
644622 defer res .Close ()
645- if res .Next () {
623+ for res .Next () {
646624 if err := res .Scan (& engine ); err != nil {
647625 return "" , err
648626 }
@@ -695,9 +673,8 @@ func (c *Connection) getTablePartitions(ctx context.Context, name string) ([]str
695673}
696674
697675func (c * Connection ) replacePartition (ctx context.Context , src , dest , part string ) error {
698- var onClusterClause string
676+ onClusterClause := c . onClusterClause ()
699677 if c .config .Cluster != "" {
700- onClusterClause = "ON CLUSTER " + safeSQLName (c .config .Cluster )
701678 dest = localTableName (dest )
702679 src = localTableName (src )
703680 }
@@ -718,9 +695,8 @@ func (c *Connection) syncReplica(ctx context.Context, tableName string) error {
718695 if err != nil {
719696 return err
720697 }
721- onClusterClause := "ON CLUSTER " + safeSQLName (c .config .Cluster )
722698 return c .Exec (ctx , & drivers.Statement {
723- Query : fmt .Sprintf ("SYSTEM SYNC REPLICA %s %s.%s" , onClusterClause , safeSQLName (database ), safeSQLName (localTableName (tableName ))),
699+ Query : fmt .Sprintf ("SYSTEM SYNC REPLICA %s %s.%s" , c . onClusterClause () , safeSQLName (database ), safeSQLName (localTableName (tableName ))),
724700 Priority : 1 ,
725701 })
726702}
@@ -750,6 +726,14 @@ func (c *Connection) currentDatabase(ctx context.Context) (string, error) {
750726 return database , nil
751727}
752728
729+ // onClusterClause returns the ON CLUSTER clause for DDL statements, or an empty string if no cluster is configured.
730+ func (c * Connection ) onClusterClause () string {
731+ if c .config .Cluster == "" {
732+ return ""
733+ }
734+ return "ON CLUSTER " + safeSQLName (c .config .Cluster )
735+ }
736+
753737func isReplicatedEngine (engine string ) bool {
754738 return strings .Contains (strings .ToLower (engine ), "replicated" )
755739}
0 commit comments