github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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  }