github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/procedure_resolved_table.go (about) 1 // Copyright 2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 "github.com/dolthub/go-mysql-server/sql" 19 "github.com/dolthub/go-mysql-server/sql/transform" 20 ) 21 22 // ProcedureResolvedTable represents a resolved SQL Table inside of a stored procedure. These are initially resolved to 23 // verify that they exist, and are then reloaded when another statement accesses its data. Some integrators return a 24 // snapshot of a table during the analysis step as an internal optimization, which is incompatible with stored 25 // procedures as they require the latest data at each statement. 26 type ProcedureResolvedTable struct { 27 ResolvedTable *ResolvedTable 28 } 29 30 var _ sql.Node = (*ProcedureResolvedTable)(nil) 31 var _ sql.DebugStringer = (*ProcedureResolvedTable)(nil) 32 var _ sql.TableWrapper = (*ProcedureResolvedTable)(nil) 33 var _ sql.Table = (*ProcedureResolvedTable)(nil) 34 var _ sql.CollationCoercible = (*ProcedureResolvedTable)(nil) 35 36 // NewProcedureResolvedTable returns a *ProcedureResolvedTable. 37 func NewProcedureResolvedTable(rt *ResolvedTable) *ProcedureResolvedTable { 38 return &ProcedureResolvedTable{rt} 39 } 40 41 // Resolved implements the sql.Node interface. 42 func (t *ProcedureResolvedTable) Resolved() bool { 43 return t.ResolvedTable.Resolved() 44 } 45 46 func (t *ProcedureResolvedTable) IsReadOnly() bool { 47 return true 48 } 49 50 // String implements the sql.Node interface. 51 func (t *ProcedureResolvedTable) String() string { 52 return t.ResolvedTable.String() 53 } 54 55 // Schema implements the sql.Node interface. 56 func (t *ProcedureResolvedTable) Schema() sql.Schema { 57 return t.ResolvedTable.Schema() 58 } 59 60 // Collation implements the sql.Table interface. 61 func (t *ProcedureResolvedTable) Collation() sql.CollationID { 62 return t.ResolvedTable.Collation() 63 } 64 65 // Comment implements the sql.CommentedTable interface. 66 func (t *ProcedureResolvedTable) Comment() string { 67 return t.ResolvedTable.Comment() 68 } 69 70 // DebugString implements the sql.DebugStringer interface. 71 func (t *ProcedureResolvedTable) DebugString() string { 72 return sql.DebugString(t.ResolvedTable) 73 } 74 75 // Children implements the sql.Node interface. 76 func (t *ProcedureResolvedTable) Children() []sql.Node { 77 return []sql.Node{t.ResolvedTable} 78 } 79 80 // WithChildren implements the sql.Node interface. 81 func (t *ProcedureResolvedTable) WithChildren(children ...sql.Node) (sql.Node, error) { 82 if len(children) != 1 { 83 return nil, sql.ErrInvalidChildrenNumber.New(t, len(children), 1) 84 } 85 // Even though we return the *ResolvedTable in Children, we cannot assume that the given child is still 86 // *ResolvedTable. In the analyzer, there are instances where the table is buried under other nodes such as 87 // tracking nodes, so we must walk the tree and find the table. 88 nt, _, err := transform.Node(children[0], func(n sql.Node) (sql.Node, transform.TreeIdentity, error) { 89 rt, ok := children[0].(*ResolvedTable) 90 if !ok { 91 return n, transform.SameTree, nil 92 } 93 return NewProcedureResolvedTable(rt), transform.NewTree, nil 94 }) 95 return nt, err 96 } 97 98 // CheckPrivileges implements the interface sql.Node. 99 func (t *ProcedureResolvedTable) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 100 return t.ResolvedTable.CheckPrivileges(ctx, opChecker) 101 } 102 103 // CollationCoercibility implements the interface sql.CollationCoercible. 104 func (t *ProcedureResolvedTable) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 105 return t.ResolvedTable.CollationCoercibility(ctx) 106 } 107 108 // Underlying implements the sql.TableWrapper interface. 109 func (t *ProcedureResolvedTable) Underlying() sql.Table { 110 return t.ResolvedTable.Table 111 } 112 113 // Name implements the sql.Table interface. 114 func (t *ProcedureResolvedTable) Name() string { 115 return t.ResolvedTable.Name() 116 } 117 118 // Partitions implements the sql.Table interface. 119 func (t *ProcedureResolvedTable) Partitions(ctx *sql.Context) (sql.PartitionIter, error) { 120 rt, err := t.NewestTable(ctx) 121 if err != nil { 122 return nil, err 123 } 124 return rt.Partitions(ctx) 125 } 126 127 // PartitionRows implements the sql.Table interface. 128 func (t *ProcedureResolvedTable) PartitionRows(ctx *sql.Context, partition sql.Partition) (sql.RowIter, error) { 129 rt, err := t.NewestTable(ctx) 130 if err != nil { 131 return nil, err 132 } 133 return rt.PartitionRows(ctx, partition) 134 } 135 136 // NewestTable fetches the newest copy of the contained table from the database. 137 func (t *ProcedureResolvedTable) NewestTable(ctx *sql.Context) (*ResolvedTable, error) { 138 // If no database was given, such as with the "dual" table, then we return the given table as-is. 139 if t.ResolvedTable.SqlDatabase == nil { 140 return t.ResolvedTable, nil 141 } 142 143 if IsDualTable(t.ResolvedTable) { 144 return t.ResolvedTable, nil 145 } else if t.ResolvedTable.AsOf == nil { 146 tbl, ok, err := t.ResolvedTable.SqlDatabase.GetTableInsensitive(ctx, t.ResolvedTable.Table.Name()) 147 if err != nil { 148 return nil, err 149 } else if !ok { 150 return nil, sql.ErrTableNotFound.New(t.ResolvedTable.Table.Name()) 151 } 152 rt, err := t.ResolvedTable.ReplaceTable(tbl) 153 if err != nil { 154 return nil, err 155 } 156 return rt.(*ResolvedTable), nil 157 } else { 158 versionedDb, ok := t.ResolvedTable.SqlDatabase.(sql.VersionedDatabase) 159 if !ok { 160 return nil, sql.ErrAsOfNotSupported.New(t.ResolvedTable.SqlDatabase.Name()) 161 } 162 163 tbl, ok, err := versionedDb.GetTableInsensitiveAsOf(ctx, t.ResolvedTable.Table.Name(), t.ResolvedTable.AsOf) 164 if err != nil { 165 return nil, err 166 } else if !ok { 167 return nil, sql.ErrTableNotFound.New(t.ResolvedTable.Table.Name()) 168 } 169 rt, err := t.ResolvedTable.ReplaceTable(tbl) 170 if err != nil { 171 return nil, err 172 } 173 return rt.(*ResolvedTable), nil 174 } 175 }