github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/mysql/resource_database.go (about) 1 package mysql 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 mysqlc "github.com/ziutek/mymysql/mysql" 9 10 "github.com/hashicorp/terraform/helper/schema" 11 ) 12 13 const defaultCharacterSetKeyword = "CHARACTER SET " 14 const defaultCollateKeyword = "COLLATE " 15 16 func resourceDatabase() *schema.Resource { 17 return &schema.Resource{ 18 Create: CreateDatabase, 19 Update: UpdateDatabase, 20 Read: ReadDatabase, 21 Delete: DeleteDatabase, 22 23 Schema: map[string]*schema.Schema{ 24 "name": &schema.Schema{ 25 Type: schema.TypeString, 26 Required: true, 27 ForceNew: true, 28 }, 29 30 "default_character_set": &schema.Schema{ 31 Type: schema.TypeString, 32 Optional: true, 33 Default: "utf8", 34 }, 35 36 "default_collation": &schema.Schema{ 37 Type: schema.TypeString, 38 Optional: true, 39 Default: "utf8_general_ci", 40 }, 41 }, 42 } 43 } 44 45 func CreateDatabase(d *schema.ResourceData, meta interface{}) error { 46 conn := meta.(*providerConfiguration).Conn 47 48 stmtSQL := databaseConfigSQL("CREATE", d) 49 log.Println("Executing statement:", stmtSQL) 50 51 _, _, err := conn.Query(stmtSQL) 52 if err != nil { 53 return err 54 } 55 56 d.SetId(d.Get("name").(string)) 57 58 return nil 59 } 60 61 func UpdateDatabase(d *schema.ResourceData, meta interface{}) error { 62 conn := meta.(*providerConfiguration).Conn 63 64 stmtSQL := databaseConfigSQL("ALTER", d) 65 log.Println("Executing statement:", stmtSQL) 66 67 _, _, err := conn.Query(stmtSQL) 68 if err != nil { 69 return err 70 } 71 72 return nil 73 } 74 75 func ReadDatabase(d *schema.ResourceData, meta interface{}) error { 76 conn := meta.(*providerConfiguration).Conn 77 78 // This is kinda flimsy-feeling, since it depends on the formatting 79 // of the SHOW CREATE DATABASE output... but this data doesn't seem 80 // to be available any other way, so hopefully MySQL keeps this 81 // compatible in future releases. 82 83 name := d.Id() 84 stmtSQL := "SHOW CREATE DATABASE " + quoteIdentifier(name) 85 86 log.Println("Executing query:", stmtSQL) 87 rows, _, err := conn.Query(stmtSQL) 88 if err != nil { 89 if mysqlErr, ok := err.(*mysqlc.Error); ok { 90 if mysqlErr.Code == mysqlc.ER_BAD_DB_ERROR { 91 d.SetId("") 92 return nil 93 } 94 } 95 return err 96 } 97 98 row := rows[0] 99 createSQL := string(row[1].([]byte)) 100 101 defaultCharset := extractIdentAfter(createSQL, defaultCharacterSetKeyword) 102 defaultCollation := extractIdentAfter(createSQL, defaultCollateKeyword) 103 104 if defaultCollation == "" && defaultCharset != "" { 105 // MySQL doesn't return the collation if it's the default one for 106 // the charset, so if we don't have a collation we need to go 107 // hunt for the default. 108 stmtSQL := "SHOW COLLATION WHERE `Charset` = '%s' AND `Default` = 'Yes'" 109 rows, _, err := conn.Query(stmtSQL, defaultCharset) 110 if err != nil { 111 return fmt.Errorf("Error getting default charset: %s", err) 112 } 113 if len(rows) == 0 { 114 return fmt.Errorf("Charset %s has no default collation", defaultCharset) 115 } 116 row := rows[0] 117 defaultCollation = string(row[0].([]byte)) 118 } 119 120 d.Set("default_character_set", defaultCharset) 121 d.Set("default_collation", defaultCollation) 122 123 return nil 124 } 125 126 func DeleteDatabase(d *schema.ResourceData, meta interface{}) error { 127 conn := meta.(*providerConfiguration).Conn 128 129 name := d.Id() 130 stmtSQL := "DROP DATABASE " + quoteIdentifier(name) 131 log.Println("Executing statement:", stmtSQL) 132 133 _, _, err := conn.Query(stmtSQL) 134 if err == nil { 135 d.SetId("") 136 } 137 return err 138 } 139 140 func databaseConfigSQL(verb string, d *schema.ResourceData) string { 141 name := d.Get("name").(string) 142 defaultCharset := d.Get("default_character_set").(string) 143 defaultCollation := d.Get("default_collation").(string) 144 145 var defaultCharsetClause string 146 var defaultCollationClause string 147 148 if defaultCharset != "" { 149 defaultCharsetClause = defaultCharacterSetKeyword + quoteIdentifier(defaultCharset) 150 } 151 if defaultCollation != "" { 152 defaultCollationClause = defaultCollateKeyword + quoteIdentifier(defaultCollation) 153 } 154 155 return fmt.Sprintf( 156 "%s DATABASE %s %s %s", 157 verb, 158 quoteIdentifier(name), 159 defaultCharsetClause, 160 defaultCollationClause, 161 ) 162 } 163 164 func extractIdentAfter(sql string, keyword string) string { 165 charsetIndex := strings.Index(sql, keyword) 166 if charsetIndex != -1 { 167 charsetIndex += len(keyword) 168 remain := sql[charsetIndex:] 169 spaceIndex := strings.IndexRune(remain, ' ') 170 return remain[:spaceIndex] 171 } 172 173 return "" 174 }