github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/sorted/sqlite/dbschema.go (about)

     1  /*
     2  Copyright 2012 The Camlistore Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sqlite
    18  
    19  import (
    20  	"bytes"
    21  	"database/sql"
    22  	"fmt"
    23  	"log"
    24  	"os"
    25  	"os/exec"
    26  	"path/filepath"
    27  	"runtime"
    28  	"strings"
    29  )
    30  
    31  const requiredSchemaVersion = 1
    32  
    33  func SchemaVersion() int {
    34  	return requiredSchemaVersion
    35  }
    36  
    37  func SQLCreateTables() []string {
    38  	return []string{
    39  		`CREATE TABLE rows (
    40   k VARCHAR(255) NOT NULL PRIMARY KEY,
    41   v VARCHAR(255))`,
    42  
    43  		`CREATE TABLE meta (
    44   metakey VARCHAR(255) NOT NULL PRIMARY KEY,
    45   value VARCHAR(255) NOT NULL)`,
    46  	}
    47  }
    48  
    49  // IsWALCapable checks if the installed sqlite3 library can
    50  // use Write-Ahead Logging (i.e version >= 3.7.0)
    51  func IsWALCapable() bool {
    52  	// TODO(mpl): alternative to make it work on windows
    53  	cmdPath, err := exec.LookPath("pkg-config")
    54  	if err != nil {
    55  		log.Printf("Could not find pkg-config to check sqlite3 lib version: %v", err)
    56  		return false
    57  	}
    58  	var stderr bytes.Buffer
    59  	cmd := exec.Command(cmdPath, "--modversion", "sqlite3")
    60  	cmd.Stderr = &stderr
    61  	if runtime.GOOS == "darwin" && os.Getenv("PKG_CONFIG_PATH") == "" {
    62  		matches, err := filepath.Glob("/usr/local/Cellar/sqlite/*/lib/pkgconfig/sqlite3.pc")
    63  		if err == nil && len(matches) > 0 {
    64  			cmd.Env = append(os.Environ(), "PKG_CONFIG_PATH="+filepath.Dir(matches[0]))
    65  		}
    66  	}
    67  
    68  	out, err := cmd.Output()
    69  	if err != nil {
    70  		log.Printf("Could not check sqlite3 version: %v\n", stderr.String())
    71  		return false
    72  	}
    73  	version := strings.TrimRight(string(out), "\n")
    74  	return version >= "3.7.0"
    75  }
    76  
    77  // EnableWAL returns the statement to enable Write-Ahead Logging,
    78  // which improves SQLite concurrency.
    79  // Requires SQLite >= 3.7.0
    80  func EnableWAL() string {
    81  	return "PRAGMA journal_mode = WAL"
    82  }
    83  
    84  // initDB creates a new sqlite database based on the file at path.
    85  func initDB(path string) error {
    86  	db, err := sql.Open("sqlite3", path)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	defer db.Close()
    91  	for _, tableSql := range SQLCreateTables() {
    92  		if _, err := db.Exec(tableSql); err != nil {
    93  			return err
    94  		}
    95  	}
    96  	if IsWALCapable() {
    97  		if _, err := db.Exec(EnableWAL()); err != nil {
    98  			return err
    99  		}
   100  	} else {
   101  		log.Print("WARNING: An SQLite DB without Write Ahead Logging will most likely fail. See http://camlistore.org/issues/114")
   102  	}
   103  	_, err = db.Exec(fmt.Sprintf(`REPLACE INTO meta VALUES ('version', '%d')`, SchemaVersion()))
   104  	return err
   105  }