Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can I get the original text of a parser node? #55441

Closed
h3n4l opened this issue Aug 15, 2024 · 4 comments · Fixed by #55520
Closed

Can I get the original text of a parser node? #55441

h3n4l opened this issue Aug 15, 2024 · 4 comments · Fixed by #55520
Assignees
Labels
component/parser severity/moderate sig/sql-infra SIG: SQL Infra type/bug The issue is confirmed as a bug.

Comments

@h3n4l
Copy link
Contributor

h3n4l commented Aug 15, 2024

package main

import (
	"fmt"

	"github.com/pingcap/tidb/pkg/parser"
	"github.com/pingcap/tidb/pkg/parser/ast"
	_ "github.com/pingcap/tidb/pkg/parser/test_driver"
)

func main() {
	statement := `
CREATE VIEW v1 AS SELECT * FROM t;
CREATE VIEW v2 AS SELECT 123123123123123;
`

	p := parser.New()

	// To support MySQL8 window function syntax.
	// See https://github.com/bytebase/bytebase/issues/175.
	p.EnableWindowFunc(true)

	nodes, _, err := p.Parse(statement, "", "")
	if err != nil {
		panic(err)
	}

	for _, node := range nodes {
		if node, ok := node.(*ast.CreateViewStmt); ok {
			viewName := node.ViewName.Name.O
			selectText := node.Select.Text()
			fmt.Printf("%s: %s\n\n\n\n", viewName, selectText)
		}
	}
}

I get the output:

v1: SELECT * FROM t;
CREATE VIEW v2 AS SELECT 123123123123123;



v2: SELECT 123123123123123;

IMO, the original text should return SELECT * FROM t; of v1.

@h3n4l h3n4l added the type/feature-request Categorizes issue or PR as related to a new feature. label Aug 15, 2024
@Defined2014
Copy link
Contributor

Try use Restore function like code below.

func TestA(t *testing.T) {
	statement := `
CREATE VIEW v1 AS SELECT * FROM t;
CREATE VIEW v2 AS SELECT 123123123123123;
`

	p := parser.New()

	// To support MySQL8 window function syntax.
	// See https://github.com/bytebase/bytebase/issues/175.
	p.EnableWindowFunc(true)

	nodes, _, err := p.Parse(statement, "", "")
	if err != nil {
		panic(err)
	}

	var sb strings.Builder
	for _, node := range nodes {
		if node, ok := node.(*ast.CreateViewStmt); ok {
			sb.Reset()
			viewName := node.ViewName.Name.O
			// selectText := node.Select.Text()
			node.Select.Restore(format.NewRestoreCtx(format.DefaultRestoreFlags, &sb))
			fmt.Printf("%s: %s\n\n\n\n", viewName, sb.String())
		}
	}
}

@Defined2014 Defined2014 added type/question The issue belongs to a question. and removed type/feature-request Categorizes issue or PR as related to a new feature. labels Aug 15, 2024
@h3n4l
Copy link
Contributor Author

h3n4l commented Aug 16, 2024

Hi @Defined2014 , thanks for your response. These are two requirements, when I need to get normalized SQL, I should use Restore, and I do. But when I need to get the original input for this statement from the input stream, I need OriginalText().

@Defined2014
Copy link
Contributor

Defined2014 commented Aug 16, 2024

Ok, I think we didn't call SetText for every nodes correctly, so maybe we need support it later.

@Defined2014 Defined2014 added component/parser type/feature-request Categorizes issue or PR as related to a new feature. and removed type/question The issue belongs to a question. labels Aug 16, 2024
@h3n4l
Copy link
Contributor Author

h3n4l commented Aug 16, 2024

Related docs:

## Background
Some new features in TiDB need all the `ast.Node` to be restorable to SQL text.
For example, we parse the `create view v as select * from t;` SQL statement to an AST,
and then expand `select` of the AST to `select test.t.col0, test.t.col1 from test.t;`.
The structure of an `ast.Node` is shown in the following picture (taking `ast.CreateUserStmt` as an example).
![create-user-stmt](./imgs/create-user-stmt.png)
We know there is a `Text()` method of `ast.Node`,
in which the parser calls the `SetText()` method during the parsing process,
and then we can call `Text()` to get the original input SQL statement.
But the `Text()` method is incomplete, and only `Text()` of root nodes can work well.
We should not use it when implementing this proposal.

@Defined2014 Defined2014 added type/bug The issue is confirmed as a bug. sig/sql-infra SIG: SQL Infra severity/moderate and removed type/feature-request Categorizes issue or PR as related to a new feature. labels Aug 20, 2024
@Defined2014 Defined2014 self-assigned this Aug 20, 2024
@ti-chi-bot ti-chi-bot bot closed this as completed in 3464dae Aug 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component/parser severity/moderate sig/sql-infra SIG: SQL Infra type/bug The issue is confirmed as a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants