Beispiel #1
0
// AddColumn adds a column to the index.
func (idx *Index) AddColumn(name string, cardinality uint64) {
	idx.Columns = append(idx.Columns, cistring.New(name))
	if cardinality == 0 {
		cardinality = uint64(len(idx.Cardinality) + 1)
	}
	idx.Cardinality = append(idx.Cardinality, cardinality)
}
Beispiel #2
0
func resolveAutoIncrement(source *vschemapb.SrvVSchema, vschema *VSchema) error {
	for ksname, ks := range source.Keyspaces {
		ksvschema := vschema.Keyspaces[ksname]
		for tname, table := range ks.Tables {
			t := ksvschema.Tables[tname]
			if table.AutoIncrement == nil {
				continue
			}
			t.AutoIncrement = &AutoIncrement{Column: cistring.New(table.AutoIncrement.Column), ColumnVindexNum: -1}
			seq := vschema.tables[table.AutoIncrement.Sequence]
			// TODO(sougou): improve this search.
			if seq == nil {
				return fmt.Errorf("sequence %s not found for table %s", table.AutoIncrement.Sequence, tname)
			}
			t.AutoIncrement.Sequence = seq
			for i, cv := range t.ColumnVindexes {
				if t.AutoIncrement.Column.Equal(cv.Column) {
					t.AutoIncrement.ColumnVindexNum = i
					break
				}
			}
		}
	}
	return nil
}
Beispiel #3
0
func TestTableColumnString(t *testing.T) {
	c := &TableColumn{Name: cistring.New("my_column"), Type: querypb.Type_INT8}
	want := "{Name: 'my_column', Type: INT8}"
	got := fmt.Sprintf("%v", c)
	if got != want {
		t.Errorf("want: %v, got: %v", want, got)
	}
}
Beispiel #4
0
// FindColumn finds a column in the table. It returns the index if found.
// Otherwise, it returns -1.
func (ta *Table) FindColumn(name string) int {
	ciName := cistring.New(name)
	for i, col := range ta.Columns {
		if col.Name.Equal(ciName) {
			return i
		}
	}
	return -1
}
Beispiel #5
0
// FindDataColumn finds a data column in the index. It returns the index if found.
// Otherwise, it returns -1.
func (idx *Index) FindDataColumn(name string) int {
	ciName := cistring.New(name)
	for i, colName := range idx.DataColumns {
		if colName.Equal(ciName) {
			return i
		}
	}
	return -1
}
Beispiel #6
0
// AddColumn adds a column to the Table.
func (ta *Table) AddColumn(name string, columnType querypb.Type, defval sqltypes.Value, extra string) {
	index := len(ta.Columns)
	ta.Columns = append(ta.Columns, TableColumn{Name: cistring.New(name)})
	ta.Columns[index].Type = columnType
	if extra == "auto_increment" {
		ta.Columns[index].IsAuto = true
		// Ignore default value, if any
		return
	}
	if defval.IsNull() {
		return
	}
	// Schema values are trusted.
	ta.Columns[index].Default = sqltypes.MakeTrusted(ta.Columns[index].Type, defval.Raw())
}
Beispiel #7
0
// NewQuerySplitter creates a new QuerySplitter. query is the original query
// to split and splitCount is the desired number of splits. splitCount must
// be a positive int, if not it will be set to 1.
func NewQuerySplitter(
	sql string,
	bindVariables map[string]interface{},
	splitColumn string,
	splitCount int64,
	schemaInfo *SchemaInfo) *QuerySplitter {
	if splitCount < 1 {
		splitCount = 1
	}
	return &QuerySplitter{
		sql:           sql,
		bindVariables: bindVariables,
		splitCount:    splitCount,
		schemaInfo:    schemaInfo,
		splitColumn:   cistring.New(splitColumn),
	}
}
Beispiel #8
0
// NewColIdent makes a new ColIdent.
func NewColIdent(str string) ColIdent {
	return ColIdent(cistring.New(str))
}
Beispiel #9
0
// NewIndex creates a new Index.
func NewIndex(name string) *Index {
	return &Index{Name: cistring.New(name)}
}
Beispiel #10
0
func TestGetWhereClause(t *testing.T) {
	splitter := &QuerySplitter{}
	sql := "select * from test_table where count > :count"
	statement, _ := sqlparser.Parse(sql)
	splitter.sel, _ = statement.(*sqlparser.Select)
	splitter.splitColumn = cistring.New("id")
	bindVars := make(map[string]interface{})
	// no boundary case, start = end = nil, should not change the where clause
	nilValue := sqltypes.Value{}
	clause := splitter.getWhereClause(splitter.sel.Where, bindVars, nilValue, nilValue)
	want := " where count > :count"
	got := sqlparser.String(clause)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect where clause for nil ranges, got:%v, want:%v", got, want)
	}

	// Set lower bound, should add the lower bound condition to where clause
	startVal := int64(20)
	start, _ := sqltypes.BuildValue(startVal)
	bindVars = make(map[string]interface{})
	bindVars[":count"] = 300
	clause = splitter.getWhereClause(splitter.sel.Where, bindVars, start, nilValue)
	want = " where (count > :count) and (id >= :" + startBindVarName + ")"
	got = sqlparser.String(clause)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect where clause, got:%v, want:%v", got, want)
	}
	v, ok := bindVars[startBindVarName]
	if !ok {
		t.Fatalf("bind var: %s not found got: nil, want: %v", startBindVarName, startVal)
	}
	if v != startVal {
		t.Fatalf("bind var: %s not found got: %v, want: %v", startBindVarName, v, startVal)
	}
	// Set upper bound, should add the upper bound condition to where clause
	endVal := int64(40)
	end, _ := sqltypes.BuildValue(endVal)
	bindVars = make(map[string]interface{})
	clause = splitter.getWhereClause(splitter.sel.Where, bindVars, nilValue, end)
	want = " where (count > :count) and (id < :" + endBindVarName + ")"
	got = sqlparser.String(clause)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect where clause, got:%v, want:%v", got, want)
	}
	v, ok = bindVars[endBindVarName]
	if !ok {
		t.Fatalf("bind var: %s not found got: nil, want: %v", endBindVarName, endVal)
	}
	if v != endVal {
		t.Fatalf("bind var: %s not found got: %v, want: %v", endBindVarName, v, endVal)
	}

	// Set both bounds, should add two conditions to where clause
	bindVars = make(map[string]interface{})
	clause = splitter.getWhereClause(splitter.sel.Where, bindVars, start, end)
	want = fmt.Sprintf(" where (count > :count) and (id >= :%s and id < :%s)", startBindVarName, endBindVarName)
	got = sqlparser.String(clause)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect where clause, got:%v, want:%v", got, want)
	}

	// Original query with no where clause
	sql = "select * from test_table"
	statement, _ = sqlparser.Parse(sql)
	splitter.sel, _ = statement.(*sqlparser.Select)
	bindVars = make(map[string]interface{})
	// no boundary case, start = end = nil should return no where clause
	clause = splitter.getWhereClause(splitter.sel.Where, bindVars, nilValue, nilValue)
	want = ""
	got = sqlparser.String(clause)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect where clause for nil ranges, got:%v, want:%v", got, want)
	}
	bindVars = make(map[string]interface{})
	// Set both bounds, should add two conditions to where clause
	clause = splitter.getWhereClause(splitter.sel.Where, bindVars, start, end)
	want = fmt.Sprintf(" where id >= :%s and id < :%s", startBindVarName, endBindVarName)
	got = sqlparser.String(clause)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect where clause, got:%v, want:%v", got, want)
	}
	v, ok = bindVars[startBindVarName]
	if !ok {
		t.Fatalf("bind var: %s not found got: nil, want: %v", startBindVarName, startVal)
	}
	if v != startVal {
		t.Fatalf("bind var: %s not found got: %v, want: %v", startBindVarName, v, startVal)
	}
	v, ok = bindVars[endBindVarName]
	if !ok {
		t.Fatalf("bind var: %s not found got: nil, want: %v", endBindVarName, endVal)
	}
	if v != endVal {
		t.Fatalf("bind var: %s not found got: %v, want: %v", endBindVarName, v, endVal)
	}
}
Beispiel #11
0
func TestVSchemaJSON(t *testing.T) {
	lkp, _ := NewLookupHash("n2", map[string]string{
		"from":  "f",
		"table": "t",
		"to":    "2",
	})
	in := map[string]*KeyspaceSchema{
		"unsharded": {
			Keyspace: &Keyspace{
				Name: "k1",
			},
			Tables: map[string]*Table{
				"t1": {
					Name: "n1",
				},
				"t2": {
					IsSequence: true,
					Name:       "n2",
				},
			},
		},
		"sharded": {
			Keyspace: &Keyspace{
				Name:    "k2",
				Sharded: true,
			},
			Tables: map[string]*Table{
				"t3": {
					Name: "n3",
					ColumnVindexes: []*ColumnVindex{{
						Column: cistring.New("aa"),
						Type:   "vtype",
						Name:   "vname",
						Owned:  true,
						Vindex: lkp,
					}},
				},
			},
		},
	}
	out, err := json.MarshalIndent(in, "", "  ")
	if err != nil {
		t.Fatal(err)
	}
	got := string(out)
	want := `{
  "sharded": {
    "sharded": true,
    "tables": {
      "t3": {
        "name": "n3",
        "column_vindexes": [
          {
            "column": "aa",
            "type": "vtype",
            "name": "vname",
            "owned": true,
            "vindex": {
              "table": "t",
              "from": "f",
              "to": "2"
            }
          }
        ]
      }
    }
  },
  "unsharded": {
    "tables": {
      "t1": {
        "name": "n1"
      },
      "t2": {
        "is_sequence": true,
        "name": "n2"
      }
    }
  }
}`
	if got != want {
		t.Errorf("json.Marshal():\n%s, want\n%s", got, want)
	}
}
Beispiel #12
0
func TestSequence(t *testing.T) {
	good := vschemapb.SrvVSchema{
		Keyspaces: map[string]*vschemapb.Keyspace{
			"unsharded": {
				Tables: map[string]*vschemapb.Table{
					"seq": {
						Type: "sequence",
					},
				},
			},
			"sharded": {
				Sharded: true,
				Vindexes: map[string]*vschemapb.Vindex{
					"stfu1": {
						Type: "stfu",
						Params: map[string]string{
							"stfu1": "1",
						},
					},
				},
				Tables: map[string]*vschemapb.Table{
					"t1": {
						ColumnVindexes: []*vschemapb.ColumnVindex{
							{
								Column: "c1",
								Name:   "stfu1",
							},
						},
						AutoIncrement: &vschemapb.AutoIncrement{
							Column:   "c1",
							Sequence: "seq",
						},
					},
				},
			},
		},
	}
	got, err := BuildVSchema(&good)
	if err != nil {
		t.Error(err)
	}
	ksu := &Keyspace{
		Name: "unsharded",
	}
	kss := &Keyspace{
		Name:    "sharded",
		Sharded: true,
	}
	seq := &Table{
		Name:       "seq",
		Keyspace:   ksu,
		IsSequence: true,
	}
	t1 := &Table{
		Name:     "t1",
		Keyspace: kss,
		ColumnVindexes: []*ColumnVindex{
			{
				Column: cistring.New("c1"),
				Type:   "stfu",
				Name:   "stfu1",
				Vindex: &stFU{
					name: "stfu1",
					Params: map[string]string{
						"stfu1": "1",
					},
				},
			},
		},
		AutoIncrement: &AutoIncrement{
			Column:   cistring.New("c1"),
			Sequence: seq,
		},
	}
	t1.Ordered = []*ColumnVindex{
		t1.ColumnVindexes[0],
	}
	want := &VSchema{
		tables: map[string]*Table{
			"seq": seq,
			"t1":  t1,
		},
		Keyspaces: map[string]*KeyspaceSchema{
			"unsharded": {
				Keyspace: ksu,
				Tables: map[string]*Table{
					"seq": seq,
				},
			},
			"sharded": {
				Keyspace: kss,
				Tables: map[string]*Table{
					"t1": t1,
				},
			},
		},
	}
	if !reflect.DeepEqual(got, want) {
		gotjson, _ := json.Marshal(got)
		wantjson, _ := json.Marshal(want)
		t.Errorf("BuildVSchema:s\n%s, want\n%s", gotjson, wantjson)
	}
}
Beispiel #13
0
func TestShardedVSchemaNotOwned(t *testing.T) {
	good := vschemapb.SrvVSchema{
		Keyspaces: map[string]*vschemapb.Keyspace{
			"sharded": {
				Sharded: true,
				Vindexes: map[string]*vschemapb.Vindex{
					"stlu1": {
						Type:  "stlu",
						Owner: "",
					},
					"stfu1": {
						Type:  "stfu",
						Owner: "",
					},
				},
				Tables: map[string]*vschemapb.Table{
					"t1": {
						ColumnVindexes: []*vschemapb.ColumnVindex{
							{
								Column: "c1",
								Name:   "stlu1",
							}, {
								Column: "c2",
								Name:   "stfu1",
							},
						},
					},
				},
			},
		},
	}
	got, err := BuildVSchema(&good)
	if err != nil {
		t.Error(err)
	}
	ks := &Keyspace{
		Name:    "sharded",
		Sharded: true,
	}
	t1 := &Table{
		Name:     "t1",
		Keyspace: ks,
		ColumnVindexes: []*ColumnVindex{
			{
				Column: cistring.New("c1"),
				Type:   "stlu",
				Name:   "stlu1",
				Owned:  false,
				Vindex: &stLU{name: "stlu1"},
			},
			{
				Column: cistring.New("c2"),
				Type:   "stfu",
				Name:   "stfu1",
				Owned:  false,
				Vindex: &stFU{name: "stfu1"},
			},
		},
	}
	t1.Ordered = []*ColumnVindex{
		t1.ColumnVindexes[1],
		t1.ColumnVindexes[0],
	}
	want := &VSchema{
		tables: map[string]*Table{
			"t1": t1,
		},
		Keyspaces: map[string]*KeyspaceSchema{
			"sharded": {
				Keyspace: ks,
				Tables: map[string]*Table{
					"t1": t1,
				},
			},
		},
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("BuildVSchema:s\n%v, want\n%v", got, want)
	}
}
Beispiel #14
0
func TestShardedVSchemaOwned(t *testing.T) {
	good := vschemapb.SrvVSchema{
		Keyspaces: map[string]*vschemapb.Keyspace{
			"sharded": {
				Sharded: true,
				Vindexes: map[string]*vschemapb.Vindex{
					"stfu1": {
						Type: "stfu",
						Params: map[string]string{
							"stfu1": "1",
						},
						Owner: "t1",
					},
					"stln1": {
						Type:  "stln",
						Owner: "t1",
					},
				},
				Tables: map[string]*vschemapb.Table{
					"t1": {
						ColumnVindexes: []*vschemapb.ColumnVindex{
							{
								Column: "c1",
								Name:   "stfu1",
							}, {
								Column: "c2",
								Name:   "stln1",
							},
						},
					},
				},
			},
		},
	}
	got, err := BuildVSchema(&good)
	if err != nil {
		t.Error(err)
	}
	ks := &Keyspace{
		Name:    "sharded",
		Sharded: true,
	}
	t1 := &Table{
		Name:     "t1",
		Keyspace: ks,
		ColumnVindexes: []*ColumnVindex{
			{
				Column: cistring.New("c1"),
				Type:   "stfu",
				Name:   "stfu1",
				Vindex: &stFU{
					name: "stfu1",
					Params: map[string]string{
						"stfu1": "1",
					},
				},
			},
			{
				Column: cistring.New("c2"),
				Type:   "stln",
				Name:   "stln1",
				Owned:  true,
				Vindex: &stLN{name: "stln1"},
			},
		},
	}
	t1.Ordered = []*ColumnVindex{
		t1.ColumnVindexes[1],
		t1.ColumnVindexes[0],
	}
	t1.Owned = t1.ColumnVindexes[1:]
	want := &VSchema{
		tables: map[string]*Table{
			"t1": t1,
		},
		Keyspaces: map[string]*KeyspaceSchema{
			"sharded": {
				Keyspace: ks,
				Tables: map[string]*Table{
					"t1": t1,
				},
			},
		},
	}
	if !reflect.DeepEqual(got, want) {
		gotjson, _ := json.Marshal(got)
		wantjson, _ := json.Marshal(want)
		t.Errorf("BuildVSchema:s\n%s, want\n%s", gotjson, wantjson)
	}
}
Beispiel #15
0
func buildTables(source *vschemapb.SrvVSchema, vschema *VSchema) error {
	for ksname, ks := range source.Keyspaces {
		keyspace := vschema.Keyspaces[ksname].Keyspace
		vindexes := make(map[string]Vindex)
		for vname, vindexInfo := range ks.Vindexes {
			vindex, err := CreateVindex(vindexInfo.Type, vname, vindexInfo.Params)
			if err != nil {
				return err
			}
			switch vindex.(type) {
			case Unique:
			case NonUnique:
			default:
				return fmt.Errorf("vindex %s needs to be Unique or NonUnique", vname)
			}
			vindexes[vname] = vindex
		}
		for tname, table := range ks.Tables {
			t := &Table{
				Name:     tname,
				Keyspace: keyspace,
			}
			if _, ok := vschema.tables[tname]; ok {
				vschema.tables[tname] = nil
			} else {
				vschema.tables[tname] = t
			}
			vschema.Keyspaces[ksname].Tables[tname] = t
			if table.Type == "sequence" {
				t.IsSequence = true
			}
			if keyspace.Sharded && len(table.ColumnVindexes) == 0 {
				return fmt.Errorf("missing primary col vindex for table: %s", tname)
			}
			for i, ind := range table.ColumnVindexes {
				vindexInfo, ok := ks.Vindexes[ind.Name]
				if !ok {
					return fmt.Errorf("vindex %s not found for table %s", ind.Name, tname)
				}
				vindex := vindexes[ind.Name]
				owned := false
				if _, ok := vindex.(Lookup); ok && vindexInfo.Owner == tname {
					owned = true
				}
				columnVindex := &ColumnVindex{
					Column: cistring.New(ind.Column),
					Type:   vindexInfo.Type,
					Name:   ind.Name,
					Owned:  owned,
					Vindex: vindex,
				}
				if i == 0 {
					// Perform Primary vindex check.
					if _, ok := columnVindex.Vindex.(Unique); !ok {
						return fmt.Errorf("primary vindex %s is not Unique for table %s", ind.Name, tname)
					}
					if owned {
						return fmt.Errorf("primary vindex %s cannot be owned for table %s", ind.Name, tname)
					}
				}
				t.ColumnVindexes = append(t.ColumnVindexes, columnVindex)
				if owned {
					t.Owned = append(t.Owned, columnVindex)
				}
			}
			t.Ordered = colVindexSorted(t.ColumnVindexes)
		}
	}
	return nil
}