terraform/builtin/providers/mysql/resource_database.go

175 lines
4.1 KiB
Go
Raw Normal View History

package mysql
import (
"fmt"
"log"
"strings"
mysqlc "github.com/ziutek/mymysql/mysql"
"github.com/hashicorp/terraform/helper/schema"
)
const defaultCharacterSetKeyword = "CHARACTER SET "
const defaultCollateKeyword = "COLLATE "
func resourceDatabase() *schema.Resource {
return &schema.Resource{
Create: CreateDatabase,
Update: UpdateDatabase,
Read: ReadDatabase,
Delete: DeleteDatabase,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"default_character_set": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "utf8",
},
"default_collation": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "utf8_general_ci",
},
},
}
}
func CreateDatabase(d *schema.ResourceData, meta interface{}) error {
conn := meta.(mysqlc.Conn)
stmtSQL := databaseConfigSQL("CREATE", d)
log.Println("Executing statement:", stmtSQL)
_, _, err := conn.Query(stmtSQL)
if err != nil {
return err
}
d.SetId(d.Get("name").(string))
return nil
}
func UpdateDatabase(d *schema.ResourceData, meta interface{}) error {
conn := meta.(mysqlc.Conn)
stmtSQL := databaseConfigSQL("ALTER", d)
log.Println("Executing statement:", stmtSQL)
_, _, err := conn.Query(stmtSQL)
if err != nil {
return err
}
return nil
}
func ReadDatabase(d *schema.ResourceData, meta interface{}) error {
conn := meta.(mysqlc.Conn)
// This is kinda flimsy-feeling, since it depends on the formatting
// of the SHOW CREATE DATABASE output... but this data doesn't seem
// to be available any other way, so hopefully MySQL keeps this
// compatible in future releases.
name := d.Id()
stmtSQL := "SHOW CREATE DATABASE " + quoteIdentifier(name)
log.Println("Executing query:", stmtSQL)
rows, _, err := conn.Query(stmtSQL)
if err != nil {
if mysqlErr, ok := err.(*mysqlc.Error); ok {
if mysqlErr.Code == mysqlc.ER_BAD_DB_ERROR {
d.SetId("")
return nil
}
}
return err
}
row := rows[0]
createSQL := string(row[1].([]byte))
defaultCharset := extractIdentAfter(createSQL, defaultCharacterSetKeyword)
defaultCollation := extractIdentAfter(createSQL, defaultCollateKeyword)
if defaultCollation == "" && defaultCharset != "" {
// MySQL doesn't return the collation if it's the default one for
// the charset, so if we don't have a collation we need to go
// hunt for the default.
stmtSQL := "SHOW COLLATION WHERE `Charset` = '%s' AND `Default` = 'Yes'"
rows, _, err := conn.Query(stmtSQL, defaultCharset)
if err != nil {
return fmt.Errorf("Error getting default charset: %s", err)
}
if len(rows) == 0 {
return fmt.Errorf("Charset %s has no default collation", defaultCharset)
}
row := rows[0]
defaultCollation = string(row[0].([]byte))
}
d.Set("default_character_set", defaultCharset)
d.Set("default_collation", defaultCollation)
return nil
}
func DeleteDatabase(d *schema.ResourceData, meta interface{}) error {
conn := meta.(mysqlc.Conn)
name := d.Id()
stmtSQL := "DROP DATABASE " + quoteIdentifier(name)
log.Println("Executing statement:", stmtSQL)
_, _, err := conn.Query(stmtSQL)
if err == nil {
d.SetId("")
}
return err
}
func databaseConfigSQL(verb string, d *schema.ResourceData) string {
name := d.Get("name").(string)
defaultCharset := d.Get("default_character_set").(string)
defaultCollation := d.Get("default_collation").(string)
var defaultCharsetClause string
var defaultCollationClause string
if defaultCharset != "" {
defaultCharsetClause = defaultCharacterSetKeyword + quoteIdentifier(defaultCharset)
}
if defaultCollation != "" {
defaultCollationClause = defaultCollateKeyword + quoteIdentifier(defaultCollation)
}
return fmt.Sprintf(
"%s DATABASE %s %s %s",
verb,
quoteIdentifier(name),
defaultCharsetClause,
defaultCollationClause,
)
}
func extractIdentAfter(sql string, keyword string) string {
charsetIndex := strings.Index(sql, keyword)
if charsetIndex != -1 {
charsetIndex += len(keyword)
remain := sql[charsetIndex:]
spaceIndex := strings.IndexRune(remain, ' ')
return remain[:spaceIndex]
}
return ""
}