Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package rqlite for openSUSE:Factory checked in at 2025-06-10 09:04:23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rqlite (Old) and /work/SRC/openSUSE:Factory/.rqlite.new.19631 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rqlite" Tue Jun 10 09:04:23 2025 rev:17 rq:1283869 version:8.37.4 Changes: -------- --- /work/SRC/openSUSE:Factory/rqlite/rqlite.changes 2025-06-03 17:53:06.724541925 +0200 +++ /work/SRC/openSUSE:Factory/.rqlite.new.19631/rqlite.changes 2025-06-10 09:07:50.749785743 +0200 @@ -1,0 +2,12 @@ +Sat Jun 7 17:02:14 UTC 2025 - Andreas Stieger <andreas.stie...@gmx.de> + +- Update to version 8.37.4: + * Upgrade SQL parser + +------------------------------------------------------------------- +Sat Jun 7 07:24:23 UTC 2025 - Andreas Stieger <andreas.stie...@gmx.de> + +- Update to version 8.37.3: + * Upgrade SQL parser + +------------------------------------------------------------------- Old: ---- rqlite-8.37.2.tar.xz New: ---- rqlite-8.37.4.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rqlite.spec ++++++ --- /var/tmp/diff_new_pack.oRRubM/_old 2025-06-10 09:07:52.489857671 +0200 +++ /var/tmp/diff_new_pack.oRRubM/_new 2025-06-10 09:07:52.513858664 +0200 @@ -17,7 +17,7 @@ Name: rqlite -Version: 8.37.2 +Version: 8.37.4 Release: 0 Summary: Distributed relational database built on SQLite License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.oRRubM/_old 2025-06-10 09:07:52.873873545 +0200 +++ /var/tmp/diff_new_pack.oRRubM/_new 2025-06-10 09:07:52.929875860 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/rqlite/rqlite.git</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v8.37.2</param> + <param name="revision">v8.37.4</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.oRRubM/_old 2025-06-10 09:07:53.125883963 +0200 +++ /var/tmp/diff_new_pack.oRRubM/_new 2025-06-10 09:07:53.157885285 +0200 @@ -1,7 +1,7 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/rqlite/rqlite.git</param> - <param name="changesrevision">5bc71b5eddecce7a4d542dbc022a0e9bcbda7aab</param> + <param name="changesrevision">4870c35c694f3173b83c45a275d7a943c8187535</param> </service> </servicedata> (No newline at EOF) ++++++ rqlite-8.37.2.tar.xz -> rqlite-8.37.4.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rqlite-8.37.2/CHANGELOG.md new/rqlite-8.37.4/CHANGELOG.md --- old/rqlite-8.37.2/CHANGELOG.md 2025-05-30 21:14:32.000000000 +0200 +++ new/rqlite-8.37.4/CHANGELOG.md 2025-06-07 17:38:12.000000000 +0200 @@ -1,3 +1,11 @@ +## v8.37.4 (Jun 7th 2025) +### Implementation changes and bug fixes +- [PR #2098](https://github.com/rqlite/rqlite/pull/2098): Upgrade SQL parser. + +## v8.37.3 (Jun 6th 2025) +### Implementation changes and bug fixes +- [PR #2097](https://github.com/rqlite/rqlite/pull/2097): Upgrade SQL parser. + ## v8.37.2 (May 30th 2025) ### Implementation changes and bug fixes - [PR #2092](https://github.com/rqlite/rqlite/pull/2092): Update Go module dependencies, Go version to 1.23.8, and toolchain to go1.23.9. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rqlite-8.37.2/go.mod new/rqlite-8.37.4/go.mod --- old/rqlite-8.37.2/go.mod 2025-05-30 21:14:32.000000000 +0200 +++ new/rqlite-8.37.4/go.mod 2025-06-07 17:38:12.000000000 +0200 @@ -18,7 +18,7 @@ github.com/rqlite/go-sqlite3 v1.38.0 github.com/rqlite/raft-boltdb/v2 v2.0.0-20230523104317-c08e70f4de48 github.com/rqlite/rqlite-disco-clients v0.0.0-20250205044118-8ada2b350099 - github.com/rqlite/sql v0.0.0-20250530185618-c2b588be35aa + github.com/rqlite/sql v0.0.0-20250607152030-b0dd329faf9b go.etcd.io/bbolt v1.4.0 golang.org/x/net v0.40.0 google.golang.org/protobuf v1.36.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rqlite-8.37.2/go.sum new/rqlite-8.37.4/go.sum --- old/rqlite-8.37.2/go.sum 2025-05-30 21:14:32.000000000 +0200 +++ new/rqlite-8.37.4/go.sum 2025-06-07 17:38:12.000000000 +0200 @@ -235,8 +235,8 @@ github.com/rqlite/raft-boltdb/v2 v2.0.0-20230523104317-c08e70f4de48/go.mod h1:CRnsxgy5G8fAf5J+AM0yrsSdxXHKkIYOaq2sm+Q4DYc= github.com/rqlite/rqlite-disco-clients v0.0.0-20250205044118-8ada2b350099 h1:5cqkVLdl6sGJSY3kiF2dqaA3bD+8OS5FUdZqO0BxXLU= github.com/rqlite/rqlite-disco-clients v0.0.0-20250205044118-8ada2b350099/go.mod h1:6SVI8KegsW9Fyu2UQ+uvw0JI5CAILRYRyiQ/OFSJPrs= -github.com/rqlite/sql v0.0.0-20250530185618-c2b588be35aa h1:EL+V1KDf6eVWJecvwvuUFPPo2tikHnw7QV5XTnw2NPQ= -github.com/rqlite/sql v0.0.0-20250530185618-c2b588be35aa/go.mod h1:ib9zVtNgRKiGuoMyUqqL5aNpk+r+++YlyiVIkclVqPg= +github.com/rqlite/sql v0.0.0-20250607152030-b0dd329faf9b h1:usSxlq+oR5Y8HZ6DTj04wLjc/17MFxYcslhFGHS41Lg= +github.com/rqlite/sql v0.0.0-20250607152030-b0dd329faf9b/go.mod h1:ib9zVtNgRKiGuoMyUqqL5aNpk+r+++YlyiVIkclVqPg= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= ++++++ vendor.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/rqlite/sql/README.md new/vendor/github.com/rqlite/sql/README.md --- old/vendor/github.com/rqlite/sql/README.md 2025-05-30 21:14:32.000000000 +0200 +++ new/vendor/github.com/rqlite/sql/README.md 2025-06-07 17:38:12.000000000 +0200 @@ -1,7 +1,7 @@ sql === -[](https://circleci.com/gh/rqlite/sql/tree/master) +[](https://app.circleci.com/pipelines/github/rqlite/sql) This repository holds a pure Go SQL parser based on the [SQLite](https://sqlite.org/) SQL definition. It implements nearly all features of the language except `ATTACH`, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/rqlite/sql/ast.go new/vendor/github.com/rqlite/sql/ast.go --- old/vendor/github.com/rqlite/sql/ast.go 2025-05-30 21:14:32.000000000 +0200 +++ new/vendor/github.com/rqlite/sql/ast.go 2025-06-07 17:38:12.000000000 +0200 @@ -11,104 +11,110 @@ fmt.Stringer } -func (*AlterTableStatement) node() {} -func (*AnalyzeStatement) node() {} -func (*ReindexStatement) node() {} -func (*Assignment) node() {} -func (*BeginStatement) node() {} -func (*BinaryExpr) node() {} -func (*BindExpr) node() {} -func (*BlobLit) node() {} -func (*BoolLit) node() {} -func (*Call) node() {} -func (*CaseBlock) node() {} -func (*CaseExpr) node() {} -func (*CastExpr) node() {} -func (*CheckConstraint) node() {} -func (*CollateConstraint) node() {} -func (*ColumnDefinition) node() {} -func (*CommitStatement) node() {} -func (*CreateIndexStatement) node() {} -func (*CreateTableStatement) node() {} -func (*CreateTriggerStatement) node() {} -func (*CreateViewStatement) node() {} -func (*DefaultConstraint) node() {} -func (*DeleteStatement) node() {} -func (*DropIndexStatement) node() {} -func (*DropTableStatement) node() {} -func (*DropTriggerStatement) node() {} -func (*DropViewStatement) node() {} -func (*Exists) node() {} -func (*ExplainStatement) node() {} -func (*ExprList) node() {} -func (*FilterClause) node() {} -func (*ForeignKeyArg) node() {} -func (*ForeignKeyConstraint) node() {} -func (*FrameSpec) node() {} -func (*GeneratedConstraint) node() {} -func (*Ident) node() {} -func (*IndexedColumn) node() {} -func (*InsertStatement) node() {} -func (*JoinClause) node() {} -func (*JoinOperator) node() {} -func (*NotNullConstraint) node() {} -func (*NullLit) node() {} -func (*NumberLit) node() {} -func (*OnConstraint) node() {} -func (*OrderingTerm) node() {} -func (*OverClause) node() {} -func (*ParenExpr) node() {} -func (*ParenSource) node() {} -func (*PrimaryKeyConstraint) node() {} -func (*QualifiedRef) node() {} -func (*QualifiedTableName) node() {} -func (*QualifiedTableFunctionName) node() {} -func (*Raise) node() {} -func (*Range) node() {} -func (*ReleaseStatement) node() {} -func (*ResultColumn) node() {} -func (*ReturningClause) node() {} -func (*RollbackStatement) node() {} -func (*SavepointStatement) node() {} -func (*SelectStatement) node() {} -func (*StringLit) node() {} -func (*TimestampLit) node() {} -func (*Type) node() {} -func (*UnaryExpr) node() {} -func (*UniqueConstraint) node() {} -func (*UpdateStatement) node() {} -func (*UpsertClause) node() {} -func (*UsingConstraint) node() {} -func (*Window) node() {} -func (*WindowDefinition) node() {} -func (*WithClause) node() {} +func (*AlterTableStatement) node() {} +func (*AnalyzeStatement) node() {} +func (*Assignment) node() {} +func (*BeginStatement) node() {} +func (*BinaryExpr) node() {} +func (*BindExpr) node() {} +func (*BlobLit) node() {} +func (*BoolLit) node() {} +func (*Call) node() {} +func (*CaseBlock) node() {} +func (*CaseExpr) node() {} +func (*CastExpr) node() {} +func (*CheckConstraint) node() {} +func (*CollateConstraint) node() {} +func (*ColumnDefinition) node() {} +func (*CommitStatement) node() {} +func (*CreateIndexStatement) node() {} +func (*CreateTableStatement) node() {} +func (*CreateTriggerStatement) node() {} +func (*CreateViewStatement) node() {} +func (*CreateVirtualTableStatement) node() {} +func (*DefaultConstraint) node() {} +func (*DeleteStatement) node() {} +func (*DropIndexStatement) node() {} +func (*DropTableStatement) node() {} +func (*DropTriggerStatement) node() {} +func (*DropViewStatement) node() {} +func (*Exists) node() {} +func (*ExplainStatement) node() {} +func (*ExprList) node() {} +func (*FilterClause) node() {} +func (*ForeignKeyArg) node() {} +func (*ForeignKeyConstraint) node() {} +func (*FrameSpec) node() {} +func (*GeneratedConstraint) node() {} +func (*Ident) node() {} +func (*IndexedColumn) node() {} +func (*InsertStatement) node() {} +func (*JoinClause) node() {} +func (*JoinOperator) node() {} +func (*ModuleArgument) node() {} +func (*NotNullConstraint) node() {} +func (*Null) node() {} +func (*NullLit) node() {} +func (*NumberLit) node() {} +func (*OnConstraint) node() {} +func (*OrderingTerm) node() {} +func (*OverClause) node() {} +func (*ParenExpr) node() {} +func (*ParenSource) node() {} +func (*PragmaStatement) node() {} +func (*PrimaryKeyConstraint) node() {} +func (*QualifiedRef) node() {} +func (*QualifiedTableName) node() {} +func (*QualifiedTableFunctionName) node() {} +func (*Raise) node() {} +func (*Range) node() {} +func (*ReindexStatement) node() {} +func (*ReleaseStatement) node() {} +func (*ResultColumn) node() {} +func (*ReturningClause) node() {} +func (*RollbackStatement) node() {} +func (*SavepointStatement) node() {} +func (*SelectStatement) node() {} +func (*StringLit) node() {} +func (*TimestampLit) node() {} +func (*Type) node() {} +func (*UnaryExpr) node() {} +func (*UniqueConstraint) node() {} +func (*UpdateStatement) node() {} +func (*UpsertClause) node() {} +func (*UsingConstraint) node() {} +func (*Window) node() {} +func (*WindowDefinition) node() {} +func (*WithClause) node() {} type Statement interface { Node stmt() } -func (*AlterTableStatement) stmt() {} -func (*AnalyzeStatement) stmt() {} -func (*ReindexStatement) stmt() {} -func (*BeginStatement) stmt() {} -func (*CommitStatement) stmt() {} -func (*CreateIndexStatement) stmt() {} -func (*CreateTableStatement) stmt() {} -func (*CreateTriggerStatement) stmt() {} -func (*CreateViewStatement) stmt() {} -func (*DeleteStatement) stmt() {} -func (*DropIndexStatement) stmt() {} -func (*DropTableStatement) stmt() {} -func (*DropTriggerStatement) stmt() {} -func (*DropViewStatement) stmt() {} -func (*ExplainStatement) stmt() {} -func (*InsertStatement) stmt() {} -func (*ReleaseStatement) stmt() {} -func (*RollbackStatement) stmt() {} -func (*SavepointStatement) stmt() {} -func (*SelectStatement) stmt() {} -func (*UpdateStatement) stmt() {} +func (*AlterTableStatement) stmt() {} +func (*AnalyzeStatement) stmt() {} +func (*BeginStatement) stmt() {} +func (*CommitStatement) stmt() {} +func (*CreateIndexStatement) stmt() {} +func (*CreateTableStatement) stmt() {} +func (*CreateTriggerStatement) stmt() {} +func (*CreateViewStatement) stmt() {} +func (*CreateVirtualTableStatement) stmt() {} +func (*DeleteStatement) stmt() {} +func (*DropIndexStatement) stmt() {} +func (*DropTableStatement) stmt() {} +func (*DropTriggerStatement) stmt() {} +func (*DropViewStatement) stmt() {} +func (*ExplainStatement) stmt() {} +func (*InsertStatement) stmt() {} +func (*PragmaStatement) stmt() {} +func (*ReindexStatement) stmt() {} +func (*ReleaseStatement) stmt() {} +func (*RollbackStatement) stmt() {} +func (*SavepointStatement) stmt() {} +func (*SelectStatement) stmt() {} +func (*UpdateStatement) stmt() {} // CloneStatement returns a deep copy stmt. func CloneStatement(stmt Statement) Statement { @@ -133,6 +139,8 @@ return stmt.Clone() case *CreateViewStatement: return stmt.Clone() + case *CreateVirtualTableStatement: + return stmt.Clone() case *DeleteStatement: return stmt.Clone() case *DropIndexStatement: @@ -145,8 +153,12 @@ return stmt.Clone() case *ExplainStatement: return stmt.Clone() + case *PragmaStatement: + return stmt.Clone() case *InsertStatement: return stmt.Clone() + case *ReindexStatement: + return stmt.Clone() case *ReleaseStatement: return stmt.Clone() case *RollbackStatement: @@ -200,6 +212,7 @@ func (*CaseExpr) expr() {} func (*CastExpr) expr() {} func (*Exists) expr() {} +func (*Null) expr() {} func (*ExprList) expr() {} func (*Ident) expr() {} func (*NullLit) expr() {} @@ -236,6 +249,8 @@ return expr.Clone() case *Exists: return expr.Clone() + case *Null: + return expr.Clone() case *ExprList: return expr.Clone() case *Ident: @@ -258,6 +273,8 @@ return expr.Clone() case *UnaryExpr: return expr.Clone() + case SelectExpr: + return expr.Clone() default: panic(fmt.Sprintf("invalid expr type: %T", expr)) } @@ -344,6 +361,8 @@ return src.Clone() case *QualifiedTableName: return src.Clone() + case *QualifiedTableFunctionName: + return src.Clone() case *SelectStatement: return src.Clone() default: @@ -628,6 +647,7 @@ If Pos // position of IF keyword (optional) IfNot Pos // position of NOT keyword (optional) IfNotExists Pos // position of EXISTS keyword (optional) + Schema *Ident // optional schema name Name *Ident // table name Lparen Pos // position of left paren of column list @@ -649,6 +669,7 @@ return s } other := *s + other.Schema = s.Schema.Clone() other.Name = s.Name.Clone() other.Columns = cloneColumnDefinitions(s.Columns) other.Constraints = cloneConstraints(s.Constraints) @@ -664,6 +685,10 @@ buf.WriteString(" IF NOT EXISTS") } buf.WriteString(" ") + if s.Schema != nil { + buf.WriteString(s.Schema.String()) + buf.WriteString(".") + } buf.WriteString(s.Name.String()) if s.Select != nil { @@ -1225,6 +1250,112 @@ return buf.String() } +type CreateVirtualTableStatement struct { + Create Pos // position of CREATE keyword + Virtual Pos // position of VIRTUAL keyword + Table Pos // position of TABLE keyword + If Pos // position of IF keyword (optional) + IfNot Pos // position of NOT keyword (optional) + IfNotExists Pos // position of EXISTS keyword (optional) + + Schema *Ident // schema name (optional) + Dot Pos // position of DOT token (optional) + Name *Ident // table name + + Using Pos // position of USING + ModuleName *Ident // name of an object that implements the virtual table + + Lparen Pos // position of left paren of module argument list (optional) + Arguments []*ModuleArgument // module argument list (optional) + Rparen Pos // position of right paren of module argument list (optional) + +} + +// Clone returns a deep copy of s. +func (s *CreateVirtualTableStatement) Clone() *CreateVirtualTableStatement { + if s == nil { + return s + } + other := *s + other.Schema = s.Name.Clone() + other.Name = s.Name.Clone() + other.ModuleName = s.ModuleName.Clone() + other.Arguments = cloneModuleArguments(s.Arguments) + return &other +} + +// String returns the string representation of the statement. +func (s *CreateVirtualTableStatement) String() string { + var buf bytes.Buffer + buf.WriteString("CREATE VIRTUAL TABLE ") + if s.IfNotExists.IsValid() { + buf.WriteString("IF NOT EXISTS ") + } + + if s.Schema != nil { + buf.WriteString(s.Schema.String()) + buf.WriteString(".") + } + buf.WriteString(s.Name.String()) + + buf.WriteString(" USING ") + buf.WriteString(s.ModuleName.String()) + if s.Lparen.IsValid() { + buf.WriteString(" (") + for i := range s.Arguments { + if i != 0 { + buf.WriteString(",") + } + buf.WriteString(s.Arguments[i].String()) + } + buf.WriteString(")") + } + return buf.String() +} + +type ModuleArgument struct { + Name *Ident // argument name + Assign Pos // position of ASSIGN token (optional) + Literal Expr // literal that is assigned to name (optional) + Type *Type // type of Name, if Assign is set then Type cant be (optional) +} + +func (a *ModuleArgument) Clone() *ModuleArgument { + if a == nil { + return a + } + other := *a + other.Name = a.Name.Clone() + other.Literal = CloneExpr(a.Literal) + other.Type = a.Type.Clone() + return &other +} + +func (a *ModuleArgument) String() string { + var buf bytes.Buffer + + buf.WriteString(a.Name.String()) + if a.Assign.IsValid() { + buf.WriteString("=") + buf.WriteString(a.Literal.String()) + } else if a.Type != nil { + buf.WriteString(" ") + buf.WriteString(a.Type.String()) + } + + return buf.String() +} +func cloneModuleArguments(a []*ModuleArgument) []*ModuleArgument { + if a == nil { + return nil + } + other := make([]*ModuleArgument, len(a)) + for i := range a { + other[i] = a[i].Clone() + } + return other +} + type AnalyzeStatement struct { Analyze Pos // position of ANALYZE keyword Name *Ident // table name @@ -1556,6 +1687,8 @@ return "-" + expr.X.String() case NOT: return "NOT " + expr.X.String() + case BITNOT: + return "~" + expr.X.String() default: panic(fmt.Sprintf("sql.UnaryExpr.String(): invalid op %s", expr.Op)) } @@ -1820,6 +1953,30 @@ return fmt.Sprintf("EXISTS (%s)", expr.Select.String()) } +type Null struct { + X Expr // expression being checked for null + Op Token // IS or NOT token + OpPos Pos // position of NOT NULL postfix operation +} + +// Clone returns a deep copy of expr. +func (expr *Null) Clone() *Null { + if expr == nil { + return nil + } + other := *expr + other.X = CloneExpr(expr.X) + return &other +} + +// String returns the string representation of the expression. +func (expr *Null) String() string { + if expr.Op == ISNULL { + return "IS NULL" + } + return "NOT NULL" +} + type ExprList struct { Lparen Pos // position of left paren Exprs []Expr // list of expressions @@ -3365,10 +3522,82 @@ // String returns the string representation of the clause. func (c *JoinClause) String() string { var buf bytes.Buffer - fmt.Fprintf(&buf, "%s%s%s", c.X.String(), c.Operator.String(), c.Y.String()) - if c.Constraint != nil { - fmt.Fprintf(&buf, " %s", c.Constraint.String()) + + // Print the left side + buf.WriteString(c.X.String()) + + // Print the operator + buf.WriteString(c.Operator.String()) + + // Handle the right side + if y, ok := c.Y.(*JoinClause); ok { + // Special case: right side is a JoinClause + + // Check if the X of the nested JoinClause is also a JoinClause + if yx, ok := y.X.(*JoinClause); ok { + // Handle the double-nested case + + // Print the first table of the inner JoinClause + buf.WriteString(yx.X.String()) + + // Add the constraint for the first join + if c.Constraint != nil { + fmt.Fprintf(&buf, " %s", c.Constraint.String()) + } + + // Print the operator of the inner JoinClause + buf.WriteString(yx.Operator.String()) + + // Print the second table of the inner JoinClause + buf.WriteString(yx.Y.String()) + + // Add the constraint for the inner JoinClause + if yx.Constraint != nil { + fmt.Fprintf(&buf, " %s", yx.Constraint.String()) + } + + // Print the operator of the outer JoinClause + buf.WriteString(y.Operator.String()) + + // Print the right side of the outer JoinClause + buf.WriteString(y.Y.String()) + + // Add the constraint for the outer JoinClause + if y.Constraint != nil { + fmt.Fprintf(&buf, " %s", y.Constraint.String()) + } + } else { + // Handle the singly-nested case + + // Print the left side of the nested JoinClause + buf.WriteString(y.X.String()) + + // Add the constraint for the first join + if c.Constraint != nil { + fmt.Fprintf(&buf, " %s", c.Constraint.String()) + } + + // Print the operator of the nested JoinClause + buf.WriteString(y.Operator.String()) + + // Print the right side of the nested JoinClause + buf.WriteString(y.Y.String()) + + // Add the constraint for the nested JoinClause + if y.Constraint != nil { + fmt.Fprintf(&buf, " %s", y.Constraint.String()) + } + } + } else { + // Normal case: right side is not a JoinClause + buf.WriteString(c.Y.String()) + + // Add the constraint + if c.Constraint != nil { + fmt.Fprintf(&buf, " %s", c.Constraint.String()) + } } + return buf.String() } @@ -3694,3 +3923,36 @@ return buf.String() } + +type PragmaStatement struct { + Pragma Pos // position of PRAGMA keyword + Schema *Ident // name of schema (optional) + Dot Pos // position of DOT token (optional) + Expr Expr // can be Ident, Call or BinaryExpr +} + +// Clone returns a deep copy of s. +func (s *PragmaStatement) Clone() *PragmaStatement { + if s == nil { + return s + } + + other := *s + other.Schema = s.Schema.Clone() + other.Expr = CloneExpr(s.Expr) + return &other +} + +// String returns the string representation of the pragma statement. +func (s *PragmaStatement) String() string { + var buf bytes.Buffer + + buf.WriteString("PRAGMA ") + if s.Schema != nil { + buf.WriteString(s.Schema.String()) + buf.WriteString(".") + } + buf.WriteString(s.Expr.String()) + + return buf.String() +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/rqlite/sql/parser.go new/vendor/github.com/rqlite/sql/parser.go --- old/vendor/github.com/rqlite/sql/parser.go 2025-05-30 21:14:32.000000000 +0200 +++ new/vendor/github.com/rqlite/sql/parser.go 2025-06-07 17:38:12.000000000 +0200 @@ -91,6 +91,8 @@ // parseStmt parses all statement types. func (p *Parser) parseNonExplainStatement() (Statement, error) { switch p.peek() { + case PRAGMA: + return p.parsePragmaStatement() case ANALYZE: return p.parseAnalyzeStatement() case REINDEX: @@ -245,6 +247,8 @@ switch p.peek() { case TABLE: return p.parseCreateTableStatement(pos) + case VIRTUAL: + return p.parseCreateVirtualTableStatement(pos) case VIEW: return p.parseCreateViewStatement(pos) case INDEX, UNIQUE: @@ -298,10 +302,29 @@ stmt.IfNotExists = pos } - if stmt.Name, err = p.parseIdent("table name"); err != nil { + // Parse the first identifier (either schema or table name) + firstIdent, err := p.parseIdent("table name") + if err != nil { return &stmt, err } + // Check if it's a schema.table format + if p.peek() == DOT { + // First identifier is the schema name + stmt.Schema = firstIdent + + // Consume the dot + p.scan() + + // Parse the table name + if stmt.Name, err = p.parseIdent("table name"); err != nil { + return &stmt, err + } + } else { + // Just a table name without schema + stmt.Name = firstIdent + } + // Parse either a column/constraint list or build table from "AS <select>". switch p.peek() { case LP: @@ -380,7 +403,7 @@ return &col, err } - if tok := p.peek(); tok == IDENT { + if tok := p.peek(); tok == IDENT || tok == NULL { if col.Type, err = p.parseType(); err != nil { return &col, err } @@ -844,6 +867,119 @@ return &cons, nil } +func (p *Parser) parseCreateVirtualTableStatement(createPos Pos) (_ *CreateVirtualTableStatement, err error) { + assert(p.peek() == VIRTUAL) + + var stmt CreateVirtualTableStatement + stmt.Create = createPos + stmt.Virtual, _, _ = p.scan() + stmt.Table, _, _ = p.scan() + + // Parse optional "IF NOT EXISTS". + if p.peek() == IF { + stmt.If, _, _ = p.scan() + + pos, tok, _ := p.scan() + if tok != NOT { + return &stmt, p.errorExpected(pos, tok, "NOT") + } + stmt.IfNot = pos + + pos, tok, _ = p.scan() + if tok != EXISTS { + return &stmt, p.errorExpected(pos, tok, "EXISTS") + } + stmt.IfNotExists = pos + } + + ident, err := p.parseIdent("schema or table name") + if err != nil { + return &stmt, err + } + if p.peek() == DOT { + stmt.Schema = ident + stmt.Dot, _, _ = p.scan() + if stmt.Name, err = p.parseIdent("table name"); err != nil { + return &stmt, err + } + } else { + stmt.Name = ident + } + + pos, tok, _ := p.scan() + if tok != USING { + return &stmt, p.errorExpected(p.pos, p.tok, "USING") + } + stmt.Using = pos + + if stmt.ModuleName, err = p.parseIdent("module name"); err != nil { + return &stmt, err + } + // Module arguments can be optional + if p.peek() != LP { + return &stmt, nil + } + stmt.Lparen, _, _ = p.scan() + + if stmt.Arguments, err = p.parseModuleArguments(); err != nil { + return &stmt, err + } + + if len(stmt.Arguments) == 0 { + return &stmt, p.errorExpected(p.pos, p.tok, "module arguments") + } + + if p.peek() != RP { + return &stmt, p.errorExpected(p.pos, p.tok, "right paren") + } + stmt.Rparen, _, _ = p.scan() + + return &stmt, nil +} + +func (p *Parser) parseModuleArguments() (_ []*ModuleArgument, err error) { + var args []*ModuleArgument + + for p.peek() != RP { + arg, err := p.parseModuleArgument() + if err != nil { + return args, err + } + args = append(args, arg) + + if p.peek() == COMMA { + p.scan() + } else if p.peek() != RP { + return args, p.errorExpected(p.pos, p.tok, "comma or right paren") + } + } + + return args, nil +} + +func (p *Parser) parseModuleArgument() (_ *ModuleArgument, err error) { + var arg ModuleArgument + + if arg.Name, err = p.parseIdent("module argument name"); err != nil { + return &arg, err + } + + if p.peek() == EQ { + // Parse literal + arg.Assign, _, _ = p.scan() + if arg.Literal, err = p.parseOperand(); err != nil { + return &arg, err + } + } else if isTypeName(p.lit) { + if arg.Type, err = p.parseType(); err != nil { + return &arg, err + } + + } + + return &arg, nil +} + func (p *Parser) parseDropTableStatement(dropPos Pos) (_ *DropTableStatement, err error) { assert(p.peek() == TABLE) @@ -1217,6 +1353,8 @@ switch tok { case IDENT, QIDENT: return &Ident{Name: lit, NamePos: pos, Quoted: tok == QIDENT}, nil + case NULL: + return &Ident{Name: lit, NamePos: pos}, nil default: if isBareToken(tok) { return &Ident{Name: lit, NamePos: pos}, nil @@ -1227,7 +1365,11 @@ func (p *Parser) parseType() (_ *Type, err error) { var typ Type - for p.peek() == IDENT { + for { + tok := p.peek() + if tok != IDENT && tok != NULL { + break + } typeName, err := p.parseIdent("type name") if err != nil { return &typ, err @@ -2139,8 +2281,7 @@ } source.Rparen, _, _ = p.scan() - // Only parse aliases for nested select statements. - if _, ok := source.X.(*SelectStatement); ok && (p.peek() == AS || isIdentToken(p.peek())) { + if p.peek() == AS || isIdentToken(p.peek()) { if p.peek() == AS { source.As, _, _ = p.scan() } @@ -2367,7 +2508,7 @@ return &BoolLit{ValuePos: pos, Value: tok == TRUE}, nil case tok == BIND: return &BindExpr{NamePos: pos, Name: lit}, nil - case tok == PLUS, tok == MINUS: + case tok == PLUS, tok == MINUS, tok == BITNOT: expr, err = p.parseOperand() if err != nil { return nil, err @@ -2423,7 +2564,10 @@ } switch op { + case NOTNULL, ISNULL: + x = &Null{X: x, OpPos: pos, Op: op} case IN, NOTIN: + y, err := p.parseExprList() if err != nil { return x, err @@ -2838,14 +2982,42 @@ return &spec, nil } -func (p *Parser) parseParenExpr() (_ *ParenExpr, err error) { - var expr ParenExpr - expr.Lparen, _, _ = p.scan() - if expr.X, err = p.ParseExpr(); err != nil { - return &expr, err +func (p *Parser) parseParenExpr() (Expr, error) { + lparen, _, _ := p.scan() + + // Parse the first expression + x, err := p.ParseExpr() + if err != nil { + return nil, err } - expr.Rparen, _, _ = p.scan() - return &expr, nil + + // If there's no comma after the first expression, treat it as a normal parenthesized expression + if p.peek() != COMMA { + rparen, _, _ := p.scan() + return &ParenExpr{Lparen: lparen, X: x, Rparen: rparen}, nil + } + + // If there's a comma, we're dealing with an expression list + var list ExprList + list.Lparen = lparen + list.Exprs = append(list.Exprs, x) + + for p.peek() == COMMA { + p.scan() // consume the comma + + expr, err := p.ParseExpr() + if err != nil { + return &list, err + } + list.Exprs = append(list.Exprs, expr) + } + + if p.peek() != RP { + return &list, p.errorExpected(p.pos, p.tok, "right paren") + } + list.Rparen, _, _ = p.scan() + + return &list, nil } func (p *Parser) parseCastExpr() (_ *CastExpr, err error) { @@ -3092,6 +3264,54 @@ } } +func (p *Parser) parsePragmaStatement() (_ *PragmaStatement, err error) { + assert(p.peek() == PRAGMA) + + var stmt PragmaStatement + stmt.Pragma, _, _ = p.scan() + + lit, err := p.parseIdent("schema name") + if err != nil { + return &stmt, err + } + + // Handle <schema>.<pragma-name> + if p.peek() == DOT { + stmt.Schema = lit + stmt.Dot, _, _ = p.scan() + if lit, err = p.parseIdent("pragma name"); err != nil { + return &stmt, err + } + } + + switch p.peek() { + case EQ: + // Parse as binary expression: pragma-name = value + opPos, _, _ := p.scan() + rhs, err := p.ParseExpr() + if err != nil { + return &stmt, err + } + stmt.Expr = &BinaryExpr{ + X: lit, + OpPos: opPos, + Op: EQ, + Y: rhs, + } + case LP: + // Parse as function call: pragma-name(args) + call, err := p.parseCall(lit) + if err != nil { + return &stmt, err + } + stmt.Expr = call + default: + stmt.Expr = lit + } + + return &stmt, nil +} + func (p *Parser) parseAnalyzeStatement() (_ *AnalyzeStatement, err error) { assert(p.peek() == ANALYZE) @@ -3154,6 +3374,9 @@ if p.peek() == NOT { p.scan() return pos, ISNOT, nil + } else if p.peek() == NULL { + p.scan() + return pos, ISNULL, nil } return pos, IS, nil case NOT: @@ -3176,8 +3399,11 @@ case BETWEEN: p.scan() return pos, NOTBETWEEN, nil + case NULL: + p.scan() + return pos, NOTNULL, nil default: - return pos, tok, p.errorExpected(p.pos, p.tok, "IN, LIKE, GLOB, REGEXP, MATCH, or BETWEEN") + return pos, tok, p.errorExpected(p.pos, p.tok, "IN, LIKE, GLOB, REGEXP, MATCH, BETWEEN, IS/NOT NULL") } default: return pos, tok, nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/rqlite/sql/scanner.go new/vendor/github.com/rqlite/sql/scanner.go --- old/vendor/github.com/rqlite/sql/scanner.go 2025-05-30 21:14:32.000000000 +0200 +++ new/vendor/github.com/rqlite/sql/scanner.go 2025-06-07 17:38:12.000000000 +0200 @@ -58,7 +58,7 @@ s.read() return pos, NE, "!=" } - return pos, BITNOT, "!" + return pos, ILLEGAL, "!" case '=': if s.peek() == '=' { s.read() @@ -119,6 +119,8 @@ return pos, SLASH, "/" case '%': return pos, REM, "%" + case '~': + return pos, BITNOT, "~" default: return pos, ILLEGAL, string(ch) } @@ -271,6 +273,25 @@ s.buf.Reset() + if s.peek() == '0' { + s.buf.WriteRune('0') + s.read() + if s.peek() == 'x' || s.peek() == 'X' { + s.read() + s.buf.WriteRune('x') + for isHex(s.peek()) { + ch, _ := s.read() + s.buf.WriteRune(ch) + } + // TODO: error handling: + // if len(s.buf.String()) < 2 => invalid + // reason: means we scanned '0x' + // if len(s.buf.String()) - 2 > 16 => invalid + // reason: according to spec maximum of 16 significant digits) + return pos, tok, s.buf.String() + } + } + // Read whole number if starting with a digit. if isDigit(s.peek()) { for isDigit(s.peek()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/rqlite/sql/token.go new/vendor/github.com/rqlite/sql/token.go --- old/vendor/github.com/rqlite/sql/token.go 2025-05-30 21:14:32.000000000 +0200 +++ new/vendor/github.com/rqlite/sql/token.go 2025-06-07 17:38:12.000000000 +0200 @@ -61,7 +61,7 @@ GE // >= BITAND // & BITOR // | - BITNOT // ! + BITNOT // ~ LSHIFT // << RSHIFT // >> PLUS // + @@ -278,7 +278,7 @@ GE: ">=", BITAND: "&", BITOR: "|", - BITNOT: "!", + BITNOT: "~", LSHIFT: "<<", RSHIFT: ">>", PLUS: "+", @@ -524,8 +524,8 @@ // List keywords that can be used as identifiers in expressions case ROWID, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP: return true - // replace() core function - case REPLACE: + // Core functions + case REPLACE, LIKE, GLOB, IF: return true // Add any other non-reserved keywords here default: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/modules.txt new/vendor/modules.txt --- old/vendor/modules.txt 2025-05-30 21:14:32.000000000 +0200 +++ new/vendor/modules.txt 2025-06-07 17:38:12.000000000 +0200 @@ -233,7 +233,7 @@ github.com/rqlite/rqlite-disco-clients/dnssrv github.com/rqlite/rqlite-disco-clients/etcd github.com/rqlite/rqlite-disco-clients/expand -# github.com/rqlite/sql v0.0.0-20250530185618-c2b588be35aa +# github.com/rqlite/sql v0.0.0-20250607152030-b0dd329faf9b ## explicit; go 1.17 github.com/rqlite/sql # go.etcd.io/bbolt v1.4.0