本文整理汇总了Golang中github.com/cockroachdb/cockroach/sql/parser.NewDString函数的典型用法代码示例。如果您正苦于以下问题:Golang NewDString函数的具体用法?Golang NewDString怎么用?Golang NewDString使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了NewDString函数的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Golang代码示例。
示例1: ShowColumns
// ShowColumns of a table.
// Privileges: None.
// Notes: postgres does not have a SHOW COLUMNS statement.
// mysql only returns columns you have privileges on.
func (p *planner) ShowColumns(n *parser.ShowColumns) (planNode, error) {
desc, err := p.getTableDesc(n.Table)
if err != nil {
return nil, err
}
if desc == nil {
return nil, sqlbase.NewUndefinedTableError(n.Table.String())
}
v := &valuesNode{
columns: []ResultColumn{
{Name: "Field", Typ: parser.TypeString},
{Name: "Type", Typ: parser.TypeString},
{Name: "Null", Typ: parser.TypeBool},
{Name: "Default", Typ: parser.TypeString},
},
}
for i, col := range desc.Columns {
defaultExpr := parser.Datum(parser.DNull)
if e := desc.Columns[i].DefaultExpr; e != nil {
defaultExpr = parser.NewDString(*e)
}
v.rows = append(v.rows, []parser.Datum{
parser.NewDString(desc.Columns[i].Name),
parser.NewDString(col.Type.SQLString()),
parser.MakeDBool(parser.DBool(desc.Columns[i].Nullable)),
defaultExpr,
})
}
return v, nil
}
示例2: SetUIData
// SetUIData is an endpoint that stores the given key/value pairs in the
// system.ui table. See GetUIData for more details on semantics.
func (s *adminServer) SetUIData(ctx context.Context, req *SetUIDataRequest) (*SetUIDataResponse, error) {
if len(req.KeyValues) == 0 {
return nil, grpc.Errorf(codes.InvalidArgument, "KeyValues cannot be empty")
}
session := sql.NewSession(sql.SessionArgs{User: s.getUser(req)}, s.server.sqlExecutor, nil)
for key, val := range req.KeyValues {
// Do an upsert of the key. We update each key in a separate transaction to
// avoid long-running transactions and possible deadlocks.
br := s.server.sqlExecutor.ExecuteStatements(ctx, session, "BEGIN;", nil)
if err := s.checkQueryResults(br.ResultList, 1); err != nil {
return nil, s.serverError(err)
}
// See if the key already exists.
resp, err := s.getUIData(session, s.getUser(req), []string{key})
if err != nil {
return nil, s.serverError(err)
}
_, alreadyExists := resp.KeyValues[key]
// INSERT or UPDATE as appropriate.
if alreadyExists {
query := "UPDATE system.ui SET value = $1, lastUpdated = NOW() WHERE key = $2; COMMIT;"
params := []parser.Datum{
parser.NewDString(string(val)), // $1
parser.NewDString(key), // $2
}
r := s.server.sqlExecutor.ExecuteStatements(ctx, session, query, params)
if err := s.checkQueryResults(r.ResultList, 2); err != nil {
return nil, s.serverError(err)
}
if a, e := r.ResultList[0].RowsAffected, 1; a != e {
return nil, s.serverErrorf("rows affected %d != expected %d", a, e)
}
} else {
query := "INSERT INTO system.ui (key, value, lastUpdated) VALUES ($1, $2, NOW()); COMMIT;"
params := []parser.Datum{
parser.NewDString(key), // $1
parser.NewDBytes(parser.DBytes(val)), // $2
}
r := s.server.sqlExecutor.ExecuteStatements(ctx, session, query, params)
if err := s.checkQueryResults(r.ResultList, 2); err != nil {
return nil, s.serverError(err)
}
if a, e := r.ResultList[0].RowsAffected, 1; a != e {
return nil, s.serverErrorf("rows affected %d != expected %d", a, e)
}
}
}
return &SetUIDataResponse{}, nil
}
示例3: ShowIndex
// ShowIndex returns all the indexes for a table.
// Privileges: Any privilege on table.
// Notes: postgres does not have a SHOW INDEXES statement.
// mysql requires some privilege for any column.
func (p *planner) ShowIndex(n *parser.ShowIndex) (planNode, error) {
tn, err := n.Table.NormalizeWithDatabaseName(p.session.Database)
if err != nil {
return nil, err
}
desc, err := p.mustGetTableDesc(tn)
if err != nil {
return nil, err
}
if err := p.anyPrivilege(desc); err != nil {
return nil, err
}
v := &valuesNode{
columns: []ResultColumn{
{Name: "Table", Typ: parser.TypeString},
{Name: "Name", Typ: parser.TypeString},
{Name: "Unique", Typ: parser.TypeBool},
{Name: "Seq", Typ: parser.TypeInt},
{Name: "Column", Typ: parser.TypeString},
{Name: "Direction", Typ: parser.TypeString},
{Name: "Storing", Typ: parser.TypeBool},
},
}
appendRow := func(index sqlbase.IndexDescriptor, colName string, sequence int,
direction string, isStored bool) {
v.rows = append(v.rows, []parser.Datum{
parser.NewDString(tn.Table()),
parser.NewDString(index.Name),
parser.MakeDBool(parser.DBool(index.Unique)),
parser.NewDInt(parser.DInt(sequence)),
parser.NewDString(colName),
parser.NewDString(direction),
parser.MakeDBool(parser.DBool(isStored)),
})
}
for _, index := range append([]sqlbase.IndexDescriptor{desc.PrimaryIndex}, desc.Indexes...) {
sequence := 1
for i, col := range index.ColumnNames {
appendRow(index, col, sequence, index.ColumnDirections[i].String(), false)
sequence++
}
for _, col := range index.StoreColumnNames {
appendRow(index, col, sequence, "N/A", true)
sequence++
}
}
return v, nil
}
示例4: ShowTables
// ShowTables returns all the tables.
// Privileges: None.
// Notes: postgres does not have a SHOW TABLES statement.
// mysql only returns tables you have privileges on.
func (p *planner) ShowTables(n *parser.ShowTables) (planNode, error) {
// TODO(pmattis): This could be implemented as:
//
// SELECT name FROM system.namespace
// WHERE parentID = (SELECT id FROM system.namespace
// WHERE parentID = 0 AND name = <database>)
name := n.Name
if name == nil {
if p.session.Database == "" {
return nil, errNoDatabase
}
name = &parser.QualifiedName{Base: parser.Name(p.session.Database)}
}
dbDesc, err := p.getDatabaseDesc(string(name.Base))
if err != nil {
return nil, err
}
if dbDesc == nil {
return nil, sqlbase.NewUndefinedDatabaseError(string(name.Base))
}
tableNames, err := p.getTableNames(dbDesc)
if err != nil {
return nil, err
}
v := &valuesNode{columns: []ResultColumn{{Name: "Table", Typ: parser.TypeString}}}
for _, name := range tableNames {
v.rows = append(v.rows, []parser.Datum{parser.NewDString(name.Table())})
}
return v, nil
}
示例5: queryNamespaceID
// queryNamespaceID queries for the ID of the namespace with the given name and
// parent ID.
func (s *adminServer) queryNamespaceID(
session *sql.Session, parentID sqlbase.ID, name string,
) (sqlbase.ID, error) {
const query = `SELECT id FROM system.namespace WHERE parentID = $1 AND name = $2`
params := parser.NewPlaceholderInfo()
params.SetValue(`1`, parser.NewDInt(parser.DInt(parentID)))
params.SetValue(`2`, parser.NewDString(name))
r := s.server.sqlExecutor.ExecuteStatements(session, query, params)
if err := s.checkQueryResults(r.ResultList, 1); err != nil {
return 0, err
}
result := r.ResultList[0]
if len(result.Rows) == 0 {
return 0, errors.Errorf("namespace %s with ParentID %d not found", name, parentID)
}
var id int64
scanner := resultScanner{}
err := scanner.ScanIndex(result.Rows[0], 0, &id)
if err != nil {
return 0, err
}
return sqlbase.ID(id), nil
}
示例6: ShowTables
// ShowTables returns all the tables.
// Privileges: None.
// Notes: postgres does not have a SHOW TABLES statement.
// mysql only returns tables you have privileges on.
func (p *planner) ShowTables(n *parser.ShowTables) (planNode, error) {
// TODO(pmattis): This could be implemented as:
//
// SELECT name FROM system.namespace
// WHERE parentID = (SELECT id FROM system.namespace
// WHERE parentID = 0 AND name = <database>)
name := p.session.Database
if n.Database != "" {
name = string(n.Database)
}
if name == "" {
return nil, errNoDatabase
}
dbDesc, err := p.mustGetDatabaseDesc(name)
if err != nil {
return nil, err
}
tableNames, err := p.getTableNames(dbDesc)
if err != nil {
return nil, err
}
v := &valuesNode{columns: []ResultColumn{{Name: "Table", Typ: parser.TypeString}}}
for _, name := range tableNames {
v.rows = append(v.rows, []parser.Datum{parser.NewDString(name.Table())})
}
return v, nil
}
示例7: ShowGrants
// ShowGrants returns grant details for the specified objects and users.
// TODO(marc): implement no targets (meaning full scan).
// Privileges: None.
// Notes: postgres does not have a SHOW GRANTS statement.
// mysql only returns the user's privileges.
func (p *planner) ShowGrants(n *parser.ShowGrants) (planNode, error) {
if n.Targets == nil {
return nil, util.Errorf("TODO(marc): implement SHOW GRANT with no targets")
}
descriptors, err := p.getDescriptorsFromTargetList(*n.Targets)
if err != nil {
return nil, err
}
objectType := "Database"
if n.Targets.Tables != nil {
objectType = "Table"
}
v := &valuesNode{
columns: []ResultColumn{
{Name: objectType, Typ: parser.TypeString},
{Name: "User", Typ: parser.TypeString},
{Name: "Privileges", Typ: parser.TypeString},
},
}
var wantedUsers map[string]struct{}
if len(n.Grantees) != 0 {
wantedUsers = make(map[string]struct{})
}
for _, u := range n.Grantees {
wantedUsers[u] = struct{}{}
}
for _, descriptor := range descriptors {
userPrivileges := descriptor.GetPrivileges().Show()
for _, userPriv := range userPrivileges {
if wantedUsers != nil {
if _, ok := wantedUsers[userPriv.User]; !ok {
continue
}
}
v.rows = append(v.rows, []parser.Datum{
parser.NewDString(descriptor.GetName()),
parser.NewDString(userPriv.User),
parser.NewDString(userPriv.Privileges),
})
}
}
return v, nil
}
示例8: golangFillQueryArguments
// golangFillQueryArguments populates the placeholder map with
// types and values from an array of Go values.
// TODO: This does not support arguments of the SQL 'Date' type, as there is not
// an equivalent type in Go's standard library. It's not currently needed by any
// of our internal tables.
func golangFillQueryArguments(pinfo *parser.PlaceholderInfo, args []interface{}) {
pinfo.Clear()
for i, arg := range args {
k := fmt.Sprint(i + 1)
if arg == nil {
pinfo.SetValue(k, parser.DNull)
continue
}
// A type switch to handle a few explicit types with special semantics:
// - Datums are passed along as is.
// - Time datatypes get special representation in the database.
var d parser.Datum
switch t := arg.(type) {
case parser.Datum:
d = t
case time.Time:
d = parser.MakeDTimestamp(t, time.Microsecond)
case time.Duration:
d = &parser.DInterval{Duration: duration.Duration{Nanos: t.Nanoseconds()}}
case *inf.Dec:
dd := &parser.DDecimal{}
dd.Set(t)
d = dd
}
if d == nil {
// Handle all types which have an underlying type that can be stored in the
// database.
// Note: if this reflection becomes a performance concern in the future,
// commonly used types could be added explicitly into the type switch above
// for a performance gain.
val := reflect.ValueOf(arg)
switch val.Kind() {
case reflect.Bool:
d = parser.MakeDBool(parser.DBool(val.Bool()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
d = parser.NewDInt(parser.DInt(val.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
d = parser.NewDInt(parser.DInt(val.Uint()))
case reflect.Float32, reflect.Float64:
d = parser.NewDFloat(parser.DFloat(val.Float()))
case reflect.String:
d = parser.NewDString(val.String())
case reflect.Slice:
// Handle byte slices.
if val.Type().Elem().Kind() == reflect.Uint8 {
d = parser.NewDBytes(parser.DBytes(val.Bytes()))
}
}
if d == nil {
panic(fmt.Sprintf("unexpected type %T", arg))
}
}
pinfo.SetValue(k, d)
}
}
示例9: Events
// Events is an endpoint that returns the latest event log entries, with the following
// optional URL parameters:
//
// type=STRING returns events with this type (e.g. "create_table")
// targetID=INT returns events for that have this targetID
func (s *adminServer) Events(ctx context.Context, req *serverpb.EventsRequest) (*serverpb.EventsResponse, error) {
args := sql.SessionArgs{User: s.getUser(req)}
session := sql.NewSession(ctx, args, s.server.sqlExecutor, nil)
// Execute the query.
q := makeSQLQuery()
q.Append("SELECT timestamp, eventType, targetID, reportingID, info, uniqueID ")
q.Append("FROM system.eventlog ")
q.Append("WHERE true ") // This simplifies the WHERE clause logic below.
if len(req.Type) > 0 {
q.Append("AND eventType = $ ", parser.NewDString(req.Type))
}
if req.TargetId > 0 {
q.Append("AND targetID = $ ", parser.NewDInt(parser.DInt(req.TargetId)))
}
q.Append("ORDER BY timestamp DESC ")
q.Append("LIMIT $", parser.NewDInt(parser.DInt(apiEventLimit)))
if len(q.Errors()) > 0 {
return nil, s.serverErrors(q.Errors())
}
r := s.server.sqlExecutor.ExecuteStatements(session, q.String(), q.QueryArguments())
if err := s.checkQueryResults(r.ResultList, 1); err != nil {
return nil, s.serverError(err)
}
// Marshal response.
var resp serverpb.EventsResponse
scanner := makeResultScanner(r.ResultList[0].Columns)
for _, row := range r.ResultList[0].Rows {
var event serverpb.EventsResponse_Event
var ts time.Time
if err := scanner.ScanIndex(row, 0, &ts); err != nil {
return nil, err
}
event.Timestamp = serverpb.EventsResponse_Event_Timestamp{Sec: ts.Unix(), Nsec: uint32(ts.Nanosecond())}
if err := scanner.ScanIndex(row, 1, &event.EventType); err != nil {
return nil, err
}
if err := scanner.ScanIndex(row, 2, &event.TargetID); err != nil {
return nil, err
}
if err := scanner.ScanIndex(row, 3, &event.ReportingID); err != nil {
return nil, err
}
if err := scanner.ScanIndex(row, 4, &event.Info); err != nil {
return nil, err
}
if err := scanner.ScanIndex(row, 5, &event.UniqueID); err != nil {
return nil, err
}
resp.Events = append(resp.Events, event)
}
return &resp, nil
}
示例10: Arg
// Arg implements the parser.Args interface.
// TODO: This does not support arguments of the SQL 'Date' type, as there is not
// an equivalent type in Go's standard library. It's not currently needed by any
// of our internal tables.
func (gp golangParameters) Arg(name string) (parser.Datum, bool) {
i, err := processPositionalArgument(name)
if err != nil {
return nil, false
}
if i < 1 || int(i) > len(gp) {
return nil, false
}
arg := gp[i-1]
if arg == nil {
return parser.DNull, true
}
// A type switch to handle a few explicit types with special semantics.
switch t := arg.(type) {
// Datums are passed along as is.
case parser.Datum:
return t, true
// Time datatypes get special representation in the database.
case time.Time:
return parser.MakeDTimestamp(t, time.Microsecond), true
case time.Duration:
return &parser.DInterval{Duration: duration.Duration{Nanos: t.Nanoseconds()}}, true
case *inf.Dec:
dd := &parser.DDecimal{}
dd.Set(t)
return dd, true
}
// Handle all types which have an underlying type that can be stored in the
// database.
// Note: if this reflection becomes a performance concern in the future,
// commonly used types could be added explicitly into the type switch above
// for a performance gain.
val := reflect.ValueOf(arg)
switch val.Kind() {
case reflect.Bool:
return parser.MakeDBool(parser.DBool(val.Bool())), true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return parser.NewDInt(parser.DInt(val.Int())), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return parser.NewDInt(parser.DInt(val.Uint())), true
case reflect.Float32, reflect.Float64:
return parser.NewDFloat(parser.DFloat(val.Float())), true
case reflect.String:
return parser.NewDString(val.String()), true
case reflect.Slice:
// Handle byte slices.
if val.Type().Elem().Kind() == reflect.Uint8 {
return parser.NewDBytes(parser.DBytes(val.Bytes())), true
}
}
panic(fmt.Sprintf("unexpected type %T", arg))
}
示例11: Show
// Show a session-local variable name.
func (p *planner) Show(n *parser.Show) (planNode, error) {
name := strings.ToUpper(n.Name)
v := &valuesNode{columns: []ResultColumn{{Name: name, Typ: parser.TypeString}}}
switch name {
case `DATABASE`:
v.rows = append(v.rows, []parser.Datum{parser.NewDString(p.session.Database)})
case `TIME ZONE`:
v.rows = append(v.rows, []parser.Datum{parser.NewDString(p.session.Location.String())})
case `SYNTAX`:
v.rows = append(v.rows, []parser.Datum{parser.NewDString(parser.Syntax(p.session.Syntax).String())})
case `DEFAULT_TRANSACTION_ISOLATION`:
level := p.session.DefaultIsolationLevel.String()
v.rows = append(v.rows, []parser.Datum{parser.NewDString(level)})
case `TRANSACTION ISOLATION LEVEL`:
v.rows = append(v.rows, []parser.Datum{parser.NewDString(p.txn.Proto.Isolation.String())})
case `TRANSACTION PRIORITY`:
v.rows = append(v.rows, []parser.Datum{parser.NewDString(p.txn.UserPriority.String())})
default:
return nil, fmt.Errorf("unknown variable: %q", name)
}
return v, nil
}
示例12: ShowColumns
// ShowColumns of a table.
// Privileges: Any privilege on table.
// Notes: postgres does not have a SHOW COLUMNS statement.
// mysql only returns columns you have privileges on.
func (p *planner) ShowColumns(n *parser.ShowColumns) (planNode, error) {
tn, err := n.Table.NormalizeWithDatabaseName(p.session.Database)
if err != nil {
return nil, err
}
desc, err := p.mustGetTableDesc(tn)
if err != nil {
return nil, err
}
if err := p.anyPrivilege(desc); err != nil {
return nil, err
}
v := &valuesNode{
columns: []ResultColumn{
{Name: "Field", Typ: parser.TypeString},
{Name: "Type", Typ: parser.TypeString},
{Name: "Null", Typ: parser.TypeBool},
{Name: "Default", Typ: parser.TypeString},
},
}
for i, col := range desc.Columns {
defaultExpr := parser.DNull
if e := desc.Columns[i].DefaultExpr; e != nil {
defaultExpr = parser.NewDString(*e)
}
v.rows = append(v.rows, []parser.Datum{
parser.NewDString(desc.Columns[i].Name),
parser.NewDString(col.Type.SQLString()),
parser.MakeDBool(parser.DBool(desc.Columns[i].Nullable)),
defaultExpr,
})
}
return v, nil
}
示例13: ShowDatabases
// ShowDatabases returns all the databases.
// Privileges: None.
// Notes: postgres does not have a "show databases"
// mysql has a "SHOW DATABASES" permission, but we have no system-level permissions.
func (p *planner) ShowDatabases(n *parser.ShowDatabases) (planNode, error) {
// TODO(pmattis): This could be implemented as:
//
// SELECT id FROM system.namespace WHERE parentID = 0
prefix := sqlbase.MakeNameMetadataKey(keys.RootNamespaceID, "")
sr, err := p.txn.Scan(prefix, prefix.PrefixEnd(), 0)
if err != nil {
return nil, err
}
v := &valuesNode{columns: []ResultColumn{{Name: "Database", Typ: parser.TypeString}}}
for db := range virtualSchemaMap {
v.rows = append(v.rows, []parser.Datum{parser.NewDString(db)})
}
for _, row := range sr {
_, name, err := encoding.DecodeUnsafeStringAscending(
bytes.TrimPrefix(row.Key, prefix), nil)
if err != nil {
return nil, err
}
v.rows = append(v.rows, []parser.Datum{parser.NewDString(name)})
}
return v, nil
}
示例14: getUIData
// getUIData returns the values and timestamps for the given UI keys. Keys
// that are not found will not be returned.
func (s *adminServer) getUIData(session *sql.Session, user string, keys []string) (*serverpb.GetUIDataResponse, error) {
if len(keys) == 0 {
return &serverpb.GetUIDataResponse{}, nil
}
// Query database.
query := makeSQLQuery()
query.Append("SELECT key, value, lastUpdated FROM system.ui WHERE key IN (")
for i, key := range keys {
if i != 0 {
query.Append(",")
}
query.Append("$", parser.NewDString(key))
}
query.Append(");")
if err := query.Errors(); err != nil {
return nil, s.serverErrorf("error constructing query: %v", err)
}
r := s.server.sqlExecutor.ExecuteStatements(context.Background(),
session, query.String(), query.QueryArguments())
if err := s.checkQueryResults(r.ResultList, 1); err != nil {
return nil, s.serverError(err)
}
// Marshal results.
resp := serverpb.GetUIDataResponse{KeyValues: make(map[string]serverpb.GetUIDataResponse_Value)}
for _, row := range r.ResultList[0].Rows {
dKey, ok := row.Values[0].(*parser.DString)
if !ok {
return nil, s.serverErrorf("unexpected type for UI key: %T", row.Values[0])
}
dValue, ok := row.Values[1].(*parser.DBytes)
if !ok {
return nil, s.serverErrorf("unexpected type for UI value: %T", row.Values[1])
}
dLastUpdated, ok := row.Values[2].(*parser.DTimestamp)
if !ok {
return nil, s.serverErrorf("unexpected type for UI lastUpdated: %T", row.Values[2])
}
resp.KeyValues[string(*dKey)] = serverpb.GetUIDataResponse_Value{
Value: []byte(*dValue),
LastUpdated: serverpb.GetUIDataResponse_Timestamp{Sec: dLastUpdated.Unix(), Nsec: uint32(dLastUpdated.Nanosecond())},
}
}
return &resp, nil
}
示例15: RandDatum
// RandDatum generates a random Datum of the given type.
// If null is true, the datum can be DNull.
func RandDatum(rng *rand.Rand, typ ColumnType_Kind, null bool) parser.Datum {
if null && rng.Intn(10) == 0 {
return parser.DNull
}
switch typ {
case ColumnType_BOOL:
return parser.MakeDBool(rng.Intn(2) == 1)
case ColumnType_INT:
return parser.NewDInt(parser.DInt(rng.Int63()))
case ColumnType_FLOAT:
return parser.NewDFloat(parser.DFloat(rng.NormFloat64()))
case ColumnType_DECIMAL:
d := &parser.DDecimal{}
d.Dec.SetScale(inf.Scale(rng.Intn(40) - 20))
d.Dec.SetUnscaled(rng.Int63())
return d
case ColumnType_DATE:
return parser.NewDDate(parser.DDate(rng.Intn(10000)))
case ColumnType_TIMESTAMP:
return &parser.DTimestamp{Time: time.Unix(rng.Int63n(1000000), rng.Int63n(1000000))}
case ColumnType_INTERVAL:
return &parser.DInterval{Duration: duration.Duration{Months: rng.Int63n(1000),
Days: rng.Int63n(1000),
Nanos: rng.Int63n(1000000),
}}
case ColumnType_STRING:
// Generate a random ASCII string.
p := make([]byte, rng.Intn(10))
for i := range p {
p[i] = byte(1 + rng.Intn(127))
}
return parser.NewDString(string(p))
case ColumnType_BYTES:
p := make([]byte, rng.Intn(10))
_, _ = rng.Read(p)
return parser.NewDBytes(parser.DBytes(p))
case ColumnType_TIMESTAMPTZ:
return &parser.DTimestampTZ{Time: time.Unix(rng.Int63n(1000000), rng.Int63n(1000000))}
default:
panic(fmt.Sprintf("invalid type %s", typ))
}
}