-
Notifications
You must be signed in to change notification settings - Fork 3
Postgres #62
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
Draft
simukka
wants to merge
28
commits into
main
Choose a base branch
from
postgres
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Postgres #62
Changes from 6 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
fa05d57
Updated testing environment.
simukka 351a6dc
Working connection.
simukka b1b982d
Updated fixture to use pgx. Simplified how we introspect the DSN to d…
simukka 2d9462f
Wrote initial sqlcode migration for postgres.
simukka 6643158
Add security definer role.
simukka fd8c76f
[wip] working through changes for EnsureUploaded to support postgresql.
simukka b6681a2
Working EnsureUpload!
simukka da5b115
[wip] update parser and scanner
simukka 18309f0
Fixed issue with Preprocess. Passing pgsql tests.
simukka b651814
Updated GO workflow to test both drivers.
simukka 160df17
Fixed typo in GH workflow.
simukka 11659ed
Updated Dockerfile
simukka 37fd588
Use build tags to exclude examples from bulid & test
simukka ca444bc
Exclude example test
simukka c483fb7
Fixed failing test.
simukka 4b803bf
Moved Document structs to a separate file for better organization.
simukka f202e18
Updated go-mssql depedency to use microsoft fork. DropAndUpload now s…
simukka ad129b8
Initial unit tests for T-SQL syntax parsing.
simukka 352ed9f
Refactored to use a Document interface.
simukka 5e807d5
Renamed the existing Document struct to be specific for T-SQL.
simukka 494dca9
Created initial PGSqlDocument for PostgreSQL.
simukka 1f7b6b7
Updated unit test.
simukka af75628
Updated tests.
simukka 6916d34
Simplified Document interface. Created Pragma struct.
simukka 1a91556
[wip] pgsql document parsing
simukka fb56414
Simplify the interfaces for parsing a SQL document.
simukka 5e29dc9
Refactored pgsql document to use node parser.
simukka 6e114a9
[wip]
simukka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| test: test_mssql test_pgsql | ||
|
|
||
|
|
||
| test_mssql: | ||
| docker compose --progress plain -f docker-compose.mssql.yml run test | ||
|
|
||
| test_pgsql: | ||
| docker compose --progress plain -f docker-compose.pgsql.yml run test |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,11 +3,25 @@ package sqlcode | |
| import ( | ||
| "context" | ||
| "database/sql" | ||
|
|
||
| mssql "github.com/denisenkom/go-mssqldb" | ||
|
||
| "github.com/jackc/pgx/v5/stdlib" | ||
| ) | ||
|
|
||
| func Exists(ctx context.Context, dbc DB, schemasuffix string) (bool, error) { | ||
| var schemaID int | ||
| err := dbc.QueryRowContext(ctx, `select isnull(schema_id(@p1), 0)`, SchemaName(schemasuffix)).Scan(&schemaID) | ||
|
|
||
| driver := dbc.Driver() | ||
| var qs string | ||
|
|
||
| if _, ok := driver.(*mssql.Driver); ok { | ||
| qs = `select isnull(schema_id(@p1), 0)` | ||
| } | ||
| if _, ok := driver.(*stdlib.Driver); ok { | ||
| qs = `select coalesce((select oid from pg_namespace where nspname = $1),0)` | ||
| } | ||
|
|
||
| err := dbc.QueryRowContext(ctx, qs, SchemaName(schemasuffix)).Scan(&schemaID) | ||
| if err != nil { | ||
| return false, err | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,9 @@ import ( | |
| "time" | ||
|
|
||
| mssql "github.com/denisenkom/go-mssqldb" | ||
| "github.com/jackc/pgx/v5" | ||
| "github.com/jackc/pgx/v5/stdlib" | ||
| pgxstdlib "github.com/jackc/pgx/v5/stdlib" | ||
| "github.com/vippsas/sqlcode/sqlparser" | ||
| ) | ||
|
|
||
|
|
@@ -77,21 +80,22 @@ func impersonate(ctx context.Context, dbc DB, username string, f func(conn *sql. | |
| // Upload will create and upload the schema; resulting in an error | ||
| // if the schema already exists | ||
| func (d *Deployable) Upload(ctx context.Context, dbc DB) error { | ||
| // First, impersonate a user with minimal privileges to get at least | ||
| // some level of sandboxing so that migration scripts can't do anything | ||
| // the caller didn't expect them to. | ||
| return impersonate(ctx, dbc, "sqlcode-deploy-sandbox-user", func(conn *sql.Conn) error { | ||
| driver := dbc.Driver() | ||
| qs := make(map[string][]interface{}, 1) | ||
|
|
||
| var uploadFunc = func(conn *sql.Conn) error { | ||
| tx, err := conn.BeginTx(ctx, nil) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| _, err = tx.ExecContext(ctx, `sqlcode.CreateCodeSchema`, | ||
| sql.Named("schemasuffix", d.SchemaSuffix), | ||
| ) | ||
| if err != nil { | ||
| _ = tx.Rollback() | ||
| return err | ||
| for q, args := range qs { | ||
| _, err = tx.ExecContext(ctx, q, args...) | ||
|
|
||
| if err != nil { | ||
| _ = tx.Rollback() | ||
| return fmt.Errorf("failed to execute (%s) with arg(%s) in schema %s: %w", q, args, d.SchemaSuffix, err) | ||
| } | ||
| } | ||
|
|
||
| preprocessed, err := Preprocess(d.CodeBase, d.SchemaSuffix) | ||
|
|
@@ -123,8 +127,36 @@ func (d *Deployable) Upload(ctx context.Context, dbc DB) error { | |
|
|
||
| return nil | ||
|
|
||
| }) | ||
| } | ||
|
|
||
| if _, ok := driver.(*mssql.Driver); ok { | ||
| // First, impersonate a user with minimal privileges to get at least | ||
| // some level of sandboxing so that migration scripts can't do anything | ||
| // the caller didn't expect them to. | ||
| qs["sqlcode.CreateCodeSchema"] = []interface { | ||
| }{ | ||
| sql.Named("schemasuffix", d.SchemaSuffix), | ||
| } | ||
|
|
||
| return impersonate(ctx, dbc, "sqlcode-deploy-sandbox-user", uploadFunc) | ||
| } | ||
|
|
||
| if _, ok := driver.(*stdlib.Driver); ok { | ||
| qs[`set role "sqlcode-deploy-sandbox-user"`] = nil | ||
| qs[`call sqlcode.createcodeschema(@schemasuffix)`] = []interface{}{ | ||
| pgx.NamedArgs{"schemasuffix": d.SchemaSuffix}, | ||
| } | ||
| conn, err := dbc.Conn(ctx) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer func() { | ||
| _ = conn.Close() | ||
| }() | ||
| return uploadFunc(conn) | ||
| } | ||
|
|
||
| return fmt.Errorf("failed to determine sql driver to upload schema: %s", d.SchemaSuffix) | ||
| } | ||
|
|
||
| // EnsureUploaded checks that the schema with the suffix already exists, | ||
|
|
@@ -137,36 +169,51 @@ func (d *Deployable) EnsureUploaded(ctx context.Context, dbc DB) error { | |
| return nil | ||
| } | ||
|
|
||
| driver := dbc.Driver() | ||
| lockResourceName := "sqlcode.EnsureUploaded/" + d.SchemaSuffix | ||
|
|
||
| var lockRetCode int | ||
| var lockQs string | ||
| var unlockQs string | ||
| var err error | ||
|
|
||
| // When a lock is opened with the Transaction lock owner, | ||
| // that lock is released when the transaction is committed or rolled back. | ||
| var lockRetCode int | ||
| err := dbc.QueryRowContext(ctx, ` | ||
| declare @retcode int; | ||
| exec @retcode = sp_getapplock @Resource = @resource, @LockMode = 'Shared', @LockOwner = 'Session', @LockTimeout = @timeoutMs; | ||
| select @retcode; | ||
| `, | ||
| sql.Named("resource", lockResourceName), | ||
| sql.Named("timeoutMs", 20000), | ||
| ).Scan(&lockRetCode) | ||
| if _, ok := driver.(*pgxstdlib.Driver); ok { | ||
| lockQs = `select sqlcode.get_applock(@resource, @timeout)` | ||
| unlockQs = `select sqlcode.release_applock(@resource)` | ||
|
|
||
| err = dbc.QueryRowContext(ctx, lockQs, pgx.NamedArgs{ | ||
| "resource": lockResourceName, | ||
| "timeoutMs": 20000, | ||
| }).Scan(&lockRetCode) | ||
|
|
||
| defer func() { | ||
| dbc.ExecContext(ctx, unlockQs, pgx.NamedArgs{"resource": lockResourceName}) | ||
| }() | ||
| } | ||
|
|
||
| if _, ok := driver.(*mssql.Driver); ok { | ||
| // TODO | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Add back the mssql sql to lock on upload. |
||
|
|
||
| defer func() { | ||
| // TODO: This returns an error if the lock is already released | ||
| _, _ = dbc.ExecContext(ctx, unlockQs, | ||
| sql.Named("Resource", lockResourceName), | ||
| sql.Named("LockOwner", "Session"), | ||
| ) | ||
| }() | ||
| } | ||
|
|
||
| if err != nil { | ||
| return err | ||
| } | ||
| if lockRetCode < 0 { | ||
| return errors.New("was not able to get lock before timeout") | ||
| } | ||
|
|
||
| defer func() { | ||
| _, _ = dbc.ExecContext(ctx, `sp_releaseapplock`, | ||
| sql.Named("Resource", lockResourceName), | ||
| sql.Named("LockOwner", "Session"), | ||
| ) | ||
| }() | ||
|
|
||
| exists, err := Exists(ctx, dbc, d.SchemaSuffix) | ||
| if err != nil { | ||
| return err | ||
| return fmt.Errorf("unable to determine if schema %s exists: %w", d.SchemaSuffix, err) | ||
| } | ||
|
|
||
| if exists { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| services: | ||
| mssql: | ||
| image: mcr.microsoft.com/mssql/server:latest | ||
| networks: | ||
| - mssql | ||
| environment: | ||
| ACCEPT_EULA: "Y" | ||
| SA_PASSWORD: VippsPw1 | ||
| healthcheck: | ||
| test: ["CMD", "/opt/mssql-tools18/bin/sqlcmd", "-C", "-Usa", "-PVippsPw1", "-Q", "select 1"] | ||
| interval: 1s | ||
| retries: 20 | ||
| test: | ||
| build: | ||
| dockerfile: dockerfile.test | ||
| networks: | ||
| - mssql | ||
| environment: | ||
| SQLSERVER_DSN: sqlserver://mssql:1433?database=master&user id=sa&password=VippsPw1 | ||
| SQLSERVER_DRIVER: sqlserver | ||
| depends_on: | ||
| mssql: | ||
| condition: service_healthy | ||
| networks: | ||
| mssql: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| services: | ||
| postgres: | ||
| image: postgres | ||
| networks: | ||
| - postgres | ||
| environment: | ||
| POSTGRES_PASSWORD: VippsPw1 | ||
| POSTGRES_USER: sa | ||
| POSTGRES_DB: master | ||
| PGOPTIONS: "-c log_error_verbosity=verbose -c log_statement=all" | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "pg_isready", "-d", "db_prod"] | ||
| interval: 1s | ||
| retries: 20 | ||
| test: | ||
| build: | ||
| dockerfile: dockerfile.test | ||
| networks: | ||
| - postgres | ||
| environment: | ||
| SQLSERVER_DSN: postgresql://sa:VippsPw1@postgres:5432/master?sslmode=disable | ||
| GODEBUG: "x509negativeserial=1" | ||
| depends_on: | ||
| postgres: | ||
| condition: service_healthy | ||
| networks: | ||
| postgres: |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| FROM golang:1.25.1 AS builder | ||
| WORKDIR /sqlcode | ||
| ENV GODEBUG="x509negativeserial=1" | ||
| COPY . . | ||
| RUN go mod tidy | ||
| CMD ["go", "test", "-v", "$(go list ./... | grep -v './example')"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a required interface for sql.DB and shouldn't be too much of a hassle to support in internal libraries.