code: func newKVDB(cfg jsonconfig.Obj) (sorted.KeyValue, error) {
  	var (
  		user     = cfg.RequiredString("user")
  		database = cfg.RequiredString("database")
  		host     = cfg.OptionalString("host", "")
  		password = cfg.OptionalString("password", "")
  	)
  	if err := cfg.Validate(); err != nil {
  		return nil, err
  	}
  	if !validDatabaseName(database) {
  		return nil, fmt.Errorf("%q looks like an invalid database name", database)
  	}
  	var err error
  	if host != "" {
  		host, err = maybeRemapCloudSQL(host)
  		if err != nil {
  			return nil, err
  		}
  		if !strings.Contains(host, ":") {
  			host += ":3306"
  		}
  		host = "tcp(" + host + ")"
  	}
  	// The DSN does NOT have a database name in it so it's
  	// cacheable and can be shared between different queues & the
  	// index, all sharing the same database server, cutting down
  	// number of TCP connections required. We add the database
  	// name in queries instead.
  	dsn := fmt.Sprintf("%s:%s@%s/", user, password, host)
  
  	db, err := openOrCachedDB(dsn)
  	if err != nil {
  		return nil, err
  	}
  
  	if err := CreateDB(db, database); err != nil {
  		return nil, err
  	}
  	return &keyValue{
  		database: database,
  		dsn:      dsn,
  		db:       db,
  		KeyValue: &sqlkv.KeyValue{
  			DB:          db,
  			TablePrefix: database + ".",
  			Gate:        syncutil.NewGate(20), // arbitrary limit. TODO: configurable, automatically-learned?
  		},
  	}, nil
  }
docs: // newKVDB returns an unusable KeyValue, with a database, but no tables yet. It
  // should be followed by Wipe or finalize.