diff --git a/enginetest/queries/trigger_queries.go b/enginetest/queries/trigger_queries.go index b13296c6d3..f817eac804 100644 --- a/enginetest/queries/trigger_queries.go +++ b/enginetest/queries/trigger_queries.go @@ -368,6 +368,50 @@ create trigger insert_into_a after insert on a for each row replace into c select d.x+2, 0 from d join b using (x) +where d.x = new.x`, + "insert into a (x,z) values (2,2)", + }, + Query: "select x, y from c order by 1", + Expected: []sql.Row{ + {4, 0}, + }, + }, + { + Name: "trigger insert projection group by index error", + SetUpScript: []string{ + "create table a (x int primary key, y int default 1, z int)", + "create table b (x int primary key)", + "create table c (x int primary key, y tinyint)", + "create table d (x int primary key)", + "insert into b values (1), (2)", + "insert into d values (1), (2)", + ` +create trigger insert_into_a +after insert on a +for each row replace into c +select max(d.x + new.x), 0 from d join b using (x) +where d.x = new.x`, + "insert into a (x,z) values (2,2)", + }, + Query: "select x, y from c order by 1", + Expected: []sql.Row{ + {4, 0}, + }, + }, + { + Name: "trigger insert projection window index error", + SetUpScript: []string{ + "create table a (x int primary key, y int default 1, z int)", + "create table b (x int primary key)", + "create table c (x int primary key, y tinyint)", + "create table d (x int primary key)", + "insert into b values (1), (2)", + "insert into d values (1), (2)", + ` +create trigger insert_into_a +after insert on a +for each row replace into c +select first_value(d.x + new.x) over (partition by (x) order by x), 0 from d join b using (x) where d.x = new.x`, "insert into a (x,z) values (2,2)", }, diff --git a/sql/analyzer/fix_exec_indexes.go b/sql/analyzer/fix_exec_indexes.go index 46b06a1fc1..5f6b823142 100644 --- a/sql/analyzer/fix_exec_indexes.go +++ b/sql/analyzer/fix_exec_indexes.go @@ -32,6 +32,7 @@ func assignExecIndexes(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Sc if !scope.IsEmpty() { // triggers s.triggerScope = true + s.insertSourceScope = scope.InInsertSource() s.addSchema(scope.Schema()) s = s.push() } @@ -161,7 +162,33 @@ type idxScope struct { children []sql.Node expressions []sql.Expression checks sql.CheckConstraints - triggerScope bool + + triggerScope bool + insertSourceScope bool +} + +func (s *idxScope) inTrigger() bool { + if s == nil { + return false + } + for _, ps := range s.parentScopes { + if ps.inTrigger() { + return true + } + } + return s.triggerScope +} + +func (s *idxScope) inInsertSource() bool { + if s == nil { + return false + } + for _, ps := range s.parentScopes { + if ps.inInsertSource() { + return true + } + } + return s.insertSourceScope } func (s *idxScope) addSchema(sch sql.Schema) { @@ -535,6 +562,20 @@ func (s *idxScope) visitSelf(n sql.Node) error { n.DestSch[colIdx].Default = newDef.(*sql.ColumnDefaultValue) } default: + // Group By and Window functions already account for the new/old columns present from triggers + // This means that when indexing the Projections, we should not include the trigger scope(s), which are + // within s.parentScopes. + if proj, isProj := n.(*plan.Project); isProj { + switch proj.Child.(type) { + case *plan.GroupBy, *plan.Window: + if s.inTrigger() && s.inInsertSource() { + for _, e := range proj.Expressions() { + s.expressions = append(s.expressions, fixExprToScope(e, s.childScopes...)) + } + return nil + } + } + } if ne, ok := n.(sql.Expressioner); ok { scope := append(s.parentScopes, s.childScopes...) for _, e := range ne.Expressions() { diff --git a/sql/analyzer/inserts.go b/sql/analyzer/inserts.go index f6b989ae5b..ececfdfab1 100644 --- a/sql/analyzer/inserts.go +++ b/sql/analyzer/inserts.go @@ -31,7 +31,8 @@ import ( func resolveInsertRows(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope, sel RuleSelector, qFlags *sql.QueryFlags) (sql.Node, transform.TreeIdentity, error) { if _, ok := n.(*plan.TriggerExecutor); ok { return n, transform.SameTree, nil - } else if _, ok := n.(*plan.CreateProcedure); ok { + } + if _, ok := n.(*plan.CreateProcedure); ok { return n, transform.SameTree, nil } // We capture all INSERTs along the tree, such as those inside of block statements. @@ -50,7 +51,7 @@ func resolveInsertRows(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Sc source := insert.Source // TriggerExecutor has already been analyzed - if _, ok := insert.Source.(*plan.TriggerExecutor); !ok && !insert.LiteralValueSource { + if _, isTrigExec := insert.Source.(*plan.TriggerExecutor); !isTrigExec && !insert.LiteralValueSource { // Analyze the source of the insert independently if _, ok := insert.Source.(*plan.Values); ok { scope = scope.NewScope(plan.NewProject( @@ -58,6 +59,7 @@ func resolveInsertRows(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Sc plan.NewSubqueryAlias("dummy", "", insert.Source), )) } + scope.SetInInsertSource(true) source, _, err = a.analyzeWithSelector(ctx, insert.Source, scope, SelectAllBatches, newInsertSourceSelector(sel), qFlags) if err != nil { return nil, transform.SameTree, err diff --git a/sql/plan/scope.go b/sql/plan/scope.go index 8e43c3d973..c1d7c5902a 100644 --- a/sql/plan/scope.go +++ b/sql/plan/scope.go @@ -44,20 +44,8 @@ type Scope struct { inLateralJoin bool joinSiblings []sql.Node JoinTrees []string -} -func (s *Scope) SetJoin(b bool) { - if s == nil { - return - } - s.inJoin = b -} - -func (s *Scope) SetLateralJoin(b bool) { - if s == nil { - return - } - s.inLateralJoin = b + inInsertSource bool } func (s *Scope) IsEmpty() bool { @@ -318,18 +306,37 @@ func (s *Scope) Schema() sql.Schema { return schema } -func (s *Scope) InJoin() bool { +func (s *Scope) SetJoin(b bool) { + if s == nil { + return + } + s.inJoin = b +} + +func (s *Scope) SetLateralJoin(b bool) { if s == nil { - return false + return } - return s.inJoin + s.inLateralJoin = b } -func (s *Scope) InLateralJoin() bool { +func (s *Scope) SetInInsertSource(b bool) { if s == nil { - return false + return } - return s.inLateralJoin + s.inInsertSource = b +} + +func (s *Scope) InJoin() bool { + return s != nil && s.inJoin +} + +func (s *Scope) InLateralJoin() bool { + return s != nil && s.inLateralJoin +} + +func (s *Scope) InInsertSource() bool { + return s != nil && s.inInsertSource } func (s *Scope) JoinSiblings() []sql.Node { diff --git a/sql/rowexec/show.go b/sql/rowexec/show.go index f765d0c576..1824a63481 100644 --- a/sql/rowexec/show.go +++ b/sql/rowexec/show.go @@ -76,6 +76,7 @@ func (b *BaseBuilder) buildDescribeQuery(ctx *sql.Context, n *plan.DescribeQuery var rows []sql.Row if n.Format.Plan { formatString := sql.Describe(n.Child, n.Format) + formatString = strings.Replace(formatString, "\r", "", -1) for _, l := range strings.Split(formatString, "\n") { if strings.TrimSpace(l) != "" { rows = append(rows, sql.NewRow(l))