@@ -98,8 +98,8 @@ func main() {
9898 Flags : cliapp .Flags ,
9999 },
100100 {
101- Name : "delete" ,
102- Usage : "Delete specific backup" ,
101+ Name : "delete" ,
102+ Usage : "Delete specific backup" ,
103103 UsageText : "clickhouse-backup delete <local|s3> <backup_name>" ,
104104 Action : func (c * cli.Context ) error {
105105 config := getConfig (c )
@@ -223,36 +223,73 @@ func main() {
223223 }
224224}
225225
226+ func addTable (tables []Table , table Table ) []Table {
227+ for _ , t := range tables {
228+ if (t .Database == table .Database ) && (t .Name == table .Name ) {
229+ return tables
230+ }
231+ }
232+ return append (tables , table )
233+ }
234+
235+ func addBackupTable (tables []BackupTable , table BackupTable ) []BackupTable {
236+ for _ , t := range tables {
237+ if (t .Database == table .Database ) && (t .Name == table .Name ) {
238+ return tables
239+ }
240+ }
241+ return append (tables , table )
242+ }
243+
244+ func addRestoreTable (tables []RestoreTable , table RestoreTable ) []RestoreTable {
245+ for _ , t := range tables {
246+ if (t .Database == table .Database ) && (t .Table == table .Table ) {
247+ return tables
248+ }
249+ }
250+ return append (tables , table )
251+ }
252+
226253func parseTablePatternForFreeze (tables []Table , tablePattern string ) ([]Table , error ) {
227254 if tablePattern == "" {
228255 return tables , nil
229256 }
257+ tablePatterns := strings .Split (tablePattern , "," )
230258 var result []Table
231259 for _ , t := range tables {
232- if matched , _ := filepath .Match (tablePattern , fmt .Sprintf ("%s.%s" , t .Database , t .Name )); matched {
233- result = append (result , t )
260+ for _ , pattern := range tablePatterns {
261+ if matched , _ := filepath .Match (pattern , fmt .Sprintf ("%s.%s" , t .Database , t .Name )); matched {
262+ result = addTable (result , t )
263+ }
234264 }
235265 }
236266 return result , nil
237267}
238268
239269func parseTablePatternForRestoreData (tables map [string ]BackupTable , tablePattern string ) ([]BackupTable , error ) {
240- if tablePattern == "" {
241- tablePattern = "*"
270+ tablePatterns := []string {"*" }
271+ if tablePattern != "" {
272+ tablePatterns = strings .Split (tablePattern , "," )
242273 }
243274 result := []BackupTable {}
244275 for _ , t := range tables {
245- tableName := fmt .Sprintf ("%s.%s" , t .Database , t .Name )
246- if matched , _ := filepath .Match (tablePattern , tableName ); matched {
247- result = append (result , t )
276+ for _ , pattern := range tablePatterns {
277+ tableName := fmt .Sprintf ("%s.%s" , t .Database , t .Name )
278+ if matched , _ := filepath .Match (pattern , tableName ); matched {
279+ result = addBackupTable (result , t )
280+ }
248281 }
249282 }
250283 return result , nil
251284}
252285
253- func parseTablePatternForRestoreSchema (metadataPath , tablePattern string ) ([]RestoreTable , error ) {
286+ func parseTablePatternForRestoreSchema (metadataPath string , tablePattern string ) ([]RestoreTable , error ) {
254287 regularTables := []RestoreTable {}
255288 distributedTables := []RestoreTable {}
289+ tablePatterns := []string {"*" }
290+ if tablePattern != "" {
291+ tablePatterns = strings .Split (tablePattern , "," )
292+ }
256293 filepath .Walk (metadataPath , func (filePath string , info os.FileInfo , err error ) error {
257294 if ! strings .HasSuffix (filePath , ".sql" ) || ! info .Mode ().IsRegular () {
258295 return nil
@@ -268,23 +305,25 @@ func parseTablePatternForRestoreSchema(metadataPath, tablePattern string) ([]Res
268305 return nil
269306 }
270307 tableName := fmt .Sprintf ("%s.%s" , database , table )
271- if matched , _ := filepath .Match (tablePattern , tableName ); ! matched {
272- return nil
273- }
274- data , err := ioutil .ReadFile (filePath )
275- if err != nil {
276- return err
277- }
278- restoreTable := RestoreTable {
279- Database : database ,
280- Table : table ,
281- Query : strings .Replace (string (data ), "ATTACH" , "CREATE" , 1 ),
282- }
283- if strings .Contains (restoreTable .Query , "ENGINE = Distributed" ) {
284- distributedTables = append (distributedTables , restoreTable )
285- return nil
308+ for _ , p := range tablePatterns {
309+ if matched , _ := filepath .Match (p , tableName ); matched {
310+ data , err := ioutil .ReadFile (filePath )
311+ if err != nil {
312+ return err
313+ }
314+ restoreTable := RestoreTable {
315+ Database : database ,
316+ Table : table ,
317+ Query : strings .Replace (string (data ), "ATTACH" , "CREATE" , 1 ),
318+ }
319+ if strings .Contains (restoreTable .Query , "ENGINE = Distributed" ) {
320+ distributedTables = addRestoreTable (distributedTables , restoreTable )
321+ return nil
322+ }
323+ regularTables = addRestoreTable (regularTables , restoreTable )
324+ return nil
325+ }
286326 }
287- regularTables = append (regularTables , restoreTable )
288327 return nil
289328 })
290329 return append (regularTables , distributedTables ... ), nil
@@ -327,9 +366,6 @@ func restoreSchema(config Config, backupName string, tablePattern string, dryRun
327366 if dataPath == "" {
328367 return ErrUnknownClickhouseDataPath
329368 }
330- if tablePattern == "" {
331- tablePattern = "*"
332- }
333369 metadataPath := path .Join (dataPath , "backup" , backupName , "metadata" )
334370 info , err := os .Stat (metadataPath )
335371 if err != nil {
@@ -569,17 +605,38 @@ func restoreData(config Config, backupName string, tablePattern string, dryRun b
569605 }
570606 defer ch .Close ()
571607
572- allTables , err := ch .GetBackupTables (backupName )
608+ allBackupTables , err := ch .GetBackupTables (backupName )
573609 if err != nil {
574610 return err
575611 }
576- restoreTables , err := parseTablePatternForRestoreData (allTables , tablePattern )
612+ restoreTables , err := parseTablePatternForRestoreData (allBackupTables , tablePattern )
613+ if err != nil {
614+ return err
615+ }
616+ chTables , err := ch .GetTables ()
577617 if err != nil {
578618 return err
579619 }
580620 if len (restoreTables ) == 0 {
581621 return fmt .Errorf ("Backup doesn't have tables to restore" )
582622 }
623+ allTablesCreated := true
624+ for _ , restoreTable := range restoreTables {
625+ found := false
626+ for _ , chTable := range chTables {
627+ if (restoreTable .Database == chTable .Database ) && (restoreTable .Name == chTable .Name ) {
628+ found = true
629+ break
630+ }
631+ }
632+ if ! found {
633+ log .Printf ("Table '%s.%s' is not created" , restoreTable .Database , restoreTable .Name )
634+ allTablesCreated = false
635+ }
636+ }
637+ if ! allTablesCreated {
638+ return fmt .Errorf ("Run 'restore-schema' first" )
639+ }
583640 for _ , table := range restoreTables {
584641 if err := ch .CopyData (table ); err != nil {
585642 return fmt .Errorf ("can't restore '%s.%s' with %v" , table .Database , table .Name , err )
@@ -784,7 +841,6 @@ func removeBackupS3(config Config, backupName string) error {
784841 return fmt .Errorf ("backup '%s' not found on s3" , backupName )
785842}
786843
787-
788844func getConfig (ctx * cli.Context ) * Config {
789845 configPath := ctx .String ("config" )
790846 if configPath == defaultConfigPath {
0 commit comments