175 lines
4.1 KiB
Go
175 lines
4.1 KiB
Go
|
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 ""
|
||
|
}
|