func (db *DB) GetCF(ro *ReadOptions, cf *ColumnFamilyHandle, key []byte) (*Slice, error) {
	var cErr *C.char
	var cValueLen C.size_t
	cKey := bytesToChar(key)
	cValue := C.rocksdb_get_cf(db.c, ro.c, cf.c, cKey, C.size_t(len(key)), &cValueLen, &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, errors.New(C.GoString(cErr))
	}
	return NewSlice(cValue, cValueLen), nil
}
GetCF returns the data associated with the key from the database
and column family.
package rocksdb
import "C"
import (
	"errors"
	"unsafe"
)
type DB struct {
	c    *C.rocksdb_t
	opts *Options
}
func OpenDB(path string, opts *Options) (*DB, error) {
	var cErr *C.char
	cPath := C.CString(path)
	defer C.free(unsafe.Pointer(cPath))
	db := C.rocksdb_open(opts.c, cPath, &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, errors.New(C.GoString(cErr))
	}
	return &DB{
		c:    db,
		opts: opts,
	}, nil
}
func OpenDBForReadOnly(path string, opts *Options, errorIfLogFileExist bool) (*DB, error) {
	var cErr *C.char
	cPath := C.CString(path)
	defer C.free(unsafe.Pointer(cPath))
	db := C.rocksdb_open_for_read_only(opts.c, cPath, boolToUchar(errorIfLogFileExist), &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, errors.New(C.GoString(cErr))
	}
	return &DB{
		c:    db,
		opts: opts,
	}, nil
}
func OpenDBColumnFamilies(
	path string,
	opts *Options,
	cfNames []string,
	cfOpts []*Options,
) (*DB, ColumnFamilyHandles, error) {
	numColumnFamilies := len(cfNames)
	if numColumnFamilies != len(cfOpts) {
		return nil, nil, errors.New("must provide the same number of column family names and options")
	}
	cPath := C.CString(path)
	defer C.free(unsafe.Pointer(cPath))
	cNames := make([]*C.char, numColumnFamilies)
	for i, s := range cfNames {
		cNames[i] = C.CString(s)
	}
	defer func() {
		for _, s := range cNames {
			C.free(unsafe.Pointer(s))
		}
	}()
	cOpts := make([]*C.rocksdb_options_t, numColumnFamilies)
	for i, o := range cfOpts {
		cOpts[i] = o.c
	}
	cHandles := make([]*C.rocksdb_column_family_handle_t, numColumnFamilies)
	var cErr *C.char
	db := C.rocksdb_open_column_families(
		opts.c,
		cPath,
		C.int(numColumnFamilies),
		&cNames[0],
		&cOpts[0],
		&cHandles[0],
		&cErr,
	)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, nil, errors.New(C.GoString(cErr))
	}
	cfHandles := make([]*ColumnFamilyHandle, numColumnFamilies)
	for i, c := range cHandles {
		cfHandles[i] = NewColumnFamilyHandle(c)
	}
	return &DB{
		c:    db,
		opts: opts,
	}, cfHandles, nil
}
func OpenDBForReadOnlyColumnFamilies(
	path string,
	opts *Options,
	cfNames []string,
	cfOpts []*Options,
	errorIfLogFileExist bool,
) (*DB, ColumnFamilyHandles, error) {
	numColumnFamilies := len(cfNames)
	if numColumnFamilies != len(cfOpts) {
		return nil, nil, errors.New("must provide the same number of column family names and options")
	}
	cPath := C.CString(path)
	defer C.free(unsafe.Pointer(cPath))
	cNames := make([]*C.char, numColumnFamilies)
	for i, s := range cfNames {
		cNames[i] = C.CString(s)
	}
	defer func() {
		for _, s := range cNames {
			C.free(unsafe.Pointer(s))
		}
	}()
	cOpts := make([]*C.rocksdb_options_t, numColumnFamilies)
	for i, o := range cfOpts {
		cOpts[i] = o.c
	}
	cHandles := make([]*C.rocksdb_column_family_handle_t, numColumnFamilies)
	var cErr *C.char
	db := C.rocksdb_open_for_read_only_column_families(
		opts.c,
		cPath,
		C.int(numColumnFamilies),
		&cNames[0],
		&cOpts[0],
		&cHandles[0],
		boolToUchar(errorIfLogFileExist),
		&cErr,
	)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, nil, errors.New(C.GoString(cErr))
	}
	cfHandles := make([]*ColumnFamilyHandle, numColumnFamilies)
	for i, c := range cHandles {
		cfHandles[i] = NewColumnFamilyHandle(c)
	}
	return &DB{
		c:    db,
		opts: opts,
	}, cfHandles, nil
}
func ListColumnFamilies(path string, opts *Options) ([]string, error) {
	var cErr *C.char
	var cLen C.size_t
	var cPath = C.CString(path)
	defer C.free(unsafe.Pointer(cPath))
	cNames := C.rocksdb_list_column_families(opts.c, cPath, &cLen, &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, errors.New(C.GoString(cErr))
	}
	namesLen := int(cLen)
	names := make([]string, namesLen)
	cNamesArr := (*[1 << 30]*C.char)(unsafe.Pointer(cNames))[:namesLen:namesLen]
	for i, n := range cNamesArr {
		names[i] = C.GoString(n)
	}
	C.rocksdb_list_column_families_destroy(cNames, cLen)
	return names, nil
}
func (db *DB) Close() error {
	if db.c != nil {
		C.rocksdb_close(db.c)
		db.c = nil
	}
	return nil
}
func (db *DB) NewCheckpoint() (*Checkpoint, error) {
	var cErr *C.char
	cCheckpoint := C.rocksdb_checkpoint_object_create(db.c, &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, errors.New(C.GoString(cErr))
	}
	return NewNativeCheckpoint(cCheckpoint), nil
}
func (db *DB) Put(wo *WriteOptions, key, value []byte) error {
	cKey := bytesToChar(key)
	cValue := bytesToChar(value)
	var cErr *C.char
	C.rocksdb_put(db.c, wo.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)), &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return errors.New(C.GoString(cErr))
	}
	return nil
}
func (db *DB) PutCF(wo *WriteOptions, cf *ColumnFamilyHandle, key, value []byte) error {
	cKey := bytesToChar(key)
	cValue := bytesToChar(value)
	var cErr *C.char
	C.rocksdb_put_cf(db.c, wo.c, cf.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)), &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return errors.New(C.GoString(cErr))
	}
	return nil
}
func (db *DB) Get(ro *ReadOptions, key []byte) (*Slice, error) {
	var cErr *C.char
	var cValueLen C.size_t
	cKey := bytesToChar(key)
	cValue := C.rocksdb_get(db.c, ro.c, cKey, C.size_t(len(key)), &cValueLen, &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, errors.New(C.GoString(cErr))
	}
	return NewSlice(cValue, cValueLen), nil
}
func (db *DB) GetBytes(ro *ReadOptions, key []byte) ([]byte, error) {
	var cErr *C.char
	var cValueLen C.size_t
	cKey := bytesToChar(key)
	cValue := C.rocksdb_get(db.c, ro.c, cKey, C.size_t(len(key)), &cValueLen, &cErr)
	if cErr != nil {
		defer C.free(unsafe.Pointer(cErr))
		return nil, errors.New(C.GoString(cErr))
	}
	if cValue == nil {
		return nil, nil
	}
	defer C.free(unsafe.Pointer(cValue))
	return C.GoBytes(unsafe.Pointer(cValue), C.int(cValueLen)), nil
}