# Migrating from JSQLParser to GoSQLX

Source: https://gosqlx.dev/docs/migration/from-jsqlparser/

This guide helps Java developers migrate from JSQLParser to GoSQLX, covering API differences, code translation patterns, and practical migration strategies.

---

## Overview Comparison

### JSQLParser
**JSQLParser** is a SQL statement parser written in Java. It translates SQLs into a traversable hierarchy of Java classes using the Visitor pattern.

**Key Strengths:**
- Mature Java library (10+ years)
- Comprehensive statement support
- Visitor pattern for AST traversal
- De-parser to regenerate SQL from AST
- Active development

**Key Weaknesses:**
- JVM startup overhead
- Higher memory usage (10KB per query)
- Slower parsing (50K ops/sec)
- Complex API with many classes
- Java-only (no cross-language bindings)

### GoSQLX
**GoSQLX** is a production-ready, race-free, high-performance SQL parsing SDK for Go.

**Key Strengths:**
- Blazing fast (1.38M+ ops/sec - 27x faster!)
- Memory efficient (1.8KB per query - 82% less memory)
- Native Go concurrency (linear scaling)
- Zero dependencies (no JVM required)
- Simple, clean API

**Key Trade-offs:**
- Fewer helper classes (simpler but less hand-holding)
- No built-in de-parser yet
- Go ecosystem only (no Java bindings)
- Less mature (newer project)

---

## Why Migrate to GoSQLX?

### You Should Migrate If:

✅ **Switching from Java to Go**
- Microservices rewrite from Java to Go
- Building new Go applications
- Want to eliminate JVM dependency

✅ **Performance is critical**
- Need to parse thousands of queries per second
- Real-time SQL analysis
- Low-latency requirements (<1ms)
- Memory-constrained environments

✅ **Want simpler deployment**
- Single binary deployment (no JVM)
- Faster startup times (no JVM warmup)
- Smaller container images

✅ **Need better concurrency**
- Process queries in parallel without thread pools
- Linear scaling to many cores
- No thread synchronization complexity

### You Should Stay with JSQLParser If:

❌ **You're committed to Java ecosystem** (Spring, JDBC, etc.)
❌ **You need the de-parser** (regenerate SQL from modified AST)
❌ **You need PL/SQL support** (Oracle stored procedures)
❌ **You have large JSQLParser codebase** (high migration cost)

---

## Feature Mapping

| Feature | JSQLParser | GoSQLX | Notes |
|---------|-----------|--------|-------|
| **Core Functionality** |
| SQL Parsing | ✅ Yes | ✅ Yes | GoSQLX 27x faster |
| AST Generation | ✅ Yes | ✅ Yes | Different structure |
| Visitor Pattern | ✅ Yes | ✅ Yes | Similar approach |
| De-parser | ✅ Yes | ❌ Planned | Generate SQL from AST |
| **SQL Statements** |
| SELECT | ✅ Full | ✅ Full | Similar coverage |
| INSERT | ✅ Full | ✅ Full | |
| UPDATE | ✅ Full | ✅ Full | |
| DELETE | ✅ Full | ✅ Full | |
| CREATE TABLE | ✅ Full | ✅ Full | |
| ALTER TABLE | ✅ Full | ✅ Full | |
| DROP | ✅ Full | ✅ Full | |
| MERGE | ✅ Yes | ⚠️ Basic | JSQLParser more complete |
| **SQL Features** |
| JOINs (All Types) | ✅ Yes | ✅ Yes | |
| Subqueries | ✅ Yes | ✅ Yes | |
| CTEs (WITH) | ✅ Yes | ✅ Yes | |
| Recursive CTEs | ✅ Yes | ✅ Yes | |
| Window Functions | ✅ Yes | ✅ Yes | |
| Set Operations | ✅ Yes | ✅ Yes | |
| **Dialects** |
| PostgreSQL | ✅ Yes | ✅ Yes | ~80-85% coverage |
| MySQL/MariaDB | ✅ Yes | ✅ Yes | ~80% coverage |
| SQL Server | ✅ Yes | ✅ Yes | ~75% coverage |
| Oracle | ✅ Yes | ✅ Yes | ~70% coverage |
| SQLite | ✅ Yes | ✅ Yes | ~85% coverage |
| H2 | ✅ Yes | ❌ No | |
| DuckDB | ✅ Yes | ❌ No | |
| **API Features** |
| Helper Classes | ✅ Many | ⚠️ Fewer | GoSQLX simpler |
| Table Name Finder | ✅ Built-in | ⚠️ DIY | Example provided |
| Expression Parser | ✅ Built-in | ✅ Built-in | |
| Fluent API | ✅ Yes | ❌ No | Build SQL in code |
| **Performance** |
| Parse Speed | 50K ops/sec | 1.38M ops/sec | 27x faster |
| Memory per Query | 10KB | 1.8KB | 5.5x less |
| Startup Time | ~2 seconds | ~5ms | 400x faster |
| **Advanced Features** |
| Stored Procedures | ✅ Full | ⚠️ Basic | JSQLParser better |
| PL/SQL | ✅ Full | ⚠️ Basic | |
| T-SQL | ✅ Full | ⚠️ Basic | |

---

## Side-by-Side Code Examples

### Example 1: Basic Parsing

#### JSQLParser (Java)
```java
// Maven: net.sf.jsqlparser:jsqlparser:4.6
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.Select;

public class BasicParsing {
    public static void main(String[] args) throws Exception {
        String sql = "SELECT * FROM users WHERE active = true";

        // Parse SQL
        Statement stmt = CCJSqlParserUtil.parse(sql);

        // Type checking required
        if (stmt instanceof Select) {
            Select select = (Select) stmt;
            System.out.println("Parsed SELECT statement");
        }
    }
}
```

#### GoSQLX (Go)
```go
// go get github.com/ajitpratap0/GoSQLX
package main

import (
    "fmt"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/parser"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer"
)

func main() {
    sql := "SELECT * FROM users WHERE active = true"

    // Step 1: Tokenize
    tkz := tokenizer.GetTokenizer()
    defer tokenizer.PutTokenizer(tkz)

    tokens, err := tkz.Tokenize([]byte(sql))
    if err != nil {
        panic(err)
    }

    // Step 2: Parse (one parser, released when main returns)
    p := parser.NewParser()
    defer p.Release()

    astObj, err := p.ParseFromModelTokens(tokens)
    if err != nil {
        panic(err)
    }
    defer ast.ReleaseAST(astObj)

    fmt.Printf("Parsed %d statement(s)\n", len(astObj.Statements))
}
```

### Example 2: Extracting Table Names

#### JSQLParser (Java)
```java
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.util.TablesNamesFinder;
import java.util.List;

public class TableExtraction {
    public static void main(String[] args) throws Exception {
        String sql = "SELECT u.*, o.id FROM users u " +
                     "JOIN orders o ON u.id = o.user_id " +
                     "WHERE u.active = true";

        // Parse statement
        Statement stmt = CCJSqlParserUtil.parse(sql);

        // Use built-in table finder
        TablesNamesFinder finder = new TablesNamesFinder();
        List<String> tables = finder.getTableList(stmt);

        // Output: [users, orders]
        for (String table : tables) {
            System.out.println("Table: " + table);
        }
    }
}
```

#### GoSQLX (Go)
```go
package main

import (
    "fmt"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer"
    "github.com/ajitpratap0/GoSQLX/pkg/models"
)

func main() {
    sql := "SELECT u.*, o.id FROM users u " +
           "JOIN orders o ON u.id = o.user_id " +
           "WHERE u.active = true"

    tables := extractTables(sql)

    // Output: [users, orders]
    for _, table := range tables {
        fmt.Printf("Table: %s\n", table)
    }
}

func extractTables(sql string) []string {
    tkz := tokenizer.GetTokenizer()
    defer tokenizer.PutTokenizer(tkz)

    tokens, _ := tkz.Tokenize([]byte(sql))

    tables := []string{}
    expectTable := false

    for _, tok := range tokens {
        if tok.Token.Type == models.TokenTypeFrom ||
           tok.Token.Type == models.TokenTypeJoin {
            expectTable = true
            continue
        }

        if expectTable && tok.Token.Type == models.TokenTypeIdentifier {
            tables = append(tables, tok.Token.Value)
            expectTable = false
        }
    }

    return tables
}
```

### Example 3: Visitor Pattern for AST Traversal

#### JSQLParser (Java)
```java
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.util.SelectUtils;

public class VisitorExample {
    public static void main(String[] args) throws Exception {
        String sql = "SELECT name, age FROM users WHERE age > 18";
        Statement stmt = CCJSqlParserUtil.parse(sql);

        // Use visitor pattern
        Select select = (Select) stmt;
        PlainSelect plainSelect = (PlainSelect) select.getSelectBody();

        // Visit select items
        SelectItemVisitorAdapter visitor = new SelectItemVisitorAdapter() {
            @Override
            public void visit(SelectExpressionItem item) {
                System.out.println("Column: " + item.toString());
            }
        };

        for (SelectItem item : plainSelect.getSelectItems()) {
            item.accept(visitor);
        }
    }
}
```

#### GoSQLX (Go)
```go
package main

import (
    "fmt"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/parser"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer"
)

func main() {
    sql := "SELECT name, age FROM users WHERE age > 18"

    // Parse to AST
    astObj := parseSQL(sql)

    // Use visitor pattern
    visitor := &ColumnVisitor{columns: []string{}}
    ast.Walk(visitor, astObj)

    for _, col := range visitor.columns {
        fmt.Printf("Column: %s\n", col)
    }
}

// Custom visitor implementation
type ColumnVisitor struct {
    columns []string
}

func (v *ColumnVisitor) Visit(node ast.Node) ast.Visitor {
    // Visit identifier nodes (column names)
    if ident, ok := node.(*ast.Identifier); ok {
        v.columns = append(v.columns, ident.Value)
    }
    return v
}

func parseSQL(sql string) *ast.AST {
    tkz := tokenizer.GetTokenizer()
    defer tokenizer.PutTokenizer(tkz)

    tokens, _ := tkz.Tokenize([]byte(sql))

    p := parser.NewParser()
    defer p.Release()

    astObj, _ := p.ParseFromModelTokens(tokens)
    return astObj
}
```

### Example 4: Parsing Multiple Statements

#### JSQLParser (Java)
```java
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.Statements;

public class MultipleStatements {
    public static void main(String[] args) throws Exception {
        String sql = "SELECT * FROM users; " +
                     "UPDATE users SET active = true; " +
                     "DELETE FROM logs WHERE old = true;";

        // Parse multiple statements
        Statements stmts = CCJSqlParserUtil.parseStatements(sql);

        for (Statement stmt : stmts.getStatements()) {
            System.out.println("Statement type: " +
                             stmt.getClass().getSimpleName());
        }
        // Output: Select, Update, Delete
    }
}
```

#### GoSQLX (Go)
```go
package main

import (
    "fmt"
    "strings"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/parser"
)

func main() {
    sql := "SELECT * FROM users; " +
           "UPDATE users SET active = true; " +
           "DELETE FROM logs WHERE old = true;"

    statements := parseMultiple(sql)

    for _, stmt := range statements {
        fmt.Printf("Statement type: %T\n", stmt)
    }
}

func parseMultiple(sql string) []interface{} {
    // Split by semicolon
    parts := strings.Split(sql, ";")
    statements := []interface{}{}

    p := parser.NewParser()
    defer p.Release()

    for _, part := range parts {
        part = strings.TrimSpace(part)
        if part == "" {
            continue
        }

        tkz := tokenizer.GetTokenizer()
        tokens, err := tkz.Tokenize([]byte(part))
        tokenizer.PutTokenizer(tkz)

        if err != nil {
            continue
        }

        astObj, _ := p.ParseFromModelTokens(tokens)
        statements = append(statements, astObj)
    }

    return statements
}
```

### Example 5: Expression Parsing

#### JSQLParser (Java)
```java
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;

public class ExpressionParsing {
    public static void main(String[] args) throws Exception {
        String expr = "age > 18 AND status = 'active'";

        // Parse expression directly
        Expression exp = CCJSqlParserUtil.parseExpression(expr);

        // Check type
        if (exp instanceof AndExpression) {
            AndExpression and = (AndExpression) exp;
            System.out.println("Left: " + and.getLeftExpression());
            System.out.println("Right: " + and.getRightExpression());
        }
    }
}
```

#### GoSQLX (Go)
```go
package main

import (
    "fmt"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer"
    "github.com/ajitpratap0/GoSQLX/pkg/models"
)

func main() {
    expr := "age > 18 AND status = 'active'"

    // Tokenize expression
    tkz := tokenizer.GetTokenizer()
    defer tokenizer.PutTokenizer(tkz)

    tokens, _ := tkz.Tokenize([]byte(expr))

    // Analyze expression structure
    for _, tok := range tokens {
        if tok.Token.Type == models.TokenTypeEOF {
            break
        }

        switch tok.Token.Type {
        case models.TokenTypeAnd:
            fmt.Println("Found AND operator")
        case models.TokenTypeIdentifier:
            fmt.Printf("Identifier: %s\n", tok.Token.Value)
        case models.TokenTypeNumber:
            fmt.Printf("Number: %s\n", tok.Token.Value)
        }
    }
}
```

### Example 6: Building SQL with Fluent API

#### JSQLParser (Java)
```java
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.expression.StringValue;

public class FluentAPI {
    public static void main(String[] args) {
        // Build SELECT using fluent API
        PlainSelect select = new PlainSelect();
        select.addSelectItems(new SelectExpressionItem(new Column("name")));
        select.addSelectItems(new SelectExpressionItem(new Column("email")));
        select.setFromItem(new Table("users"));

        // Add WHERE clause
        EqualsTo equals = new EqualsTo();
        equals.setLeftExpression(new Column("active"));
        equals.setRightExpression(new StringValue("true"));
        select.setWhere(equals);

        // Generate SQL
        System.out.println(select.toString());
        // Output: SELECT name, email FROM users WHERE active = 'true'
    }
}
```

#### GoSQLX (Go)
```go
package main

import (
    "fmt"
    "strings"
)

// GoSQLX doesn't have fluent API (yet)
// Build SQL using strings.Builder

func main() {
    sql := buildSelect(
        []string{"name", "email"},
        "users",
        "active = true",
    )

    fmt.Println(sql)
    // Output: SELECT name, email FROM users WHERE active = true
}

func buildSelect(columns []string, table string, where string) string {
    var b strings.Builder

    b.WriteString("SELECT ")
    b.WriteString(strings.Join(columns, ", "))
    b.WriteString(" FROM ")
    b.WriteString(table)

    if where != "" {
        b.WriteString(" WHERE ")
        b.WriteString(where)
    }

    return b.String()
}

// Note: Fluent API for building SQL is planned for GoSQLX v2.0
```

---

## Common Patterns Translation

### Pattern 1: Batch Processing

#### JSQLParser (Java)
```java
import java.util.*;
import java.util.concurrent.*;

public class BatchProcessor {
    private ExecutorService executor =
        Executors.newFixedThreadPool(16);

    public List<ParseResult> processBatch(List<String> queries) {
        List<Future<ParseResult>> futures = new ArrayList<>();

        for (String sql : queries) {
            futures.add(executor.submit(() -> {
                try {
                    Statement stmt = CCJSqlParserUtil.parse(sql);
                    return new ParseResult(true, null);
                } catch (Exception e) {
                    return new ParseResult(false, e.getMessage());
                }
            }));
        }

        // Collect results
        List<ParseResult> results = new ArrayList<>();
        for (Future<ParseResult> f : futures) {
            try {
                results.add(f.get());
            } catch (Exception e) {
                results.add(new ParseResult(false, e.getMessage()));
            }
        }

        return results;
    }
}
```

#### GoSQLX (Go)
```go
package main

import (
    "sync"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer"
)

type ParseResult struct {
    Valid bool
    Error string
}

func processBatch(queries []string) []ParseResult {
    results := make([]ParseResult, len(queries))
    var wg sync.WaitGroup

    // Process concurrently (no thread pool needed!)
    for i, sql := range queries {
        wg.Add(1)
        go func(idx int, query string) {
            defer wg.Done()

            tkz := tokenizer.GetTokenizer()
            defer tokenizer.PutTokenizer(tkz)

            _, err := tkz.Tokenize([]byte(query))

            results[idx] = ParseResult{
                Valid: err == nil,
                Error: "",
            }
            if err != nil {
                results[idx].Error = err.Error()
            }
        }(i, sql)
    }

    wg.Wait()
    return results
}
```

### Pattern 2: Query Analysis Service

#### JSQLParser (Java + Spring Boot)
```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;

@SpringBootApplication
@RestController
public class QueryAnalyzer {

    @PostMapping("/analyze")
    public AnalysisResult analyze(@RequestBody QueryRequest req) {
        try {
            Statement stmt = CCJSqlParserUtil.parse(req.getSql());

            // Extract information
            TablesNamesFinder finder = new TablesNamesFinder();
            List<String> tables = finder.getTableList(stmt);

            return new AnalysisResult(
                true,
                tables,
                stmt.getClass().getSimpleName()
            );
        } catch (Exception e) {
            return new AnalysisResult(false, null, null);
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(QueryAnalyzer.class, args);
    }
}
```

#### GoSQLX (Go + net/http)
```go
package main

import (
    "encoding/json"
    "net/http"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer"
    "github.com/ajitpratap0/GoSQLX/pkg/models"
)

type QueryRequest struct {
    SQL string `json:"sql"`
}

type AnalysisResult struct {
    Valid  bool     `json:"valid"`
    Tables []string `json:"tables,omitempty"`
    Type   string   `json:"type,omitempty"`
}

func analyzeHandler(w http.ResponseWriter, r *http.Request) {
    var req QueryRequest
    json.NewDecoder(r.Body).Decode(&req)

    tkz := tokenizer.GetTokenizer()
    defer tokenizer.PutTokenizer(tkz)

    tokens, err := tkz.Tokenize([]byte(req.SQL))

    result := AnalysisResult{Valid: err == nil}
    if err == nil {
        result.Tables = extractTables(tokens)
        result.Type = detectType(tokens)
    }

    json.NewEncoder(w).Encode(result)
}

func main() {
    http.HandleFunc("/analyze", analyzeHandler)
    http.ListenAndServe(":8080", nil)
}

func extractTables(tokens []models.TokenWithSpan) []string {
    // Implementation from earlier example
    return []string{}
}

func detectType(tokens []models.TokenWithSpan) string {
    for _, tok := range tokens {
        switch tok.Token.Type {
        case models.TokenTypeSelect:
            return "SELECT"
        case models.TokenTypeInsert:
            return "INSERT"
        case models.TokenTypeUpdate:
            return "UPDATE"
        case models.TokenTypeDelete:
            return "DELETE"
        }
    }
    return "UNKNOWN"
}
```

---

## Performance Comparison

### Benchmark: Parsing 10,000 SQL Queries

**Test Query:**
```sql
SELECT u.id, u.name, COUNT(o.id)
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.active = true
GROUP BY u.id, u.name
```

**Results:**

| Metric | JSQLParser | GoSQLX | Improvement |
|--------|-----------|--------|-------------|
| Total Time | 200 seconds | 7.2 seconds | 27.7x faster |
| Throughput | 50,000 ops/sec | 1,388,889 ops/sec | 27.7x faster |
| Memory Usage | 100MB | 18MB | 5.5x less |
| JVM Startup | ~2 seconds | N/A (no JVM) | Instant |
| Container Size | 250MB (with JVM) | 15MB | 16x smaller |

### Example Scenario: SQL Validation Service

**Scenario:** REST API validating 1,000 SQL queries/second

**JSQLParser (Java):**
```
- Requires: 20 server instances (50 req/sec each)
- Memory: 4GB per instance × 20 = 80GB total
- Cost: $2,000/month (c5.xlarge × 20)
- Latency: 20ms p50, 50ms p99
- JVM warmup: 30 seconds per deployment
```

**GoSQLX (Go):**
```
- Requires: 1 server instance (1.38M req/sec capable)
- Memory: 2GB total
- Cost: $100/month (c5.large × 1)
- Latency: 0.7ms p50, 1.2ms p99
- Startup: Instant
```

**Savings:** 95% cost reduction, 28x better latency!

---

## Migration Checklist

### Phase 1: Assessment (Week 1)
- [ ] Audit current JSQLParser usage in codebase
- [ ] Identify which API features you use (parsing, visitor, de-parser, etc.)
- [ ] List SQL dialects you support
- [ ] Document custom visitor implementations
- [ ] Check if you use fluent API for SQL building

### Phase 2: Proof of Concept (Week 1-2)
- [ ] Install Go 1.26+ on development machines
- [ ] Install GoSQLX: `go get github.com/ajitpratap0/GoSQLX`
- [ ] Port one Java class to Go
- [ ] Test with your SQL queries
- [ ] Benchmark performance improvement
- [ ] Document API differences

### Phase 3: Development (Week 2-4)
- [ ] Create Go packages to replace Java classes
- [ ] Implement table extraction helpers
- [ ] Port visitor pattern implementations
- [ ] Add error handling with position info
- [ ] Write comprehensive tests
- [ ] Create integration with existing systems

### Phase 4: Testing (Week 4-5)
- [ ] Unit test all Go code
- [ ] Integration test with real SQL queries
- [ ] Load test for performance validation
- [ ] Test error handling and edge cases
- [ ] Verify concurrent processing works correctly

### Phase 5: Deployment (Week 5-6)
- [ ] Deploy Go services alongside Java (parallel run)
- [ ] Monitor metrics (latency, throughput, errors)
- [ ] Gradually shift traffic to Go services
- [ ] Decommission Java services
- [ ] Update documentation and runbooks

### Phase 6: Cleanup (Week 6+)
- [ ] Remove JSQLParser dependencies
- [ ] Clean up Java code
- [ ] Archive old repositories
- [ ] Train team on Go best practices
- [ ] Celebrate performance improvements! 🎉

---

## Example Migration Case Study

### Scenario: FinTech Startup (illustrative example, not a real company)
**Industry:** Financial Services
**Use Case:** SQL query analysis in fraud detection system
**Previous Setup:** Java microservice with JSQLParser

### Problem
- Java service consuming 4GB RAM per instance
- Needed 10 instances to handle 500 queries/sec load
- JVM warmup delayed deployments (30+ seconds)
- High infrastructure costs ($1,000/month)

### Migration Process

#### Week 1-2: Development

**Before (JSQLParser):**
```java
// QueryAnalyzerService.java
@Service
public class QueryAnalyzerService {
    public QueryAnalysis analyze(String sql) throws Exception {
        Statement stmt = CCJSqlParserUtil.parse(sql);

        TablesNamesFinder finder = new TablesNamesFinder();
        List<String> tables = finder.getTableList(stmt);

        // Extract columns, analyze complexity...
        return new QueryAnalysis(tables, ...);
    }
}
```

**After (GoSQLX):**
```go
// query_analyzer.go
package analyzer

import (
    "github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer"
    "github.com/ajitpratap0/GoSQLX/pkg/models"
)

type QueryAnalysis struct {
    Tables []string
    // ... other fields
}

func Analyze(sql string) (*QueryAnalysis, error) {
    tkz := tokenizer.GetTokenizer()
    defer tokenizer.PutTokenizer(tkz)

    tokens, err := tkz.Tokenize([]byte(sql))
    if err != nil {
        return nil, err
    }

    tables := extractTables(tokens)

    return &QueryAnalysis{
        Tables: tables,
        // ... populate other fields
    }, nil
}

func extractTables(tokens []models.TokenWithSpan) []string {
    // Implementation...
    return []string{}
}
```

#### Week 3-4: Testing & Deployment

**Performance Results:**
```
Latency (p50):
  Before: 20ms (JSQLParser)
  After:  0.7ms (GoSQLX)
  Improvement: 28x faster

Throughput:
  Before: 50 queries/sec per instance
  After:  100,000+ queries/sec per instance
  Improvement: 2000x higher

Memory:
  Before: 4GB per instance
  After:  256MB per instance
  Improvement: 16x less

Instance Count:
  Before: 10 instances
  After:  1 instance
  Improvement: 10x fewer
```

**Cost Savings:**
```
Infrastructure:
  Before: $1,000/month (10 × c5.xlarge)
  After:  $50/month (1 × t3.medium)
  Savings: $950/month = $11,400/year

Developer Productivity:
  - Instant deployments (no JVM warmup)
  - Simpler codebase (fewer classes)
  - Faster local development
```

### Lessons Learned

1. **Go Learning Curve:** Team needed 1-2 weeks to learn Go basics
2. **API Simplicity:** GoSQLX's simpler API was easier to work with
3. **Testing:** Go's testing tools made testing easier than JUnit
4. **Deployment:** Single binary deployment was much simpler
5. **Performance:** Even exceeded expectations (27x faster!)

---

## Known Limitations

### Features Not Available in GoSQLX

#### 1. De-parser (SQL Generation from AST)
**JSQLParser Has:**
- Generate SQL string from modified AST
- Useful for query rewriting

**GoSQLX Status:**
- ❌ Not available yet
- ⏳ Planned for v2.0

**Workaround:**
Modify SQL as string before parsing, or keep JSQLParser for this use case.

#### 2. Fluent API for Building SQL
**JSQLParser Has:**
- Build SQL programmatically with Java objects
- Type-safe query construction

**GoSQLX Status:**
- ❌ Not available
- ⏳ Planned for v2.0

**Workaround:**
Use template strings or string builders:
```go
sql := fmt.Sprintf("SELECT %s FROM %s WHERE %s",
    strings.Join(columns, ", "), table, condition)
```

#### 3. Comprehensive PL/SQL Support
**JSQLParser Has:**
- Full Oracle PL/SQL parsing
- Stored procedure support

**GoSQLX Status:**
- ⚠️ Basic support only
- More coverage planned

#### 4. Helper Utilities
**JSQLParser Has:**
- TablesNamesFinder
- ColumnNamesFinder
- ExpressionDeParser
- Many built-in utilities

**GoSQLX Status:**
- ⚠️ Fewer helpers (simpler API)
- Developers implement as needed

**Example Implementation:**
See code examples above for table/column extraction.

---

## Getting Help

### Documentation
- **[GoSQLX Documentation](https://github.com/ajitpratap0/GoSQLX/blob/main/docs/README.md)** - Complete documentation
- **[Getting Started Guide](/docs/getting-started/)** - Quick start in 5 minutes
- **[Usage Guide](/docs/usage-guide/)** - Comprehensive patterns
- **[API Reference](/docs/reference/api/)** - Complete API documentation

### Community Support
- **[GitHub Issues](https://github.com/ajitpratap0/GoSQLX/issues)** - Report bugs or request features
- **[GitHub Discussions](https://github.com/ajitpratap0/GoSQLX/discussions)** - Ask questions
- **[Examples Directory](https://github.com/ajitpratap0/GoSQLX/tree/main/examples/)** - Real-world code examples

### Learning Go
- **[Go Tour](https://go.dev/tour/)** - Interactive Go tutorial
- **[Effective Go](https://go.dev/doc/effective_go)** - Go best practices
- **[Go by Example](https://gobyexample.com/)** - Practical Go examples

---

## Next Steps

### After Migration

1. **Monitor Performance**
   - Track latency improvements
   - Measure throughput gains
   - Document cost savings

2. **Optimize Go Code**
   - Profile with pprof
   - Use benchmarks to find bottlenecks
   - Apply Go best practices

3. **Contribute Back**
   - Share migration experiences
   - Contribute missing features
   - Help other Java developers migrate

---

## FAQ

### Q: Can I call JSQLParser from Go?
**A:** Yes, using cgo, but you lose the performance benefits. Better to fully migrate.

### Q: How do I handle the lack of de-parser?
**A:** For now, keep JSQLParser for SQL generation, or use Go templates/string building.

### Q: What about stored procedures?
**A:** GoSQLX has basic support. For complex PL/SQL, JSQLParser is more complete.

### Q: How do I learn Go quickly?
**A:** Take the [Go Tour](https://go.dev/tour/) (2-3 hours), then read [Effective Go](https://go.dev/doc/effective_go).

### Q: Is the performance gain real?
**A:** Yes! 27x faster parsing is reproducible. See benchmarks in [COMPARISON.md](https://github.com/ajitpratap0/GoSQLX/blob/main/docs/COMPARISON.md).

---

**Migration Time Estimate:** 4-6 weeks for typical project
**Performance Improvement:** 25-30x faster parsing
**Cost Savings:** Up to 95% reduction in infrastructure

**Ready to migrate?** Start with our [Getting Started Guide](/docs/getting-started/)!

---

**Maintained by:** GoSQLX Community
