/ kvdb / sqlbase / schema.go
schema.go
 1  //go:build kvdb_postgres || (kvdb_sqlite && !(windows && (arm || 386)) && !(linux && (ppc64 || mips || mipsle || mips64)))
 2  
 3  package sqlbase
 4  
 5  import (
 6  	"fmt"
 7  	"strings"
 8  )
 9  
10  // SQLiteCmdReplacements is a one to one mapping of sqlite keywords that should
11  // be replaced by the mapped strings in any command. Note that the sqlite
12  // keywords to be replaced are case-sensitive.
13  type SQLiteCmdReplacements map[string]string
14  
15  func newKVSchemaCreationCmd(table, schema string,
16  	replacements SQLiteCmdReplacements) string {
17  
18  	var (
19  		tableInSchema = table
20  		finalCmd      string
21  	)
22  	if schema != "" {
23  		finalCmd = fmt.Sprintf(
24  			`CREATE SCHEMA IF NOT EXISTS ` + schema + `;`,
25  		)
26  
27  		tableInSchema = fmt.Sprintf("%s.%s", schema, table)
28  	}
29  
30  	// Construct the sql statements to set up a kv table in postgres. Every
31  	// row points to the bucket that it is one via its parent_id field. A
32  	// NULL parent_id means that the key belongs to the uppermost bucket in
33  	// this table. A constraint on parent_id is enforcing referential
34  	// integrity.
35  	//
36  	// Furthermore, there is a <table>_p index on parent_id that is required
37  	// for the foreign key constraint.
38  	//
39  	// Finally, there are unique indices on (parent_id, key) to prevent the
40  	// same key being present in a bucket more than once (<table>_up and
41  	// <table>_unp). In postgres, a single index wouldn't enforce the unique
42  	// constraint on rows with a NULL parent_id. Therefore, two indices are
43  	// defined.
44  	//
45  	// The replacements map can be used to replace any sqlite keywords.
46  	// Callers should note that the sqlite keywords are case-sensitive.
47  	finalCmd += fmt.Sprintf(`
48  CREATE TABLE IF NOT EXISTS ` + tableInSchema + `
49  (
50      key BLOB NOT NULL,
51      value BLOB,
52      parent_id BIGINT,
53      id INTEGER PRIMARY KEY,
54      sequence BIGINT,
55      CONSTRAINT ` + table + `_parent FOREIGN KEY (parent_id)
56          REFERENCES ` + tableInSchema + ` (id)
57          ON UPDATE NO ACTION
58          ON DELETE CASCADE
59  );
60  CREATE INDEX IF NOT EXISTS ` + table + `_p
61      ON ` + tableInSchema + ` (parent_id);
62  CREATE UNIQUE INDEX IF NOT EXISTS ` + table + `_up
63      ON ` + tableInSchema + `
64      (parent_id, key) WHERE parent_id IS NOT NULL;
65  CREATE UNIQUE INDEX IF NOT EXISTS ` + table + `_unp 
66      ON ` + tableInSchema + ` (key) WHERE parent_id IS NULL;
67  `)
68  
69  	for from, to := range replacements {
70  		finalCmd = strings.Replace(finalCmd, from, to, -1)
71  	}
72  
73  	return finalCmd
74  }