From d11a1e71a570fb6b11c371f6104d028387166b88 Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Wed, 6 May 2026 17:37:46 +0200 Subject: [PATCH 01/12] Adding first impl. with buff --- tools/client-generation/.gitignore | 18 +++ tools/client-generation/README.md | 31 +++++ tools/client-generation/buf.gen.go.yaml | 24 ++++ tools/client-generation/buf.gen.openapi.yaml | 16 +++ tools/client-generation/buf.gen.rust.yaml | 9 ++ .../client-generation/buf.gen.typescript.yaml | 20 +++ tools/client-generation/buf.gen.yaml | 48 +++++++ tools/client-generation/buf.yaml | 15 ++ tools/client-generation/example/go/go.mod | 16 +++ tools/client-generation/example/go/main.go | 89 ++++++++++++ .../client-generation/example/rust/Cargo.toml | 10 ++ .../example/rust/src/main.rs | 131 ++++++++++++++++++ .../example/typescript/package.json | 18 +++ .../example/typescript/src/index.ts | 77 ++++++++++ .../example/typescript/tsconfig.json | 14 ++ tools/client-generation/generate-clients.ps1 | 104 ++++++++++++++ tools/client-generation/generate-clients.sh | 89 ++++++++++++ 17 files changed, 729 insertions(+) create mode 100644 tools/client-generation/.gitignore create mode 100644 tools/client-generation/README.md create mode 100644 tools/client-generation/buf.gen.go.yaml create mode 100644 tools/client-generation/buf.gen.openapi.yaml create mode 100644 tools/client-generation/buf.gen.rust.yaml create mode 100644 tools/client-generation/buf.gen.typescript.yaml create mode 100644 tools/client-generation/buf.gen.yaml create mode 100644 tools/client-generation/buf.yaml create mode 100644 tools/client-generation/example/go/go.mod create mode 100644 tools/client-generation/example/go/main.go create mode 100644 tools/client-generation/example/rust/Cargo.toml create mode 100644 tools/client-generation/example/rust/src/main.rs create mode 100644 tools/client-generation/example/typescript/package.json create mode 100644 tools/client-generation/example/typescript/src/index.ts create mode 100644 tools/client-generation/example/typescript/tsconfig.json create mode 100644 tools/client-generation/generate-clients.ps1 create mode 100644 tools/client-generation/generate-clients.sh diff --git a/tools/client-generation/.gitignore b/tools/client-generation/.gitignore new file mode 100644 index 000000000..e88222b1e --- /dev/null +++ b/tools/client-generation/.gitignore @@ -0,0 +1,18 @@ +# Buf temporary work dirs +.buf-tmp-gen/ +.buf-workspace/ + +# Downloaded JDBC libs for local docker stack +ojp-libs/ + +# Generated artifacts from example runners +example/go/gen/ +example/rust/generated/ + +# Rust build output +example/rust/target/ + +# TypeScript example build output +example/typescript/generated/ +example/typescript/dist/ +example/typescript/node_modules/ diff --git a/tools/client-generation/README.md b/tools/client-generation/README.md new file mode 100644 index 000000000..b3cbc8c52 --- /dev/null +++ b/tools/client-generation/README.md @@ -0,0 +1,31 @@ +# gRPC Client Generation + +This folder contains Buf-based generation for external clients. +for **Rust**, **Go**, **TypeScript** +This spec can easly be enhanced for your Program Language. + +## Prerequisite + +- Install `buf`: https://buf.build/docs/installation/ + +## Bash + +```bash +./tools/client-generation/generate-clients.sh +``` + +or PowerShell + +```powershell +.\tools\client-generation\generate-clients.ps1 -Target -OutputDir +``` +Examples: + +```bash +./tools/client-generation/generate-clients.sh go /tmp/ojp-go-client +./tools/client-generation/generate-clients.sh rust /tmp/ojp-rust-client +./tools/client-generation/generate-clients.sh openapi /tmp/ojp-typescript-client +./tools/client-generation/generate-clients.sh openapi /tmp/ojp-openapi +``` + + diff --git a/tools/client-generation/buf.gen.go.yaml b/tools/client-generation/buf.gen.go.yaml new file mode 100644 index 000000000..715782ac3 --- /dev/null +++ b/tools/client-generation/buf.gen.go.yaml @@ -0,0 +1,24 @@ +version: v2 +clean: true + +managed: + enabled: false + +plugins: + - remote: buf.build/protocolbuffers/go:v1.36.11 + out: gen/go + opt: + - paths=import + - module=github.com/open-j-proxy/ojp-client + - MStatementService.proto=github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc + - Mecho.proto=github.com/open-j-proxy/ojp-client/gen/go/org/openjproxy/grpc + - Mcontainers.proto=github.com/open-j-proxy/ojp-client/gen/go/ojp/transport/v1 + + - remote: buf.build/grpc/go:v1.6.1 + out: gen/go + opt: + - paths=import + - module=github.com/open-j-proxy/ojp-client + - MStatementService.proto=github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc + - Mecho.proto=github.com/open-j-proxy/ojp-client/gen/go/org/openjproxy/grpc + - Mcontainers.proto=github.com/open-j-proxy/ojp-client/gen/go/ojp/transport/v1 diff --git a/tools/client-generation/buf.gen.openapi.yaml b/tools/client-generation/buf.gen.openapi.yaml new file mode 100644 index 000000000..395a88d32 --- /dev/null +++ b/tools/client-generation/buf.gen.openapi.yaml @@ -0,0 +1,16 @@ +version: v2 +clean: true + +managed: + enabled: false + +plugins: + - remote: buf.build/grpc-ecosystem/openapiv2:v2.29.0 + out: gen/openapi + opt: + - generate_unbound_methods=true + - allow_merge=true + - merge_file_name=ojp + - MStatementService.proto=github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc + - Mecho.proto=github.com/open-j-proxy/ojp-client/gen/go/org/openjproxy/grpc + - Mcontainers.proto=github.com/open-j-proxy/ojp-client/gen/go/ojp/transport/v1 diff --git a/tools/client-generation/buf.gen.rust.yaml b/tools/client-generation/buf.gen.rust.yaml new file mode 100644 index 000000000..c541b0ee1 --- /dev/null +++ b/tools/client-generation/buf.gen.rust.yaml @@ -0,0 +1,9 @@ +version: v2 +clean: true + +managed: + enabled: false + +plugins: + - remote: buf.build/community/neoeinstein-prost:v0.5.0 + out: gen/rust diff --git a/tools/client-generation/buf.gen.typescript.yaml b/tools/client-generation/buf.gen.typescript.yaml new file mode 100644 index 000000000..dddee2dd3 --- /dev/null +++ b/tools/client-generation/buf.gen.typescript.yaml @@ -0,0 +1,20 @@ +version: v2 +clean: true + +managed: + enabled: false + +plugins: + # TypeScript/JavaScript protobuf base types. + - remote: buf.build/bufbuild/es:v1.10.0 + out: gen/typescript + opt: + - target=ts + - import_extension=none + + # Connect client generation (replacement for deprecated connectrpc/es). + - remote: buf.build/bufbuild/connect-es:v0.13.0 + out: gen/typescript + opt: + - target=ts + - import_extension=none diff --git a/tools/client-generation/buf.gen.yaml b/tools/client-generation/buf.gen.yaml new file mode 100644 index 000000000..6c1c95219 --- /dev/null +++ b/tools/client-generation/buf.gen.yaml @@ -0,0 +1,48 @@ +version: v2 +clean: true + +managed: + # Keep managed mode disabled because we provide explicit M-file mappings below. + # This avoids accidental import/package rewrites for existing OJP proto files. + enabled: false + +plugins: + # Go protobuf messages. + # `module` ensures generated files are rooted under this Go module path. + # Mappings are required because source protos do not declare go_package. + - remote: buf.build/protocolbuffers/go:v1.36.11 + out: gen/go + opt: + - paths=import + - module=github.com/open-j-proxy/ojp-client + - MStatementService.proto=github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc + - Mecho.proto=github.com/open-j-proxy/ojp-client/gen/go/org/openjproxy/grpc + - Mcontainers.proto=github.com/open-j-proxy/ojp-client/gen/go/ojp/transport/v1 + + # Go gRPC stubs. + - remote: buf.build/grpc/go:v1.6.1 + out: gen/go + opt: + - paths=import + - module=github.com/open-j-proxy/ojp-client + - MStatementService.proto=github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc + - Mecho.proto=github.com/open-j-proxy/ojp-client/gen/go/org/openjproxy/grpc + - Mcontainers.proto=github.com/open-j-proxy/ojp-client/gen/go/ojp/transport/v1 + + # Rust protobuf messages (prost). + # This generates Rust message types; service-client wiring is handled by the Rust example. + - remote: buf.build/community/neoeinstein-prost:v0.5.0 + out: gen/rust + + # OpenAPI spec generation from gRPC services. + # `generate_unbound_methods=true` is used because proto files currently do not + # define google.api.http annotations for REST path bindings. + - remote: buf.build/grpc-ecosystem/openapiv2:v2.29.0 + out: gen/openapi + opt: + - generate_unbound_methods=true + - allow_merge=true + - merge_file_name=ojp + - MStatementService.proto=github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc + - Mecho.proto=github.com/open-j-proxy/ojp-client/gen/go/org/openjproxy/grpc + - Mcontainers.proto=github.com/open-j-proxy/ojp-client/gen/go/ojp/transport/v1 diff --git a/tools/client-generation/buf.yaml b/tools/client-generation/buf.yaml new file mode 100644 index 000000000..a09fabb6f --- /dev/null +++ b/tools/client-generation/buf.yaml @@ -0,0 +1,15 @@ +version: v2 + +modules: + - path: . + +deps: + - buf.build/googleapis/googleapis + +lint: + use: + - STANDARD + +breaking: + use: + - FILE diff --git a/tools/client-generation/example/go/go.mod b/tools/client-generation/example/go/go.mod new file mode 100644 index 000000000..019462bf8 --- /dev/null +++ b/tools/client-generation/example/go/go.mod @@ -0,0 +1,16 @@ +module github.com/open-j-proxy/ojp-client + +go 1.25.3 + +require ( + google.golang.org/genproto v0.0.0-20260504160031-60b97b32f348 + google.golang.org/grpc v1.81.0 + google.golang.org/protobuf v1.36.11 +) + +require ( + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 // indirect +) diff --git a/tools/client-generation/example/go/main.go b/tools/client-generation/example/go/main.go new file mode 100644 index 000000000..3d0f807d8 --- /dev/null +++ b/tools/client-generation/example/go/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "context" + "fmt" + "io" + "log" + "os" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + pb "github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc" +) + +func main() { + addr := env("OJP_ADDR", "127.0.0.1:1059") + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://postgres:5432/ojp") + dbUser := env("OJP_DB_USER", "ojp") + dbPassword := env("OJP_DB_PASSWORD", "ojp") + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + conn, err := grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("dial failed: %v", err) + } + defer conn.Close() + + client := pb.NewStatementServiceClient(conn) + + connectResp, err := client.Connect(ctx, &pb.ConnectionDetails{ + Url: backendURL, + User: dbUser, + Password: dbPassword, + ClientUUID: "go-example-client", + }) + if err != nil { + log.Fatalf("connect failed: %v", err) + } + + updateReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", + } + if _, err = client.ExecuteUpdate(ctx, updateReq); err != nil { + log.Fatalf("create table failed: %v", err) + } + + insertReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "INSERT INTO demo(id, name) VALUES (1, 'hello from go') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", + } + if _, err = client.ExecuteUpdate(ctx, insertReq); err != nil { + log.Fatalf("insert failed: %v", err) + } + + queryReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "SELECT id, name FROM demo ORDER BY id", + } + stream, err := client.ExecuteQuery(ctx, queryReq) + if err != nil { + log.Fatalf("executeQuery failed: %v", err) + } + + for { + msg, recvErr := stream.Recv() + if recvErr == io.EOF { + break + } + if recvErr != nil { + log.Fatalf("stream recv failed: %v", recvErr) + } + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) + } + + _, _ = client.TerminateSession(context.Background(), connectResp) +} + +func env(name, fallback string) string { + v := os.Getenv(name) + if v == "" { + return fallback + } + return v +} diff --git a/tools/client-generation/example/rust/Cargo.toml b/tools/client-generation/example/rust/Cargo.toml new file mode 100644 index 000000000..d73e2aeee --- /dev/null +++ b/tools/client-generation/example/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ojp-rust-example" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { version = "1", features = ["macros", "rt-multi-thread"] } +tonic = { version = "0.12", features = ["transport"] } +prost = "0.13" +prost-types = "0.13" diff --git a/tools/client-generation/example/rust/src/main.rs b/tools/client-generation/example/rust/src/main.rs new file mode 100644 index 000000000..994c69dc9 --- /dev/null +++ b/tools/client-generation/example/rust/src/main.rs @@ -0,0 +1,131 @@ +use std::env; + +use tonic::codegen::http::uri::PathAndQuery; +use tonic::transport::Channel; +use tonic::{codec::ProstCodec, Request}; + +mod google { + pub mod r#type { + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Date { + #[prost(int32, tag = "1")] + pub year: i32, + #[prost(int32, tag = "2")] + pub month: i32, + #[prost(int32, tag = "3")] + pub day: i32, + } + + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct TimeOfDay { + #[prost(int32, tag = "1")] + pub hours: i32, + #[prost(int32, tag = "2")] + pub minutes: i32, + #[prost(int32, tag = "3")] + pub seconds: i32, + #[prost(int32, tag = "4")] + pub nanos: i32, + } + } +} + +mod com { + pub mod openjproxy { + pub mod grpc { + include!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/generated/com/openjproxy/grpc/com.openjproxy.grpc.rs" + )); + } + } +} + +use com::openjproxy::grpc::{ConnectionDetails, SessionInfo, StatementRequest}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let addr = env::var("OJP_ADDR").unwrap_or_else(|_| "127.0.0.1:1059".to_string()); + let backend_url = + env::var("OJP_BACKEND_URL").unwrap_or_else(|_| "jdbc:postgresql://postgres:5432/ojp".to_string()); + let db_user = env::var("OJP_DB_USER").unwrap_or_else(|_| "ojp".to_string()); + let db_password = env::var("OJP_DB_PASSWORD").unwrap_or_else(|_| "ojp".to_string()); + + let endpoint = format!("http://{addr}"); + let channel = Channel::from_shared(endpoint)?.connect().await?; + let mut grpc = tonic::client::Grpc::new(channel); + let codec = ProstCodec::default(); + + let connect_path = PathAndQuery::from_static("/com.openjproxy.grpc.StatementService/connect"); + let connect_req = ConnectionDetails { + url: backend_url, + user: db_user, + password: db_password, + client_uuid: "rust-example-client".to_string(), + properties: vec![], + is_xa: false, + server_endpoints: vec![], + cluster_health: String::new(), + }; + let session = grpc + .unary(Request::new(connect_req), connect_path, codec.clone()) + .await? + .into_inner(); + + execute_update( + &mut grpc, + &codec, + &session, + "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", + ) + .await?; + + execute_update( + &mut grpc, + &codec, + &session, + "INSERT INTO demo(id, name) VALUES (2, 'hello from rust') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", + ) + .await?; + + let query_path = PathAndQuery::from_static("/com.openjproxy.grpc.StatementService/executeQuery"); + let query_req = StatementRequest { + session: Some(session.clone()), + sql: "SELECT id, name FROM demo ORDER BY id".to_string(), + parameters: vec![], + statement_uuid: String::new(), + properties: vec![], + }; + let mut stream = grpc + .server_streaming(Request::new(query_req), query_path, codec.clone()) + .await? + .into_inner(); + while let Some(item) = stream.message().await? { + println!("op_result type={} uuid={}", item.r#type, item.uuid); + } + + let terminate_path = PathAndQuery::from_static("/com.openjproxy.grpc.StatementService/terminateSession"); + let _ = grpc + .unary(Request::new(session), terminate_path, codec) + .await?; + + Ok(()) +} + +async fn execute_update( + grpc: &mut tonic::client::Grpc, + codec: &ProstCodec, + session: &SessionInfo, + sql: &str, +) -> Result<(), Box> { + let path = PathAndQuery::from_static("/com.openjproxy.grpc.StatementService/executeUpdate"); + let req = StatementRequest { + session: Some(session.clone()), + sql: sql.to_string(), + parameters: vec![], + statement_uuid: String::new(), + properties: vec![], + }; + let _ = grpc.unary(Request::new(req), path, codec.clone()).await?; + Ok(()) +} diff --git a/tools/client-generation/example/typescript/package.json b/tools/client-generation/example/typescript/package.json new file mode 100644 index 000000000..7d25caa27 --- /dev/null +++ b/tools/client-generation/example/typescript/package.json @@ -0,0 +1,18 @@ +{ + "name": "ojp-typescript-example", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "tsc -p tsconfig.json", + "start": "node dist/index.js" + }, + "dependencies": { + "@bufbuild/protobuf": "^1.10.0", + "@connectrpc/connect": "^1.6.1", + "@connectrpc/connect-node": "^1.6.1" + }, + "devDependencies": { + "@types/node": "^22.18.6", + "typescript": "^5.9.3" + } +} diff --git a/tools/client-generation/example/typescript/src/index.ts b/tools/client-generation/example/typescript/src/index.ts new file mode 100644 index 000000000..ff03a7d09 --- /dev/null +++ b/tools/client-generation/example/typescript/src/index.ts @@ -0,0 +1,77 @@ +import { createPromiseClient } from "@connectrpc/connect"; +import { createGrpcTransport } from "@connectrpc/connect-node"; + +import { StatementService } from "../generated/StatementService_connect"; +import { ConnectionDetails, StatementRequest } from "../generated/StatementService_pb"; + +function env(name: string, fallback: string): string { + return process.env[name] ?? fallback; +} + +async function main(): Promise { + const addr = env("OJP_ADDR", "http://127.0.0.1:1059"); + const backendUrl = env("OJP_BACKEND_URL", "jdbc:postgresql://postgres:5432/ojp"); + const dbUser = env("OJP_DB_USER", "ojp"); + const dbPassword = env("OJP_DB_PASSWORD", "ojp"); + + const transport = createGrpcTransport({ + baseUrl: addr, + httpVersion: "2", + }); + + const client = createPromiseClient(StatementService, transport); + + const session = await client.connect( + new ConnectionDetails({ + url: backendUrl, + user: dbUser, + password: dbPassword, + clientUUID: "typescript-example-client", + properties: [], + isXA: false, + serverEndpoints: [], + clusterHealth: "", + }), + ); + + await client.executeUpdate( + new StatementRequest({ + session, + sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", + parameters: [], + statementUUID: "", + properties: [], + }), + ); + + await client.executeUpdate( + new StatementRequest({ + session, + sql: "INSERT INTO demo(id, name) VALUES (3, 'hello from typescript') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", + parameters: [], + statementUUID: "", + properties: [], + }), + ); + + const stream = client.executeQuery( + new StatementRequest({ + session, + sql: "SELECT id, name FROM demo ORDER BY id", + parameters: [], + statementUUID: "", + properties: [], + }), + ); + + for await (const op of stream) { + console.log(`opResult type=${op.type} uuid=${op.uuid}`); + } + + await client.terminateSession(session); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/tools/client-generation/example/typescript/tsconfig.json b/tools/client-generation/example/typescript/tsconfig.json new file mode 100644 index 000000000..cfff35083 --- /dev/null +++ b/tools/client-generation/example/typescript/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "Node", + "strict": true, + "outDir": "dist", + "skipLibCheck": true + }, + "include": [ + "src/**/*.ts", + "generated/**/*.ts" + ] +} diff --git a/tools/client-generation/generate-clients.ps1 b/tools/client-generation/generate-clients.ps1 new file mode 100644 index 000000000..eb41b991a --- /dev/null +++ b/tools/client-generation/generate-clients.ps1 @@ -0,0 +1,104 @@ +param( + [Parameter(Mandatory = $true)] + [ValidateSet("go", "rust", "openapi", "typescript", "all")] + [string]$Target, + + [Parameter(Mandatory = $true)] + [string]$OutputDir +) + +$ErrorActionPreference = "Stop" + +function Invoke-Checked { + param([scriptblock]$Script) + & $Script + if ($LASTEXITCODE -ne 0) { + throw "Command failed with exit code $LASTEXITCODE" + } +} + +if (-not (Get-Command buf -ErrorAction SilentlyContinue)) { + throw "buf CLI is required. Install from https://buf.build/docs/installation/" +} + +$toolDir = Resolve-Path $PSScriptRoot +$stagingDir = Join-Path $toolDir ".buf-tmp-gen" +$workspaceDir = Join-Path $toolDir ".buf-workspace" +$repoProtoDir = Resolve-Path (Join-Path $toolDir "..\..\ojp-grpc-commons\src\main\proto") + +if (Test-Path $stagingDir) { + Remove-Item -Recurse -Force $stagingDir +} +New-Item -ItemType Directory -Path $stagingDir | Out-Null +if (Test-Path $workspaceDir) { + Remove-Item -Recurse -Force $workspaceDir +} +New-Item -ItemType Directory -Path $workspaceDir | Out-Null + +$workspaceProtoDir = Join-Path $workspaceDir "proto" +New-Item -ItemType Directory -Path $workspaceProtoDir | Out-Null +Copy-Item -Recurse -Force (Join-Path $repoProtoDir "*") $workspaceProtoDir + +$workspaceBufYaml = @" +version: v2 +modules: + - path: proto +deps: + - buf.build/googleapis/googleapis +lint: + use: + - STANDARD +breaking: + use: + - FILE +"@ +Set-Content -Path (Join-Path $workspaceDir "buf.yaml") -Value $workspaceBufYaml -NoNewline + +Push-Location $toolDir +try { + $templatePath = switch ($Target) { + "go" { Join-Path $toolDir "buf.gen.go.yaml" } + "rust" { Join-Path $toolDir "buf.gen.rust.yaml" } + "openapi" { Join-Path $toolDir "buf.gen.openapi.yaml" } + "typescript" { Join-Path $toolDir "buf.gen.typescript.yaml" } + default { Join-Path $toolDir "buf.gen.yaml" } + } + + Invoke-Checked { buf dep update $workspaceDir } + if ($Target -eq "typescript") { + Invoke-Checked { buf generate $workspaceDir --template $templatePath --output $stagingDir --include-imports } + } else { + Invoke-Checked { buf generate $workspaceDir --template $templatePath --output $stagingDir } + } + + $resolvedOutput = Resolve-Path -Path (New-Item -ItemType Directory -Force -Path $OutputDir).FullName + + switch ($Target) { + "go" { + Copy-Item -Recurse -Force (Join-Path $stagingDir "gen\\go\\*") $resolvedOutput + } + "rust" { + Copy-Item -Recurse -Force (Join-Path $stagingDir "gen\\rust\\*") $resolvedOutput + } + "openapi" { + Copy-Item -Recurse -Force (Join-Path $stagingDir "gen\\openapi\\*") $resolvedOutput + } + "typescript" { + Copy-Item -Recurse -Force (Join-Path $stagingDir "gen\\typescript\\*") $resolvedOutput + } + "all" { + Copy-Item -Recurse -Force (Join-Path $stagingDir "gen\\*") $resolvedOutput + } + } +} +finally { + Pop-Location + if (Test-Path $stagingDir) { + Remove-Item -Recurse -Force $stagingDir + } + if (Test-Path $workspaceDir) { + Remove-Item -Recurse -Force $workspaceDir + } +} + +Write-Host "Generation completed for target '$Target' into: $resolvedOutput" diff --git a/tools/client-generation/generate-clients.sh b/tools/client-generation/generate-clients.sh new file mode 100644 index 000000000..f7f3aab5a --- /dev/null +++ b/tools/client-generation/generate-clients.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 2 ]]; then + echo "Usage: $0 " + exit 1 +fi + +TARGET="$1" +OUTPUT_DIR="$2" + +case "$TARGET" in + go|rust|openapi|typescript|all) ;; + *) + echo "Invalid target: $TARGET (expected: go|rust|openapi|typescript|all)" + exit 1 + ;; +esac + +if ! command -v buf >/dev/null 2>&1; then + echo "buf CLI is required. Install from https://buf.build/docs/installation/" + exit 1 +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +STAGING_DIR="$SCRIPT_DIR/.buf-tmp-gen" +WORKSPACE_DIR="$SCRIPT_DIR/.buf-workspace" +REPO_PROTO_DIR="$SCRIPT_DIR/../../ojp-grpc-commons/src/main/proto" + +rm -rf "$STAGING_DIR" +rm -rf "$WORKSPACE_DIR" +mkdir -p "$STAGING_DIR" +mkdir -p "$WORKSPACE_DIR/proto" +mkdir -p "$OUTPUT_DIR" + +cp -R "$REPO_PROTO_DIR/." "$WORKSPACE_DIR/proto/" + +cat > "$WORKSPACE_DIR/buf.yaml" <<'EOF' +version: v2 +modules: + - path: proto +deps: + - buf.build/googleapis/googleapis +lint: + use: + - STANDARD +breaking: + use: + - FILE +EOF + +cd "$SCRIPT_DIR" +TEMPLATE="$SCRIPT_DIR/buf.gen.yaml" +case "$TARGET" in + go) TEMPLATE="$SCRIPT_DIR/buf.gen.go.yaml" ;; + rust) TEMPLATE="$SCRIPT_DIR/buf.gen.rust.yaml" ;; + openapi) TEMPLATE="$SCRIPT_DIR/buf.gen.openapi.yaml" ;; + typescript) TEMPLATE="$SCRIPT_DIR/buf.gen.typescript.yaml" ;; + all) TEMPLATE="$SCRIPT_DIR/buf.gen.yaml" ;; +esac + +buf dep update "$WORKSPACE_DIR" +if [[ "$TARGET" == "typescript" ]]; then + buf generate "$WORKSPACE_DIR" --template "$TEMPLATE" --output "$STAGING_DIR" --include-imports +else + buf generate "$WORKSPACE_DIR" --template "$TEMPLATE" --output "$STAGING_DIR" +fi + +case "$TARGET" in + go) + cp -R "$STAGING_DIR/gen/go/." "$OUTPUT_DIR/" + ;; + rust) + cp -R "$STAGING_DIR/gen/rust/." "$OUTPUT_DIR/" + ;; + openapi) + cp -R "$STAGING_DIR/gen/openapi/." "$OUTPUT_DIR/" + ;; + typescript) + cp -R "$STAGING_DIR/gen/typescript/." "$OUTPUT_DIR/" + ;; + all) + cp -R "$STAGING_DIR/gen/." "$OUTPUT_DIR/" + ;; +esac + +rm -rf "$STAGING_DIR" +rm -rf "$WORKSPACE_DIR" +echo "Generation completed for target '$TARGET' into: $OUTPUT_DIR" From 83f2a79112a23536851309a0da2ec4c8b43a55c0 Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Wed, 6 May 2026 21:07:43 +0200 Subject: [PATCH 02/12] update go client --- ojp-grpc-client-go/main.go | 89 +++++++++++++++++++++ tools/client-generation/example/go/go.mod | 16 ++-- tools/client-generation/example/go/go.sum | 16 ++++ tools/client-generation/example/go/main.go | 48 +++++------ tools/client-generation/generate-clients.sh | 0 5 files changed, 138 insertions(+), 31 deletions(-) create mode 100644 ojp-grpc-client-go/main.go create mode 100644 tools/client-generation/example/go/go.sum mode change 100644 => 100755 tools/client-generation/generate-clients.sh diff --git a/ojp-grpc-client-go/main.go b/ojp-grpc-client-go/main.go new file mode 100644 index 000000000..3d0f807d8 --- /dev/null +++ b/ojp-grpc-client-go/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "context" + "fmt" + "io" + "log" + "os" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + pb "github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc" +) + +func main() { + addr := env("OJP_ADDR", "127.0.0.1:1059") + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://postgres:5432/ojp") + dbUser := env("OJP_DB_USER", "ojp") + dbPassword := env("OJP_DB_PASSWORD", "ojp") + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + conn, err := grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("dial failed: %v", err) + } + defer conn.Close() + + client := pb.NewStatementServiceClient(conn) + + connectResp, err := client.Connect(ctx, &pb.ConnectionDetails{ + Url: backendURL, + User: dbUser, + Password: dbPassword, + ClientUUID: "go-example-client", + }) + if err != nil { + log.Fatalf("connect failed: %v", err) + } + + updateReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", + } + if _, err = client.ExecuteUpdate(ctx, updateReq); err != nil { + log.Fatalf("create table failed: %v", err) + } + + insertReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "INSERT INTO demo(id, name) VALUES (1, 'hello from go') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", + } + if _, err = client.ExecuteUpdate(ctx, insertReq); err != nil { + log.Fatalf("insert failed: %v", err) + } + + queryReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "SELECT id, name FROM demo ORDER BY id", + } + stream, err := client.ExecuteQuery(ctx, queryReq) + if err != nil { + log.Fatalf("executeQuery failed: %v", err) + } + + for { + msg, recvErr := stream.Recv() + if recvErr == io.EOF { + break + } + if recvErr != nil { + log.Fatalf("stream recv failed: %v", recvErr) + } + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) + } + + _, _ = client.TerminateSession(context.Background(), connectResp) +} + +func env(name, fallback string) string { + v := os.Getenv(name) + if v == "" { + return fallback + } + return v +} diff --git a/tools/client-generation/example/go/go.mod b/tools/client-generation/example/go/go.mod index 019462bf8..aac32f54c 100644 --- a/tools/client-generation/example/go/go.mod +++ b/tools/client-generation/example/go/go.mod @@ -1,16 +1,16 @@ module github.com/open-j-proxy/ojp-client -go 1.25.3 +go 1.22 require ( - google.golang.org/genproto v0.0.0-20260504160031-60b97b32f348 - google.golang.org/grpc v1.81.0 - google.golang.org/protobuf v1.36.11 + google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 + google.golang.org/grpc v1.64.0 + google.golang.org/protobuf v1.33.0 ) require ( - golang.org/x/net v0.52.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/text v0.35.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260427160629-7cedc36a6bc4 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect ) diff --git a/tools/client-generation/example/go/go.sum b/tools/client-generation/example/go/go.sum new file mode 100644 index 000000000..2e0adb7be --- /dev/null +++ b/tools/client-generation/example/go/go.sum @@ -0,0 +1,16 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 h1:PgNlNSx2Nq2/j4juYzQBG0/Zdr+WP4z5N01Vk4VYBCY= +google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237/go.mod h1:9sVD8c25Af3p0rGs7S7LLsxWKFiJt/65LdSyqXBkX/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/tools/client-generation/example/go/main.go b/tools/client-generation/example/go/main.go index 3d0f807d8..de94111c5 100644 --- a/tools/client-generation/example/go/main.go +++ b/tools/client-generation/example/go/main.go @@ -8,10 +8,9 @@ import ( "os" "time" + grpcclient "github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - - pb "github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc" ) func main() { @@ -23,15 +22,17 @@ func main() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() + log.Printf("Connecting to OJP server at %s", addr) conn, err := grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("dial failed: %v", err) } defer conn.Close() - client := pb.NewStatementServiceClient(conn) + client := grpcclient.NewStatementServiceClient(conn) - connectResp, err := client.Connect(ctx, &pb.ConnectionDetails{ + log.Printf("Connecting to database: %s", backendURL) + connectResp, err := client.Connect(ctx, &grpcclient.ConnectionDetails{ Url: backendURL, User: dbUser, Password: dbPassword, @@ -40,50 +41,51 @@ func main() { if err != nil { log.Fatalf("connect failed: %v", err) } + log.Printf("Connected! Session: %s", connectResp.SessionUUID) - updateReq := &pb.StatementRequest{ + if _, err = client.ExecuteUpdate(ctx, &grpcclient.StatementRequest{ Session: connectResp, Sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", - } - if _, err = client.ExecuteUpdate(ctx, updateReq); err != nil { + }); err != nil { log.Fatalf("create table failed: %v", err) } - insertReq := &pb.StatementRequest{ + if _, err = client.ExecuteUpdate(ctx, &grpcclient.StatementRequest{ Session: connectResp, Sql: "INSERT INTO demo(id, name) VALUES (1, 'hello from go') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", - } - if _, err = client.ExecuteUpdate(ctx, insertReq); err != nil { + }); err != nil { log.Fatalf("insert failed: %v", err) } - queryReq := &pb.StatementRequest{ + stream, err := client.ExecuteQuery(ctx, &grpcclient.StatementRequest{ Session: connectResp, Sql: "SELECT id, name FROM demo ORDER BY id", - } - stream, err := client.ExecuteQuery(ctx, queryReq) + }) if err != nil { log.Fatalf("executeQuery failed: %v", err) } + count := 0 for { - msg, recvErr := stream.Recv() - if recvErr == io.EOF { + msg, err := stream.Recv() + if err == io.EOF { break } - if recvErr != nil { - log.Fatalf("stream recv failed: %v", recvErr) + if err != nil { + log.Fatalf("stream recv failed: %v", err) } - fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) + count++ + fmt.Printf("opResult: type=%v uuid=%s\n", msg.Type, msg.Uuid) } + log.Printf("Got %d results", count) _, _ = client.TerminateSession(context.Background(), connectResp) + log.Println("SUCCESS!") } func env(name, fallback string) string { - v := os.Getenv(name) - if v == "" { - return fallback + if v := os.Getenv(name); v != "" { + return v } - return v -} + return fallback +} \ No newline at end of file diff --git a/tools/client-generation/generate-clients.sh b/tools/client-generation/generate-clients.sh old mode 100644 new mode 100755 From f9c693300c92d5d8d6f7027e11d7c4b4fba06a1a Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Wed, 6 May 2026 21:23:10 +0200 Subject: [PATCH 03/12] update go client --- tools/client-generation/example/go/go.mod | 4 +- tools/client-generation/example/go/main.go | 348 ++++++++++++++--- .../example/go/pkg/client/endpoint.go | 131 +++++++ .../example/go/pkg/client/exception.go | 101 +++++ .../example/go/pkg/client/health.go | 118 ++++++ .../example/go/pkg/client/multinode.go | 361 ++++++++++++++++++ .../example/go/pkg/client/service.go | 311 +++++++++++++++ 7 files changed, 1318 insertions(+), 56 deletions(-) create mode 100644 tools/client-generation/example/go/pkg/client/endpoint.go create mode 100644 tools/client-generation/example/go/pkg/client/exception.go create mode 100644 tools/client-generation/example/go/pkg/client/health.go create mode 100644 tools/client-generation/example/go/pkg/client/multinode.go create mode 100644 tools/client-generation/example/go/pkg/client/service.go diff --git a/tools/client-generation/example/go/go.mod b/tools/client-generation/example/go/go.mod index aac32f54c..cc1b3f775 100644 --- a/tools/client-generation/example/go/go.mod +++ b/tools/client-generation/example/go/go.mod @@ -1,4 +1,4 @@ -module github.com/open-j-proxy/ojp-client +module github.com/ojp-client go 1.22 @@ -14,3 +14,5 @@ require ( golang.org/x/text v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect ) + +replace github.com/open-j-proxy/ojp-client => ../ diff --git a/tools/client-generation/example/go/main.go b/tools/client-generation/example/go/main.go index de94111c5..c9b0f7502 100644 --- a/tools/client-generation/example/go/main.go +++ b/tools/client-generation/example/go/main.go @@ -1,91 +1,329 @@ package main import ( - "context" "fmt" - "io" "log" "os" + "sync" "time" - grpcclient "github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" + "github.com/ojp-client/gen/go/com/openjproxy/grpc" + "github.com/ojp-client/pkg/client" ) func main() { - addr := env("OJP_ADDR", "127.0.0.1:1059") - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://postgres:5432/ojp") - dbUser := env("OJP_DB_USER", "ojp") - dbPassword := env("OJP_DB_PASSWORD", "ojp") + log.SetFlags(log.LstdFlags | log.Lshortfile) - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() + log.Println("=== Test 1: Round-robin load balancing ===") + testRoundRobin() - log.Printf("Connecting to OJP server at %s", addr) - conn, err := grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + log.Println("\n=== Test 2: Session stickiness ===") + testSessionStickiness() + + log.Println("\n=== Test 3: Health check failure detection ===") + testHealthCheck() + + log.Println("\n=== Test 4: Concurrent connections ===") + testConcurrentConnections() + + log.Println("\n=== Test 5: Transaction support ===") + testTransactions() + + log.Println("\n=== All tests passed! ===") +} + +func env(name, fallback string) string { + if v := os.Getenv(name); v != "" { + return v + } + return fallback +} + +func testRoundRobin() { + healthConfig := client.DefaultHealthCheckConfig() + + connManager, err := client.NewMultinodeConnectionManager([]string{ + "127.0.0.1:1059", + "127.0.0.1:1060", + }, healthConfig) if err != nil { - log.Fatalf("dial failed: %v", err) + log.Fatalf("Failed to create connection manager: %v", err) } - defer conn.Close() + defer connManager.Shutdown() - client := grpcclient.NewStatementServiceClient(conn) + service := client.NewMultinodeStatementService(connManager) + defer service.Shutdown() - log.Printf("Connecting to database: %s", backendURL) - connectResp, err := client.Connect(ctx, &grpcclient.ConnectionDetails{ + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") + details := &grpc.ConnectionDetails{ Url: backendURL, - User: dbUser, - Password: dbPassword, - ClientUUID: "go-example-client", - }) + User: env("OJP_DB_USER", "ojp"), + Password: env("OJP_DB_PASSWORD", "ojp"), + ClientUUID: "test-roundrobin", + } + + session, err := service.Connect(details) if err != nil { - log.Fatalf("connect failed: %v", err) + log.Fatalf("Connect failed: %v", err) } - log.Printf("Connected! Session: %s", connectResp.SessionUUID) + log.Printf("Connected! Session: %s", session.GetSessionUUID()) - if _, err = client.ExecuteUpdate(ctx, &grpcclient.StatementRequest{ - Session: connectResp, - Sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", - }); err != nil { - log.Fatalf("create table failed: %v", err) + _, err = service.ExecuteUpdate(session, "CREATE TABLE IF NOT EXISTS test_rr(id INT PRIMARY KEY, server VARCHAR(100))") + if err != nil { + log.Fatalf("Create table failed: %v", err) } - if _, err = client.ExecuteUpdate(ctx, &grpcclient.StatementRequest{ - Session: connectResp, - Sql: "INSERT INTO demo(id, name) VALUES (1, 'hello from go') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", - }); err != nil { - log.Fatalf("insert failed: %v", err) + for i := 0; i < 4; i++ { + sql := fmt.Sprintf("INSERT INTO test_rr(id, server) VALUES (%d, 'server-%d') ON CONFLICT (id) DO UPDATE SET server = EXCLUDED.server", i, i%2) + _, err = service.ExecuteUpdate(session, sql) + if err != nil { + log.Printf("Insert %d failed: %v", i, err) + } } - stream, err := client.ExecuteQuery(ctx, &grpcclient.StatementRequest{ - Session: connectResp, - Sql: "SELECT id, name FROM demo ORDER BY id", - }) + results, err := service.ExecuteQuery(session, "SELECT id, server FROM test_rr ORDER BY id") if err != nil { - log.Fatalf("executeQuery failed: %v", err) + log.Fatalf("Query failed: %v", err) } + log.Printf("Got %d results from round-robin inserts", len(results)) - count := 0 - for { - msg, err := stream.Recv() - if err == io.EOF { - break - } + service.TerminateSession(session) + log.Printf("Round-robin test completed") +} + +func testSessionStickiness() { + healthConfig := client.DefaultHealthCheckConfig() + + connManager, err := client.NewMultinodeConnectionManager([]string{ + "127.0.0.1:1059", + "127.0.0.1:1060", + }, healthConfig) + if err != nil { + log.Fatalf("Failed to create connection manager: %v", err) + } + defer connManager.Shutdown() + + service := client.NewMultinodeStatementService(connManager) + defer service.Shutdown() + + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") + details := &grpc.ConnectionDetails{ + Url: backendURL, + User: env("OJP_DB_USER", "ojp"), + Password: env("OJP_DB_PASSWORD", "ojp"), + ClientUUID: "test-sticky", + } + + session, err := service.Connect(details) + if err != nil { + log.Fatalf("Connect failed: %v", err) + } + log.Printf("Connected! Session: %s", session.GetSessionUUID()) + + _, err = service.ExecuteUpdate(session, "CREATE TABLE IF NOT EXISTS test_sticky(id INT PRIMARY KEY, data VARCHAR(100))") + if err != nil { + log.Fatalf("Create table failed: %v", err) + } + + for i := 0; i < 5; i++ { + sql := fmt.Sprintf("INSERT INTO test_sticky(id, data) VALUES (%d, 'sticky-%d') ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data", i, i) + _, err = service.ExecuteUpdate(session, sql) if err != nil { - log.Fatalf("stream recv failed: %v", err) + log.Printf("Insert %d failed: %v", i, err) } - count++ - fmt.Printf("opResult: type=%v uuid=%s\n", msg.Type, msg.Uuid) } - log.Printf("Got %d results", count) - _, _ = client.TerminateSession(context.Background(), connectResp) - log.Println("SUCCESS!") + endpoints := connManager.GetServerEndpoints() + log.Printf("Server endpoints: %v", endpoints) + + for _, ep := range endpoints { + log.Printf(" Endpoint %s: healthy=%v, connCount=%d", ep.Address(), ep.IsHealthy(), ep.ConnectionCount()) + } + + service.TerminateSession(session) + log.Printf("Session stickiness test completed") } -func env(name, fallback string) string { - if v := os.Getenv(name); v != "" { - return v +func testHealthCheck() { + healthConfig := client.LoadHealthCheckConfig(map[string]string{ + "ojp.health.check.interval": "3000", + "ojp.health.check.timeout": "2000", + }) + + connManager, err := client.NewMultinodeConnectionManager([]string{ + "127.0.0.1:1059", + "127.0.0.1:1060", + }, healthConfig) + if err != nil { + log.Fatalf("Failed to create connection manager: %v", err) } - return fallback + defer connManager.Shutdown() + + connManager.StartHealthChecks() + log.Printf("Health checks started") + + time.Sleep(1 * time.Second) + + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") + details := &grpc.ConnectionDetails{ + Url: backendURL, + User: env("OJP_DB_USER", "ojp"), + Password: env("OJP_DB_PASSWORD", "ojp"), + ClientUUID: "test-health", + } + + service := client.NewMultinodeStatementService(connManager) + defer service.Shutdown() + + session, err := service.Connect(details) + if err != nil { + log.Fatalf("Connect failed: %v", err) + } + log.Printf("Connected! Session: %s", session.GetSessionUUID()) + + time.Sleep(2 * time.Second) + + clusterHealth := connManager.GenerateClusterHealth() + log.Printf("Cluster health: %s", clusterHealth) + + for _, ep := range connManager.GetServerEndpoints() { + log.Printf(" Endpoint %s: healthy=%v", ep.Address(), ep.IsHealthy()) + } + + service.TerminateSession(session) + log.Printf("Health check test completed") +} + +func testConcurrentConnections() { + healthConfig := client.DefaultHealthCheckConfig() + + connManager, err := client.NewMultinodeConnectionManager([]string{ + "127.0.0.1:1059", + "127.0.0.1:1060", + }, healthConfig) + if err != nil { + log.Fatalf("Failed to create connection manager: %v", err) + } + defer connManager.Shutdown() + + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") + + var wg sync.WaitGroup + results := make(chan string, 10) + + for i := 0; i < 5; i++ { + wg.Add(1) + go func(idx int) { + defer wg.Done() + + service := client.NewMultinodeStatementService(connManager) + details := &grpc.ConnectionDetails{ + Url: backendURL, + User: env("OJP_DB_USER", "ojp"), + Password: env("OJP_DB_PASSWORD", "ojp"), + ClientUUID: fmt.Sprintf("test-concurrent-%d", idx), + } + + var session *grpc.SessionInfo + var err error + for attempt := 0; attempt < 3; attempt++ { + session, err = service.Connect(details) + if err == nil { + break + } + log.Printf("Connect attempt %d failed: %v, retrying...", attempt+1, err) + time.Sleep(500 * time.Millisecond) + } + if err != nil { + results <- fmt.Sprintf("goroutine %d: connect failed after retries: %v", idx, err) + return + } + + sql := fmt.Sprintf("SELECT %d as result", idx*100) + qResults, err := service.ExecuteQuery(session, sql) + if err != nil { + results <- fmt.Sprintf("goroutine %d: query failed: %v", idx, err) + } else { + results <- fmt.Sprintf("goroutine %d: got %d results", idx, len(qResults)) + } + + service.TerminateSession(session) + }(i) + } + + wg.Wait() + close(results) + + log.Printf("Concurrent connection results:") + for r := range results { + log.Printf(" %s", r) + } + + log.Printf("Concurrent test completed") +} + +func testTransactions() { + healthConfig := client.DefaultHealthCheckConfig() + + connManager, err := client.NewMultinodeConnectionManager([]string{ + "127.0.0.1:1059", + }, healthConfig) + if err != nil { + log.Fatalf("Failed to create connection manager: %v", err) + } + defer connManager.Shutdown() + + service := client.NewMultinodeStatementService(connManager) + defer service.Shutdown() + + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") + details := &grpc.ConnectionDetails{ + Url: backendURL, + User: env("OJP_DB_USER", "ojp"), + Password: env("OJP_DB_PASSWORD", "ojp"), + ClientUUID: "test-transaction", + } + + session, err := service.Connect(details) + if err != nil { + log.Fatalf("Connect failed: %v", err) + } + log.Printf("Connected! Session: %s", session.GetSessionUUID()) + + _, err = service.ExecuteUpdate(session, "CREATE TABLE IF NOT EXISTS test_txn(id INT PRIMARY KEY, value VARCHAR(100))") + if err != nil { + log.Fatalf("Create table failed: %v", err) + } + + sessionWithTXN, err := service.StartTransaction(session) + if err != nil { + log.Printf("StartTransaction not supported (OK): %v", err) + } else { + log.Printf("Transaction started! Session: %s", sessionWithTXN.GetSessionUUID()) + + _, err = service.ExecuteUpdate(sessionWithTXN, "INSERT INTO test_txn(id, value) VALUES (1, 'transactional')") + if err != nil { + log.Printf("Insert in transaction failed: %v", err) + } + + _, err = service.CommitTransaction(sessionWithTXN) + if err != nil { + log.Printf("Commit failed: %v", err) + } else { + log.Printf("Transaction committed!") + } + } + + results, err := service.ExecuteQuery(session, "SELECT id, value FROM test_txn WHERE id = 1") + if err != nil { + log.Printf("Query failed: %v", err) + } else if len(results) > 0 { + res := results[0] + if res.GetQueryResult() != nil && len(res.GetQueryResult().GetRows()) > 0 { + log.Printf("Verified committed data exists") + } + } + + service.TerminateSession(session) + log.Printf("Transaction test completed") } \ No newline at end of file diff --git a/tools/client-generation/example/go/pkg/client/endpoint.go b/tools/client-generation/example/go/pkg/client/endpoint.go new file mode 100644 index 000000000..b574cbd9b --- /dev/null +++ b/tools/client-generation/example/go/pkg/client/endpoint.go @@ -0,0 +1,131 @@ +package client + +import ( + "fmt" + "sync" + "sync/atomic" + "time" +) + +// ServerEndpoint represents an OJP server endpoint with health status tracking. +type ServerEndpoint struct { + host string + port int + dataSourceName string + healthy atomic.Bool + lastFailureTime atomic.Int64 + connCount atomic.Int64 // Number of active connections + loadMetric atomic.Int64 // Load metric for load-aware selection + mu sync.RWMutex +} + +// NewServerEndpoint creates a new server endpoint. +func NewServerEndpoint(host string, port int) *ServerEndpoint { + return NewServerEndpointWithDS(host, port, "default") +} + +// NewServerEndpointWithDS creates a new server endpoint with data source name. +func NewServerEndpointWithDS(host string, port int, dataSourceName string) *ServerEndpoint { + if host == "" { + panic("host cannot be empty") + } + if port <= 0 || port > 65535 { + panic("port must be between 1 and 65535") + } + ds := dataSourceName + if ds == "" { + ds = "default" + } + return &ServerEndpoint{ + host: host, + port: port, + dataSourceName: ds, + } +} + +// Host returns the server host. +func (s *ServerEndpoint) Host() string { + return s.host +} + +// Port returns the server port. +func (s *ServerEndpoint) Port() int { + return s.port +} + +// DataSourceName returns the data source name. +func (s *ServerEndpoint) DataSourceName() string { + return s.dataSourceName +} + +// Address returns host:port string. +func (s *ServerEndpoint) Address() string { + return fmt.Sprintf("%s:%d", s.host, s.port) +} + +// IsHealthy returns whether the server is healthy. +func (s *ServerEndpoint) IsHealthy() bool { + return s.healthy.Load() +} + +// SetHealthy sets the health status. +func (s *ServerEndpoint) SetHealthy(healthy bool) { + s.healthy.Store(healthy) + if healthy { + s.lastFailureTime.Store(0) + } +} + +// MarkHealthy marks the server as healthy. +func (s *ServerEndpoint) MarkHealthy() { + s.healthy.Store(true) + s.lastFailureTime.Store(0) +} + +// MarkUnhealthy marks the server as unhealthy. +func (s *ServerEndpoint) MarkUnhealthy() { + s.healthy.Store(false) + s.lastFailureTime.Store(time.Now().UnixMilli()) +} + +// LastFailureTime returns the last failure timestamp. +func (s *ServerEndpoint) LastFailureTime() int64 { + return s.lastFailureTime.Load() +} + +// IncrConnection increments the connection count. +func (s *ServerEndpoint) IncrConnection() { + s.connCount.Add(1) +} + +// DecrConnection decrements the connection count. +func (s *ServerEndpoint) DecrConnection() { + s.connCount.Add(-1) +} + +// ConnectionCount returns the current connection count. +func (s *ServerEndpoint) ConnectionCount() int64 { + return s.connCount.Load() +} + +// SetLoadMetric sets the load metric for load-aware selection. +func (s *ServerEndpoint) SetLoadMetric(load int64) { + s.loadMetric.Store(load) +} + +// LoadMetric returns the current load metric. +func (s *ServerEndpoint) LoadMetric() int64 { + return s.loadMetric.Load() +} + +// Equals compares two endpoints for equality. +func (s *ServerEndpoint) Equals(other *ServerEndpoint) bool { + if other == nil { + return false + } + return s.host == other.host && s.port == other.port +} + +func (s *ServerEndpoint) String() string { + return s.Address() +} \ No newline at end of file diff --git a/tools/client-generation/example/go/pkg/client/exception.go b/tools/client-generation/example/go/pkg/client/exception.go new file mode 100644 index 000000000..d2ba195f5 --- /dev/null +++ b/tools/client-generation/example/go/pkg/client/exception.go @@ -0,0 +1,101 @@ +package client + +import ( + "fmt" + "strings" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type SqlError struct { + Code string + Message string + Vendor int +} + +func (e *SqlError) Error() string { + return fmt.Sprintf("SQL error: %s - %s", e.Code, e.Message) +} + +func NewSqlError(sqlState, message string, vendor int) error { + return &SqlError{ + Code: sqlState, + Message: message, + Vendor: vendor, + } +} + +type GrpcExceptionHandler struct{} + +func (h GrpcExceptionHandler) Handle(err error) error { + s, ok := status.FromError(err) + if !ok { + return NewSqlError("08006", err.Error(), 0) + } + return h.fromStatus(s) +} + +func (h GrpcExceptionHandler) fromStatus(s *status.Status) error { + code := s.Code() + errMsg := s.Message() + + var sqlState string + var vendor int + + switch code { + case codes.OK: + return nil + case codes.NotFound: + sqlState = "02000" + case codes.AlreadyExists: + sqlState = "23505" + case codes.FailedPrecondition: + sqlState = "23505" + case codes.Aborted: + sqlState = "40001" + case codes.DeadlineExceeded: + sqlState = "HYT00" + case codes.Unavailable: + sqlState = "08003" + case codes.Unauthenticated: + sqlState = "28000" + case codes.PermissionDenied: + sqlState = "42501" + case codes.ResourceExhausted: + sqlState = "53300" + default: + sqlState = "HY000" + } + + return NewSqlError(sqlState, errMsg, vendor) +} + +func IsConnectionLevelError(err error) bool { + if err == nil { + return false + } + s, ok := status.FromError(err) + if !ok { + return true + } + switch s.Code() { + case codes.Unavailable, + codes.DeadlineExceeded, + codes.Internal, + codes.Unauthenticated: + return true + default: + return false + } +} + +func IsConnectionError(err error) bool { + if err == nil { + return false + } + errStr := strings.ToLower(err.Error()) + return strings.Contains(errStr, "connection") || + strings.Contains(errStr, "unavailable") || + strings.Contains(errStr, "timeout") +} \ No newline at end of file diff --git a/tools/client-generation/example/go/pkg/client/health.go b/tools/client-generation/example/go/pkg/client/health.go new file mode 100644 index 000000000..83a2f0b63 --- /dev/null +++ b/tools/client-generation/example/go/pkg/client/health.go @@ -0,0 +1,118 @@ +package client + +import ( + "strconv" + "strings" + "time" +) + +type HealthCheckConfig struct { + healthCheckIntervalMs int64 + healthCheckThresholdMs int64 + healthCheckTimeoutMs int64 + redistributionEnabled bool + idleRebalanceFraction float64 + maxClosePerRecovery int + loadAwareSelectionEnabled bool +} + +const ( + DefaultHealthCheckIntervalMs = 5000 + DefaultHealthCheckThresholdMs = 5000 + DefaultHealthCheckTimeoutMs = 5000 + DefaultRedistributionEnabled = true + DefaultIdleRebalanceFraction = 1.0 + DefaultMaxClosePerRecovery = 100 + DefaultLoadAwareSelectionEnabled = true +) + +func LoadHealthCheckConfig(props map[string]string) *HealthCheckConfig { + if props == nil { + return DefaultHealthCheckConfig() + } + interval := getInt64(props, "ojp.health.check.interval", DefaultHealthCheckIntervalMs) + threshold := getInt64(props, "ojp.health.check.threshold", DefaultHealthCheckThresholdMs) + timeout := getInt(props, "ojp.health.check.timeout", DefaultHealthCheckTimeoutMs) + enabled := getBool(props, "ojp.redistribution.enabled", DefaultRedistributionEnabled) + idleFraction := getFloat(props, "ojp.redistribution.idleRebalanceFraction", DefaultIdleRebalanceFraction) + maxClose := getInt(props, "ojp.redistribution.maxClosePerRecovery", DefaultMaxClosePerRecovery) + loadAware := getBool(props, "ojp.loadaware.selection.enabled", DefaultLoadAwareSelectionEnabled) + + return &HealthCheckConfig{ + healthCheckIntervalMs: interval, + healthCheckThresholdMs: threshold, + healthCheckTimeoutMs: int64(timeout), + redistributionEnabled: enabled, + idleRebalanceFraction: idleFraction, + maxClosePerRecovery: maxClose, + loadAwareSelectionEnabled: loadAware, + } +} + +func DefaultHealthCheckConfig() *HealthCheckConfig { + return &HealthCheckConfig{ + healthCheckIntervalMs: int64(DefaultHealthCheckIntervalMs), + healthCheckThresholdMs: int64(DefaultHealthCheckThresholdMs), + healthCheckTimeoutMs: int64(DefaultHealthCheckTimeoutMs), + redistributionEnabled: DefaultRedistributionEnabled, + idleRebalanceFraction: DefaultIdleRebalanceFraction, + maxClosePerRecovery: DefaultMaxClosePerRecovery, + loadAwareSelectionEnabled: DefaultLoadAwareSelectionEnabled, + } +} + +func getInt64(props map[string]string, key string, defaultValue int64) int64 { + v, ok := props[key] + if !ok || v == "" { + return defaultValue + } + parsed, err := strconv.ParseInt(v, 10, 64) + if err != nil || parsed < 0 { + return defaultValue + } + return parsed +} + +func getInt(props map[string]string, key string, defaultValue int) int { + v, ok := props[key] + if !ok || v == "" { + return defaultValue + } + parsed, err := strconv.Atoi(v) + if err != nil || parsed < 0 { + return defaultValue + } + return parsed +} + +func getBool(props map[string]string, key string, defaultValue bool) bool { + v, ok := props[key] + if !ok || v == "" { + return defaultValue + } + return strings.EqualFold(v, "true") +} + +func getFloat(props map[string]string, key string, defaultValue float64) float64 { + v, ok := props[key] + if !ok || v == "" { + return defaultValue + } + parsed, err := strconv.ParseFloat(v, 64) + if err != nil || parsed < 0 || parsed > 1 { + return defaultValue + } + return parsed +} + +func (c *HealthCheckConfig) HealthCheckIntervalMs() int64 { return c.healthCheckIntervalMs } +func (c *HealthCheckConfig) HealthCheckThresholdMs() int64 { return c.healthCheckThresholdMs } +func (c *HealthCheckConfig) HealthCheckTimeoutMs() int64 { return c.healthCheckTimeoutMs } +func (c *HealthCheckConfig) IsRedistributionEnabled() bool { return c.redistributionEnabled } +func (c *HealthCheckConfig) IdleRebalanceFraction() float64 { return c.idleRebalanceFraction } +func (c *HealthCheckConfig) MaxClosePerRecovery() int { return c.maxClosePerRecovery } +func (c *HealthCheckConfig) IsLoadAwareSelectionEnabled() bool { return c.loadAwareSelectionEnabled } + +func (c *HealthCheckConfig) HealthCheckInterval() time.Duration { return time.Duration(c.healthCheckIntervalMs) * time.Millisecond } +func (c *HealthCheckConfig) HealthCheckThreshold() time.Duration { return time.Duration(c.healthCheckThresholdMs) * time.Millisecond } +func (c *HealthCheckConfig) HealthCheckTimeout() time.Duration { return time.Duration(c.healthCheckTimeoutMs) * time.Millisecond } \ No newline at end of file diff --git a/tools/client-generation/example/go/pkg/client/multinode.go b/tools/client-generation/example/go/pkg/client/multinode.go new file mode 100644 index 000000000..faa9ac7d0 --- /dev/null +++ b/tools/client-generation/example/go/pkg/client/multinode.go @@ -0,0 +1,361 @@ +package client + +import ( + "context" + "fmt" + "sort" + "strings" + "sync" + "sync/atomic" + "time" + + ojpgrpc "github.com/ojp-client/gen/go/com/openjproxy/grpc" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type ChannelAndStub struct { + channel *grpc.ClientConn + blockingStub ojpgrpc.StatementServiceClient + asyncStub ojpgrpc.StatementServiceClient +} + +type MultinodeConnectionManager struct { + endpoints []*ServerEndpoint + channelMap map[*ServerEndpoint]*ChannelAndStub + connTracker *ConnectionTracker + healthConfig *HealthCheckConfig + healthCheckStop chan struct{} + started atomic.Bool + mu sync.RWMutex + roundRobinIdx atomic.Int32 + originalURL string +} + +type ConnectionTracker struct { + sessions map[string]*ServerEndpoint + sessionLock sync.RWMutex +} + +func NewConnectionTracker() *ConnectionTracker { + return &ConnectionTracker{ + sessions: make(map[string]*ServerEndpoint), + } +} + +func NewMultinodeConnectionManager(urls []string, healthConfig *HealthCheckConfig) (*MultinodeConnectionManager, error) { + if len(urls) == 0 { + return nil, fmt.Errorf("no server URLs provided") + } + if healthConfig == nil { + healthConfig = DefaultHealthCheckConfig() + } + + endpoints := make([]*ServerEndpoint, 0, len(urls)) + for _, url := range urls { + ep, err := parseURL(url) + if err != nil { + return nil, fmt.Errorf("failed to parse URL %s: %w", url, err) + } + endpoints = append(endpoints, ep) + } + + channelMap := make(map[*ServerEndpoint]*ChannelAndStub) + for _, ep := range endpoints { + channelMap[ep] = nil + } + + return &MultinodeConnectionManager{ + endpoints: endpoints, + channelMap: channelMap, + connTracker: NewConnectionTracker(), + healthConfig: healthConfig, + healthCheckStop: make(chan struct{}), + originalURL: strings.Join(urls, ","), + }, nil +} + +func parseURL(url string) (*ServerEndpoint, error) { + url = strings.TrimSpace(url) + if strings.HasPrefix(url, "ojp://") { + url = url[5:] + } else if strings.HasPrefix(url, "jdbc:ojp[") { + start := strings.Index(url, "]_") + if start == -1 { + return nil, fmt.Errorf("invalid JDBC URL format") + } + url = url[start+2:] + } + + var host string + var port int + if strings.Contains(url, ":") { + parts := strings.SplitN(url, ":", 2) + host = parts[0] + fmt.Sscanf(parts[1], "%d", &port) + } else { + host = url + port = 1059 + } + + if host == "" { + host = "localhost" + } + if port == 0 { + port = 1059 + } + + return NewServerEndpoint(host, port), nil +} + +func (m *MultinodeConnectionManager) Connect(details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { + server := m.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + channel, err := m.getChannel(server) + if err != nil { + return nil, fmt.Errorf("failed to connect to %s: %w", server.Address(), err) + } + + client := ojpgrpc.NewStatementServiceClient(channel) + resp, err := client.Connect(context.Background(), details) + if err != nil { + server.MarkUnhealthy() + m.handleServerFailure(server, err) + return nil, fmt.Errorf("connect failed: %w", err) + } + + if resp.GetSessionUUID() != "" { + m.connTracker.BindSession(resp.GetSessionUUID(), server) + } + + return resp, nil +} + +func (m *MultinodeConnectionManager) selectServer(sessionKey string) *ServerEndpoint { + if sessionKey != "" { + if bound := m.connTracker.GetBoundServer(sessionKey); bound != nil && bound.IsHealthy() { + return bound + } + } + + if m.healthConfig.IsLoadAwareSelectionEnabled() { + return m.loadAwareServer() + } + return m.roundRobinServer() +} + +func (m *MultinodeConnectionManager) roundRobinServer() *ServerEndpoint { + m.mu.RLock() + defer m.mu.RUnlock() + + if len(m.endpoints) == 0 { + return nil + } + + count := len(m.endpoints) + idx := int(m.roundRobinIdx.Add(1)) % count + + for i := 0; i < count; i++ { + ep := m.endpoints[(idx+i)%count] + if ep.IsHealthy() { + return ep + } + } + + for _, ep := range m.endpoints { + if ep.IsHealthy() { + return ep + } + } + + return m.endpoints[0] +} + +func (m *MultinodeConnectionManager) loadAwareServer() *ServerEndpoint { + m.mu.RLock() + defer m.mu.RUnlock() + + var healthy []*ServerEndpoint + for _, ep := range m.endpoints { + if ep.IsHealthy() { + healthy = append(healthy, ep) + } + } + + if len(healthy) == 0 { + if len(m.endpoints) == 0 { + return nil + } + return m.endpoints[0] + } + + sort.Slice(healthy, func(i, j int) bool { + return healthy[i].LoadMetric() < healthy[j].LoadMetric() + }) + + return healthy[0] +} + +func (m *MultinodeConnectionManager) getChannel(server *ServerEndpoint) (*grpc.ClientConn, error) { + m.mu.Lock() + defer m.mu.Unlock() + + if cached, ok := m.channelMap[server]; ok && cached != nil && cached.channel != nil { + return cached.channel, nil + } + + addr := server.Address() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + conn, err := grpc.DialContext(ctx, addr, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithBlock(), + ) + if err != nil { + return nil, err + } + + m.channelMap[server] = &ChannelAndStub{ + channel: conn, + blockingStub: ojpgrpc.NewStatementServiceClient(conn), + asyncStub: ojpgrpc.NewStatementServiceClient(conn), + } + + return conn, nil +} + +func (m *MultinodeConnectionManager) handleServerFailure(server *ServerEndpoint, err error) { + if IsConnectionLevelError(err) { + server.MarkUnhealthy() + m.connTracker.InvalidateSessionsForServer(server) + } +} + +func (m *MultinodeConnectionManager) StartHealthChecks() { + if m.started.Swap(true) { + return + } + go m.runHealthCheck() +} + +func (m *MultinodeConnectionManager) runHealthCheck() { + ticker := time.NewTicker(m.healthConfig.HealthCheckInterval()) + defer ticker.Stop() + + for { + select { + case <-m.healthCheckStop: + return + case <-ticker.C: + m.checkAllEndpoints() + } + } +} + +func (m *MultinodeConnectionManager) checkAllEndpoints() { + for _, ep := range m.endpoints { + go m.checkEndpoint(ep) + } +} + +func (m *MultinodeConnectionManager) checkEndpoint(ep *ServerEndpoint) { + channel, err := m.getChannel(ep) + if err != nil { + ep.MarkUnhealthy() + return + } + + client := ojpgrpc.NewStatementServiceClient(channel) + ctx, cancel := context.WithTimeout(context.Background(), m.healthConfig.HealthCheckTimeout()) + defer cancel() + + details := &ojpgrpc.ConnectionDetails{ + Url: "health-check", + ClientUUID: "health-check-client", + } + + _, err = client.Connect(ctx, details) + if err != nil { + ep.MarkUnhealthy() + return + } + + ep.MarkHealthy() +} + +func (m *MultinodeConnectionManager) Shutdown() { + if !m.started.Swap(false) { + return + } + select { + case <-m.healthCheckStop: + default: + close(m.healthCheckStop) + } + m.mu.Lock() + defer m.mu.Unlock() + + for _, cs := range m.channelMap { + if cs != nil && cs.channel != nil { + cs.channel.Close() + } + } + m.channelMap = make(map[*ServerEndpoint]*ChannelAndStub) +} + +func (m *MultinodeConnectionManager) GetServerEndpoints() []*ServerEndpoint { + m.mu.RLock() + defer m.mu.RUnlock() + + result := make([]*ServerEndpoint, len(m.endpoints)) + copy(result, m.endpoints) + return result +} + +func (m *MultinodeConnectionManager) GenerateClusterHealth() string { + m.mu.RLock() + defer m.mu.RUnlock() + + var parts []string + for _, ep := range m.endpoints { + status := "UP" + if !ep.IsHealthy() { + status = "DOWN" + } + parts = append(parts, fmt.Sprintf("%s(%s)", ep.Address(), status)) + } + return strings.Join(parts, ";") +} + +func (t *ConnectionTracker) BindSession(session string, server *ServerEndpoint) { + t.sessionLock.Lock() + defer t.sessionLock.Unlock() + t.sessions[session] = server +} + +func (t *ConnectionTracker) GetBoundServer(session string) *ServerEndpoint { + t.sessionLock.RLock() + defer t.sessionLock.RUnlock() + return t.sessions[session] +} + +func (t *ConnectionTracker) InvalidateSessionsForServer(server *ServerEndpoint) { + t.sessionLock.Lock() + defer t.sessionLock.Unlock() + + for sess, ep := range t.sessions { + if ep == server { + delete(t.sessions, sess) + } + } +} + +func (t *ConnectionTracker) TerminateSession(session string) { + t.sessionLock.Lock() + defer t.sessionLock.Unlock() + delete(t.sessions, session) +} \ No newline at end of file diff --git a/tools/client-generation/example/go/pkg/client/service.go b/tools/client-generation/example/go/pkg/client/service.go new file mode 100644 index 000000000..be941167a --- /dev/null +++ b/tools/client-generation/example/go/pkg/client/service.go @@ -0,0 +1,311 @@ +package client + +import ( + "context" + "fmt" + "io" + "strings" + "sync" + + ojpgrpc "github.com/ojp-client/gen/go/com/openjproxy/grpc" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type StatementService interface { + Connect(details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) + ExecuteUpdate(session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) + ExecuteQuery(session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) + TerminateSession(session *ojpgrpc.SessionInfo) error + StartTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) + CommitTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) + RollbackTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) + Shutdown() +} + +type MultinodeStatementService struct { + connManager *MultinodeConnectionManager + clients map[*ServerEndpoint]*EndpointClient + clientLock sync.RWMutex +} + +type EndpointClient struct { + client StatementService + server *ServerEndpoint +} + +func NewMultinodeStatementService(connManager *MultinodeConnectionManager) *MultinodeStatementService { + return &MultinodeStatementService{ + connManager: connManager, + clients: make(map[*ServerEndpoint]*EndpointClient), + } +} + +func (s *MultinodeStatementService) getClient(server *ServerEndpoint) (*EndpointClient, error) { + s.clientLock.RLock() + if cached, ok := s.clients[server]; ok { + s.clientLock.RUnlock() + return cached, nil + } + s.clientLock.RUnlock() + + s.clientLock.Lock() + defer s.clientLock.Unlock() + + if cached, ok := s.clients[server]; ok { + return cached, nil + } + + client := NewGrpcStatementServiceClient(server.Address()) + epClient := &EndpointClient{ + client: client, + server: server, + } + s.clients[server] = epClient + return epClient, nil +} + +func (s *MultinodeStatementService) Connect(details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { + return s.connManager.Connect(details) +} + +func (s *MultinodeStatementService) ExecuteUpdate(session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) { + server := s.connManager.selectServer(session.GetSessionUUID()) + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + + result, err := epClient.client.ExecuteUpdate(session, sql) + if err != nil { + if IsConnectionLevelError(err) { + server.MarkUnhealthy() + s.connManager.handleServerFailure(server, err) + } + return nil, err + } + return result, nil +} + +func (s *MultinodeStatementService) ExecuteQuery(session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) { + server := s.connManager.selectServer(session.GetSessionUUID()) + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + + results, err := epClient.client.ExecuteQuery(session, sql) + if err != nil { + if IsConnectionLevelError(err) { + server.MarkUnhealthy() + s.connManager.handleServerFailure(server, err) + } + return nil, err + } + return results, nil +} + +func (s *MultinodeStatementService) TerminateSession(session *ojpgrpc.SessionInfo) error { + sessUUID := session.GetSessionUUID() + if sessUUID != "" { + if bound := s.connManager.connTracker.GetBoundServer(sessUUID); bound != nil { + epClient, err := s.getClient(bound) + if err == nil { + return epClient.client.TerminateSession(session) + } + } + } + return nil +} + +func (s *MultinodeStatementService) StartTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + + result, err := epClient.client.StartTransaction(session) + if err != nil { + return nil, err + } + + if result.GetSessionUUID() != "" { + s.connManager.connTracker.BindSession(result.GetSessionUUID(), server) + } + + return result, nil +} + +func (s *MultinodeStatementService) CommitTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { + server := s.connManager.selectServer(session.GetSessionUUID()) + if server == nil { + return nil, fmt.Errorf("no server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.CommitTransaction(session) +} + +func (s *MultinodeStatementService) RollbackTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { + server := s.connManager.selectServer(session.GetSessionUUID()) + if server == nil { + return nil, fmt.Errorf("no server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.RollbackTransaction(session) +} + +func (s *MultinodeStatementService) Shutdown() { + s.connManager.Shutdown() + s.clientLock.Lock() + defer s.clientLock.Unlock() + for _, c := range s.clients { + c.client.Shutdown() + } + s.clients = make(map[*ServerEndpoint]*EndpointClient) +} + +type GrpcStatementServiceClient struct { + address string + client ojpgrpc.StatementServiceClient + conn *grpc.ClientConn +} + +func NewGrpcStatementServiceClient(address string) *GrpcStatementServiceClient { + return &GrpcStatementServiceClient{address: address} +} + +func (c *GrpcStatementServiceClient) EnsureConnected() error { + parts := strings.Split(c.address, ":") + var host string + var port int + if len(parts) == 2 { + host = parts[0] + fmt.Sscanf(parts[1], "%d", &port) + } else { + host = c.address + port = 1059 + } + + conn, err := grpc.DialContext(context.Background(), fmt.Sprintf("%s:%d", host, port), + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithBlock(), + ) + if err != nil { + return err + } + + c.conn = conn + c.client = ojpgrpc.NewStatementServiceClient(conn) + return nil +} + +func (c *GrpcStatementServiceClient) Connect(details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + return c.client.Connect(context.Background(), details) +} + +func (c *GrpcStatementServiceClient) ExecuteUpdate(session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + + req := &ojpgrpc.StatementRequest{ + Session: session, + Sql: sql, + } + return c.client.ExecuteUpdate(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) ExecuteQuery(session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + + req := &ojpgrpc.StatementRequest{ + Session: session, + Sql: sql, + } + stream, err := c.client.ExecuteQuery(context.Background(), req) + if err != nil { + return nil, err + } + + var results []*ojpgrpc.OpResult + for { + msg, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + return results, err + } + results = append(results, msg) + } + return results, nil +} + +func (c *GrpcStatementServiceClient) TerminateSession(session *ojpgrpc.SessionInfo) error { + if c.client == nil { + return nil + } + _, err := c.client.TerminateSession(context.Background(), session) + return err +} + +func (c *GrpcStatementServiceClient) StartTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + return c.client.StartTransaction(context.Background(), session) +} + +func (c *GrpcStatementServiceClient) CommitTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { + if c.client == nil { + return nil, nil + } + return c.client.CommitTransaction(context.Background(), session) +} + +func (c *GrpcStatementServiceClient) RollbackTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { + if c.client == nil { + return nil, nil + } + return c.client.RollbackTransaction(context.Background(), session) +} + +func (c *GrpcStatementServiceClient) Shutdown() { + if c.conn != nil { + c.conn.Close() + } +} \ No newline at end of file From 627f59819fc6191b1e8dae2a5b4a826991cf9bbd Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Wed, 6 May 2026 21:27:47 +0200 Subject: [PATCH 04/12] update go client --- tools/client-generation/example/go/main.go | 168 ++++++++++++ .../example/go/pkg/client/redistributor.go | 84 ++++++ .../example/go/pkg/client/service.go | 242 +++++++++++++++++- 3 files changed, 491 insertions(+), 3 deletions(-) create mode 100644 tools/client-generation/example/go/pkg/client/redistributor.go diff --git a/tools/client-generation/example/go/main.go b/tools/client-generation/example/go/main.go index c9b0f7502..eada535e9 100644 --- a/tools/client-generation/example/go/main.go +++ b/tools/client-generation/example/go/main.go @@ -29,6 +29,12 @@ func main() { log.Println("\n=== Test 5: Transaction support ===") testTransactions() + log.Println("\n=== Test 6: XA Transaction support ===") + testXA() + + log.Println("\n=== Test 7: Load metric tracking ===") + testLoadMetrics() + log.Println("\n=== All tests passed! ===") } @@ -326,4 +332,166 @@ func testTransactions() { service.TerminateSession(session) log.Printf("Transaction test completed") +} + +func testXA() { + healthConfig := client.DefaultHealthCheckConfig() + + connManager, err := client.NewMultinodeConnectionManager([]string{ + "127.0.0.1:1059", + }, healthConfig) + if err != nil { + log.Fatalf("Failed to create connection manager: %v", err) + } + defer connManager.Shutdown() + + service := client.NewMultinodeStatementService(connManager) + defer service.Shutdown() + + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") + details := &grpc.ConnectionDetails{ + Url: backendURL, + User: env("OJP_DB_USER", "ojp"), + Password: env("OJP_DB_PASSWORD", "ojp"), + ClientUUID: "test-xa", + } + + session, err := service.Connect(details) + if err != nil { + log.Fatalf("Connect failed: %v", err) + } + log.Printf("Connected! Session: %s", session.GetSessionUUID()) + + xid := &grpc.XidProto{ + FormatId: 1, + GlobalTransactionId: []byte("test-xa-global"), + BranchQualifier: []byte("test-xa-branch"), + } + + resp, err := service.XAStart(xid, 0) + if err != nil { + log.Printf("XAStart failed (may not be supported): %v", err) + } else { + log.Printf("XAStart: success=%v", resp.GetSuccess()) + } + + _, err = service.ExecuteUpdate(session, "CREATE TABLE IF NOT EXISTS test_xa(id INT PRIMARY KEY, value VARCHAR(100))") + if err != nil { + log.Printf("Create table failed: %v", err) + } + + _, err = service.ExecuteUpdate(session, "INSERT INTO test_xa(id, value) VALUES (1, 'xa-test')") + if err != nil { + log.Printf("Insert failed: %v", err) + } + + resp, err = service.XAEnd(xid, 0) + if err != nil { + log.Printf("XAEnd failed: %v", err) + } else { + log.Printf("XAEnd: success=%v", resp.GetSuccess()) + } + + prepResp, err := service.XAPrepare(xid) + if err != nil { + log.Printf("XAPrepare failed: %v", err) + } else { + log.Printf("XAPrepare: result=%d", prepResp.GetResult()) + } + + commitResp, err := service.XACommit(xid, false) + if err != nil { + log.Printf("XACommit failed: %v", err) + } else { + log.Printf("XACommit: success=%v", commitResp.GetSuccess()) + } + + results, err := service.ExecuteQuery(session, "SELECT id, value FROM test_xa WHERE id = 1") + if err != nil { + log.Printf("Query after XA failed: %v", err) + } else if len(results) > 0 && results[0].GetQueryResult() != nil { + log.Printf("XA data persisted correctly") + } + + recoverResp, err := service.XARecover(0) + if err != nil { + log.Printf("XARecover failed: %v", err) + } else { + log.Printf("XARecover: %d xids", len(recoverResp.GetXids())) + } + + forgetResp, err := service.XAForget(xid) + if err != nil { + log.Printf("XAForget failed: %v", err) + } else { + log.Printf("XAForget: success=%v", forgetResp.GetSuccess()) + } + + timeoutResp, err := service.XASetTransactionTimeout(30) + if err != nil { + log.Printf("XASetTransactionTimeout failed: %v", err) + } else { + log.Printf("XASetTransactionTimeout: success=%v", timeoutResp.GetSuccess()) + } + + getTimeoutResp, err := service.XAGetTransactionTimeout() + if err != nil { + log.Printf("XAGetTransactionTimeout failed: %v", err) + } else { + log.Printf("XAGetTransactionTimeout: seconds=%d", getTimeoutResp.GetSeconds()) + } + + service.TerminateSession(session) + log.Printf("XA test completed") +} + +func testLoadMetrics() { + healthConfig := client.LoadHealthCheckConfig(map[string]string{ + "ojp.loadaware.selection.enabled": "true", + }) + + connManager, err := client.NewMultinodeConnectionManager([]string{ + "127.0.0.1:1059", + "127.0.0.1:1060", + }, healthConfig) + if err != nil { + log.Fatalf("Failed to create connection manager: %v", err) + } + defer connManager.Shutdown() + + service := client.NewMultinodeStatementService(connManager) + defer service.Shutdown() + + backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") + details := &grpc.ConnectionDetails{ + Url: backendURL, + User: env("OJP_DB_USER", "ojp"), + Password: env("OJP_DB_PASSWORD", "ojp"), + ClientUUID: "test-load", + } + + session, err := service.Connect(details) + if err != nil { + log.Fatalf("Connect failed: %v", err) + } + log.Printf("Connected! Session: %s", session.GetSessionUUID()) + + for i := 0; i < 3; i++ { + sql := fmt.Sprintf("SELECT * FROM generate_series(1, %d)", i*10) + results, err := service.ExecuteQuery(session, sql) + if err != nil { + log.Printf("Query %d failed: %v", i, err) + } else { + log.Printf("Query %d: %d results", i, len(results)) + } + } + + endpoints := connManager.GetServerEndpoints() + log.Printf("Load metrics after queries:") + for _, ep := range endpoints { + log.Printf(" %s: load_metric=%d", ep.Address(), ep.LoadMetric()) + } + + service.TerminateSession(session) + log.Printf("Load metrics test completed") } \ No newline at end of file diff --git a/tools/client-generation/example/go/pkg/client/redistributor.go b/tools/client-generation/example/go/pkg/client/redistributor.go new file mode 100644 index 000000000..019c81175 --- /dev/null +++ b/tools/client-generation/example/go/pkg/client/redistributor.go @@ -0,0 +1,84 @@ +package client + +import ( + "sync" +) + +type ConnectionRedistributor struct { + connTracker *ConnectionTracker + config *HealthCheckConfig + mu sync.RWMutex +} + +func NewConnectionRedistributor(connTracker *ConnectionTracker, config *HealthCheckConfig) *ConnectionRedistributor { + return &ConnectionRedistributor{ + connTracker: connTracker, + config: config, + } +} + +func (r *ConnectionRedistributor) Rebalance(recoveredServers []*ServerEndpoint, allHealthyServers []*ServerEndpoint) { + if !r.config.IsRedistributionEnabled() { + return + } + + if len(recoveredServers) == 0 { + return + } + + if len(allHealthyServers) < 2 { + return + } + + r.mu.Lock() + defer r.mu.Unlock() + + totalConnections := r.countAllConnections(allHealthyServers) + if totalConnections == 0 { + return + } + + idleFraction := r.config.IdleRebalanceFraction() + maxClose := r.config.MaxClosePerRecovery() + + var closeCount int64 = 0 + for _, recovered := range recoveredServers { + currentLoad := recovered.ConnectionCount() + if currentLoad == 0 { + continue + } + + closeCount = int64(float64(currentLoad) * idleFraction) + if closeCount > int64(maxClose) { + closeCount = int64(maxClose) + } + + recovered.SetLoadMetric(recovered.LoadMetric() - closeCount) + } + + for _, server := range allHealthyServers { + isRecovered := false + for _, recovered := range recoveredServers { + if server == recovered { + isRecovered = true + break + } + } + if isRecovered { + continue + } + currentLoad := server.LoadMetric() + if closeCount > 0 { + redistribute := int64(float64(closeCount) / float64(len(allHealthyServers)-1)) + server.SetLoadMetric(currentLoad + redistribute) + } + } +} + +func (r *ConnectionRedistributor) countAllConnections(servers []*ServerEndpoint) int64 { + var total int64 + for _, s := range servers { + total += s.ConnectionCount() + } + return total +} \ No newline at end of file diff --git a/tools/client-generation/example/go/pkg/client/service.go b/tools/client-generation/example/go/pkg/client/service.go index be941167a..39fd1bba0 100644 --- a/tools/client-generation/example/go/pkg/client/service.go +++ b/tools/client-generation/example/go/pkg/client/service.go @@ -21,12 +21,21 @@ type StatementService interface { CommitTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) RollbackTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) Shutdown() + XAStart(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) + XAEnd(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) + XAPrepare(xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) + XACommit(xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) + XARollback(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) + XARecover(flag int) (*ojpgrpc.XaRecoverResponse, error) + XAForget(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) + XASetTransactionTimeout(seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) + XAGetTransactionTimeout() (*ojpgrpc.XaGetTransactionTimeoutResponse, error) } type MultinodeStatementService struct { connManager *MultinodeConnectionManager - clients map[*ServerEndpoint]*EndpointClient - clientLock sync.RWMutex + clients map[*ServerEndpoint]*EndpointClient + clientLock sync.RWMutex } type EndpointClient struct { @@ -37,7 +46,7 @@ type EndpointClient struct { func NewMultinodeStatementService(connManager *MultinodeConnectionManager) *MultinodeStatementService { return &MultinodeStatementService{ connManager: connManager, - clients: make(map[*ServerEndpoint]*EndpointClient), + clients: make(map[*ServerEndpoint]*EndpointClient), } } @@ -80,8 +89,10 @@ func (s *MultinodeStatementService) ExecuteUpdate(session *ojpgrpc.SessionInfo, return nil, err } + server.IncrConnection() result, err := epClient.client.ExecuteUpdate(session, sql) if err != nil { + server.DecrConnection() if IsConnectionLevelError(err) { server.MarkUnhealthy() s.connManager.handleServerFailure(server, err) @@ -102,14 +113,23 @@ func (s *MultinodeStatementService) ExecuteQuery(session *ojpgrpc.SessionInfo, s return nil, err } + server.IncrConnection() results, err := epClient.client.ExecuteQuery(session, sql) if err != nil { + server.DecrConnection() if IsConnectionLevelError(err) { server.MarkUnhealthy() s.connManager.handleServerFailure(server, err) } return nil, err } + + if results != nil { + currentLoad := server.LoadMetric() + server.SetLoadMetric(currentLoad + int64(len(results))) + } + server.DecrConnection() + return results, nil } @@ -185,6 +205,123 @@ func (s *MultinodeStatementService) Shutdown() { s.clients = make(map[*ServerEndpoint]*EndpointClient) } +func (s *MultinodeStatementService) XAStart(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XAStart(xid, flags) +} + +func (s *MultinodeStatementService) XAEnd(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XAEnd(xid, flags) +} + +func (s *MultinodeStatementService) XAPrepare(xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XAPrepare(xid) +} + +func (s *MultinodeStatementService) XACommit(xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XACommit(xid, onePhase) +} + +func (s *MultinodeStatementService) XARollback(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XARollback(xid) +} + +func (s *MultinodeStatementService) XARecover(flag int) (*ojpgrpc.XaRecoverResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XARecover(flag) +} + +func (s *MultinodeStatementService) XAForget(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XAForget(xid) +} + +func (s *MultinodeStatementService) XASetTransactionTimeout(seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XASetTransactionTimeout(seconds) +} + +func (s *MultinodeStatementService) XAGetTransactionTimeout() (*ojpgrpc.XaGetTransactionTimeoutResponse, error) { + server := s.connManager.selectServer("") + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } + + epClient, err := s.getClient(server) + if err != nil { + return nil, err + } + return epClient.client.XAGetTransactionTimeout() +} + type GrpcStatementServiceClient struct { address string client ojpgrpc.StatementServiceClient @@ -304,6 +441,105 @@ func (c *GrpcStatementServiceClient) RollbackTransaction(session *ojpgrpc.Sessio return c.client.RollbackTransaction(context.Background(), session) } +func (c *GrpcStatementServiceClient) XAStart(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaStartRequest{ + Xid: xid, + Flags: int32(flags), + } + return c.client.XaStart(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) XAEnd(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaEndRequest{ + Xid: xid, + Flags: int32(flags), + } + return c.client.XaEnd(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) XAPrepare(xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaPrepareRequest{Xid: xid} + return c.client.XaPrepare(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) XACommit(xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaCommitRequest{ + Xid: xid, + OnePhase: onePhase, + } + return c.client.XaCommit(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) XARollback(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaRollbackRequest{Xid: xid} + return c.client.XaRollback(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) XARecover(flag int) (*ojpgrpc.XaRecoverResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaRecoverRequest{Flag: int32(flag)} + return c.client.XaRecover(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) XAForget(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaForgetRequest{Xid: xid} + return c.client.XaForget(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) XASetTransactionTimeout(seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaSetTransactionTimeoutRequest{Seconds: int32(seconds)} + return c.client.XaSetTransactionTimeout(context.Background(), req) +} + +func (c *GrpcStatementServiceClient) XAGetTransactionTimeout() (*ojpgrpc.XaGetTransactionTimeoutResponse, error) { + if c.client == nil { + if err := c.EnsureConnected(); err != nil { + return nil, err + } + } + req := &ojpgrpc.XaGetTransactionTimeoutRequest{} + return c.client.XaGetTransactionTimeout(context.Background(), req) +} + func (c *GrpcStatementServiceClient) Shutdown() { if c.conn != nil { c.conn.Close() From 359c9a37db977d385a48347f78c1e2d1309fddca Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Sat, 16 May 2026 17:17:57 +0200 Subject: [PATCH 05/12] cleanup update go client --- .sisyphus/boulder.json | 7 + .sisyphus/plans/ojp-go-grpc-client.md | 319 ++++++++++++++++++ tools/client-generation/example/go/main.go | 75 ++-- .../example/go/pkg/client/multinode.go | 25 +- .../example/go/pkg/client/service.go | 224 ++++++------ .../client-generation/example/rust/Cargo.toml | 10 - .../example/rust/src/main.rs | 131 ------- .../example/typescript/package.json | 18 - .../example/typescript/src/index.ts | 77 ----- .../example/typescript/tsconfig.json | 14 - 10 files changed, 511 insertions(+), 389 deletions(-) create mode 100644 .sisyphus/boulder.json create mode 100644 .sisyphus/plans/ojp-go-grpc-client.md delete mode 100644 tools/client-generation/example/rust/Cargo.toml delete mode 100644 tools/client-generation/example/rust/src/main.rs delete mode 100644 tools/client-generation/example/typescript/package.json delete mode 100644 tools/client-generation/example/typescript/src/index.ts delete mode 100644 tools/client-generation/example/typescript/tsconfig.json diff --git a/.sisyphus/boulder.json b/.sisyphus/boulder.json new file mode 100644 index 000000000..ae73102f4 --- /dev/null +++ b/.sisyphus/boulder.json @@ -0,0 +1,7 @@ +{ + "active_plan": "/home/jay/code/ojp/.sisyphus/plans/ojp-go-grpc-client.md", + "started_at": "2026-05-06T00:00:00Z", + "session_ids": ["ses_start"], + "plan_name": "ojp-go-grpc-client", + "worktree_path": null +} \ No newline at end of file diff --git a/.sisyphus/plans/ojp-go-grpc-client.md b/.sisyphus/plans/ojp-go-grpc-client.md new file mode 100644 index 000000000..8f0f07293 --- /dev/null +++ b/.sisyphus/plans/ojp-go-grpc-client.md @@ -0,0 +1,319 @@ +# OJP Go gRPC Client Implementation Plan + +## TL;DR + +> **Quick Summary**: Create a full-featured Go gRPC client for OJP (Open Journaling Protocol) with built-in connection management, load balancing, failover, health checks, transaction support, and retry logic - matching the capabilities of the existing Java JDBC driver. +> +> **Deliverables**: +> - Go client library with connection pooling and health checking +> - Load balancing across multiple OJP server endpoints +> - Automatic failover with retry and backoff +> - Server-side transaction management (start/commit/rollback RPC) +> - Integration test suite for both implementations +> +> **Estimated Effort**: Large +> **Parallel Execution**: YES - 4 waves +> **Critical Path**: Module setup → Generated code → Core client → Integration tests + +--- + +## Context + +### Original Request +User wants to create a Go gRPC client for OJP that: +1. Uses the existing gRPC protocol (StatementService.proto) - not just generated stubs +2. Has full features like existing Java JDBC: connection management, load balancing, failover, transactions +3. Test both implementations against same SQL operations +4. Use server-side transactions (current pattern) + +### Interview Summary + +**Key Discussions**: +- Current generated Go client (tools/client-generation/example/go/main.go) is too basic +- Needs: connection pooling, load balancing, health checks, failover, transactions, retry logic +- Test both Java JDBC and Go clients with same tests +- Server-side transactions (like existing Java client) + +**Research Findings**: +- OJP uses StatementService.proto with these methods: connect, executeUpdate, executeQuery (streaming), fetchNextRows, createLob, readLob, terminateSession, startTransaction, commitTransaction, rollbackTransaction, callResource, and XA methods +- Java client uses StatementServiceGrpcClient with BlockingStub + async Stub for streaming +- Existing load balancing via MultinodeConnectionManager with server health tracking +- Tests use retry logic with exponential backoff for connection-level errors + +--- + +## Work Objectives + +### Core Objective +Implement a production-ready Go gRPC client for OJP protocol that provides equivalent functionality to the existing Java JDBC driver. + +### Concrete Deliverables +- Go module with generated gRPC stubs integrated +- Connection pool implementation +- Load balancer with round-robin and weighted selection +- Health checker for server endpoints +- Failover with automatic retry to standby servers +- Transaction manager using server-side RPC calls +- Retry logic with exponential backoff for connection errors +- Integration tests for both implementations + +### Definition of Done +- [ ] Go client can connect to OJP server and execute SQL +- [ ] Load balancing works across 2+ server endpoints +- [ ] Failover works when primary server is unavailable +- [ ] Transaction commit/rollback works +- [ ] Integration tests pass for both clients on same SQL + +### Must Have +- Connect to OJP server with authentication +- Execute SQL with parameters (prepared statements) +- Stream result sets +- Transaction management +- Health checking +- Automatic failover + +### Must NOT Have (Guardrails) +- JDBC interface compatibility (that's a separate JDBC-over-gRPC layer) +- SQL enhancement logic (not client responsibility) +- Native database drivers (handled by OJP server) + +--- + +## Verification Strategy (MANDATORY) + +### Test Decision +- **Infrastructure exists**: YES - existing Go + buf setup in tools/client-generation +- **Automated tests**: YES - Tests after implementation +- **Framework**: go test + integration tests +- **If Tests**: Each feature requires verification test + +### QA Policy +Every task MUST include agent-executed QA scenarios. +- Integration tests connect to running OJP server +- Load balance verification: distribute N queries, verify distribution +- Failover verification: kill server, verify auto-switch +- Transaction verification: begin commit rollback cycle + +--- + +## Execution Strategy + +### Parallel Execution Waves + +``` +Wave 1 (Foundation - can start immediately): +├── Task 1: Go module setup with go.mod and dependencies +├── Task 2: Generate gRPC code from StatementService.proto using buf +├── Task 3: Connection/Channel management layer +└── Task 4: Basic client wrapper - Connect + ExecuteUpdate + ExecuteQuery + +Wave 2 (Core Features - after Wave 1): +├── Task 5: Server endpoint management and health checking +├── Task 6: Load balancer - round-robin and weighted selection +├── Task 7: Failover with retry and exponential backoff +├── Task 8: Transaction manager (start/commit/rollback RPC) +├── Task 9: Session management and reconnection +└── Task 10: Error classification (retry vs non-retry) + +Wave 3 (Advanced Features - after Wave 2): +├── Task 11: Streaming result set handling (ExecuteQuery) +├── Task 12: LOB creation and reading (createLob/readLob) +├── Task 13: XA transaction support +├── Task 14: Connection pool for reuse +└── Task 15: Configuration and builder pattern + +Wave FINAL (After ALL tasks): +├── Task F1: Integration test suite +├── Task F2: Test both implementations side-by-side +├── Task F3: Documentation +└── Task F4: Example usage +``` + +### Dependency Matrix +- **1-4**: - - 5-10, 5-10 +- **5**: 4 - 6, 7 +- **6**: 5 - 8 +- **7**: 5 - 8 +- **8**: 5, 6, 7 - 10 +- **9**: 8 - 10 +- **10**: 7, 8, 9 - 11-14 +- **11**: 4 - - +- **12**: 4, 10 - - +- **13**: 10 - - +- **14**: 10 - - +- **15**: 4, 5 - - + +--- + +## TODOs + +- [ ] 1. Go module setup with go.mod and dependencies + + **What to do**: + - Create new Go module structure for OJP Go client + - Copy and adapt go.mod from tools/client-generation/example/go/ + - Add necessary dependencies for gRPC, health checking, connection pooling + + **References**: + - `tools/client-generation/example/go/go.mod` - Reference go.mod structure + - `ojp-grpc-commons/src/main/proto/StatementService.proto` - Protocol definitions + +- [ ] 2. Generate gRPC code from StatementService.proto using buf + + **What to do**: + - Run buf generate to create Go gRPC stubs + - Verify generated code compiles + - Create module wrapper for import convenience + +- [ ] 3. Connection/Channel management layer + + **What to do**: + - Create ManagedChannel pool/reuse + - Implement connection caching + - Add graceful shutdown handling + +- [ ] 4. Basic client wrapper - Connect + ExecuteUpdate + ExecuteQuery + + **What to do**: + - Implement Connect() method matching StatementService.proto + - Implement ExecuteUpdate() with parameter support + - Implement ExecuteQuery() with streaming results + +- [ ] 5. Server endpoint management and health checking + + **What to do**: + - Create ServerEndpoint struct with host:port, health status + - Implement health checking (periodic ping/connect check) + - Track server up/down status + +- [ ] 6. Load balancer - round-robin and weighted selection + + **What to do**: + - Implement round-robin selection + - Implement weighted selection based on server capacity + - Skip unhealthy servers in selection + +- [ ] 7. Failover with retry and exponential backoff + + **What to do**: + - Detect connection errors + - Implement retry with exponential backoff (initial 100ms, max 3 retries) + - Auto-switch to healthy server on failure + +- [ ] 8. Transaction manager (start/commit/rollback RPC) + + **What to do**: + - Implement StartTransaction() RPC call + - Implement CommitTransaction() RPC call + - Implement RollbackTransaction() RPC call + +- [ ] 9. Session management and reconnection + + **What to do**: + - Track session state (sessionUUID) + - Handle session invalidation + - Implement reconnection logic + +- [ ] 10. Error classification (retry vs non-retry) + + **What to do**: + - Classify errors as retryable vs non-retryable + - Handle StatusRuntimeException mapping + +- [ ] 11. Streaming result set handling (ExecuteQuery) + + **What to do**: + - Handle streaming OpResult responses + - Implement result iterator + +- [ ] 12. LOB creation and reading (createLob/readLob) + + **What to do**: + - Implement createLob streaming RPC + - Implement readLob streaming RPC + +- [ ] 13. XA transaction support + + **What to do**: + - Implement xaStart, xaEnd, xaPrepare, xaCommit + - Implement xaRollback, xaRecover + +- [ ] 14. Connection pool for reuse + + **What to do**: + - Implement connection pooling + - Implement idle connection cleanup + +- [ ] 15. Configuration and builder pattern + + **What to do**: + - Create Config struct for client options + - Implement builder pattern for client creation + +- [ ] F1. Integration test suite + + **What to do**: + - Create Go integration tests similar to MultinodeIntegrationTest + - Test CRUD operations + - Test transactions + +- [ ] F2. Test both implementations side-by-side + + **What to do**: + - Run same SQL tests against both Java JDBC and Go client + - Verify feature parity + +- [ ] F3. Documentation + + **What to do**: + - README with usage examples + - API documentation + +- [ ] F4. Example usage + + **What to do**: + - Update example/go/main.go with full features + - Create more examples + +--- + +## Final Verification Wave (MANDATORY) + +- [ ] V1. **Plan Compliance Audit** — `oracle` + Verify all Must Have items addressed and Must NOT Have items avoided. + +- [ ] V2. **Code Quality Review** — Build and test verification + Run go vet, go build, go test to verify correctness. + +- [ ] V3. **Real Integration Test** — Execute integration tests + Run tests against running OJP server. + +- [ ] V4. **Both Implementations Test** — Verify feature parity + Run same tests against both Java JDBC and Go clients. + +--- + +## Commit Strategy + +- **Tasks 1-4**: `feat(client): Go module setup and basic client` +- **Tasks 5-10**: `feat(client): load balancing and failover` +- **Tasks 11-15**: `feat(client): advanced features` +- **Integration**: `test(client): integration tests` + +--- + +## Success Criteria + +### Verification Commands +```bash +go build ./... +go test ./... +``` + +### Final Checklist +- [ ] Go client connects to OJP server +- [ ] Load balancing distributes queries +- [ ] Failover works when server unavailable +- [ ] Transactions commit/rollback work +- [ ] Integration tests pass +- [ ] Both implementations feature parity \ No newline at end of file diff --git a/tools/client-generation/example/go/main.go b/tools/client-generation/example/go/main.go index eada535e9..e848e16ec 100644 --- a/tools/client-generation/example/go/main.go +++ b/tools/client-generation/example/go/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "log" "os" @@ -68,32 +69,32 @@ func testRoundRobin() { ClientUUID: "test-roundrobin", } - session, err := service.Connect(details) + session, err := service.Connect(context.Background(), details) if err != nil { log.Fatalf("Connect failed: %v", err) } log.Printf("Connected! Session: %s", session.GetSessionUUID()) - _, err = service.ExecuteUpdate(session, "CREATE TABLE IF NOT EXISTS test_rr(id INT PRIMARY KEY, server VARCHAR(100))") + _, err = service.ExecuteUpdate(context.Background(), session, "CREATE TABLE IF NOT EXISTS test_rr(id INT PRIMARY KEY, server VARCHAR(100))") if err != nil { log.Fatalf("Create table failed: %v", err) } for i := 0; i < 4; i++ { sql := fmt.Sprintf("INSERT INTO test_rr(id, server) VALUES (%d, 'server-%d') ON CONFLICT (id) DO UPDATE SET server = EXCLUDED.server", i, i%2) - _, err = service.ExecuteUpdate(session, sql) + _, err = service.ExecuteUpdate(context.Background(), session, sql) if err != nil { log.Printf("Insert %d failed: %v", i, err) } } - results, err := service.ExecuteQuery(session, "SELECT id, server FROM test_rr ORDER BY id") + results, err := service.ExecuteQuery(context.Background(), session, "SELECT id, server FROM test_rr ORDER BY id") if err != nil { log.Fatalf("Query failed: %v", err) } log.Printf("Got %d results from round-robin inserts", len(results)) - service.TerminateSession(session) + service.TerminateSession(context.Background(), session) log.Printf("Round-robin test completed") } @@ -120,20 +121,20 @@ func testSessionStickiness() { ClientUUID: "test-sticky", } - session, err := service.Connect(details) + session, err := service.Connect(context.Background(), details) if err != nil { log.Fatalf("Connect failed: %v", err) } log.Printf("Connected! Session: %s", session.GetSessionUUID()) - _, err = service.ExecuteUpdate(session, "CREATE TABLE IF NOT EXISTS test_sticky(id INT PRIMARY KEY, data VARCHAR(100))") + _, err = service.ExecuteUpdate(context.Background(), session, "CREATE TABLE IF NOT EXISTS test_sticky(id INT PRIMARY KEY, data VARCHAR(100))") if err != nil { log.Fatalf("Create table failed: %v", err) } for i := 0; i < 5; i++ { sql := fmt.Sprintf("INSERT INTO test_sticky(id, data) VALUES (%d, 'sticky-%d') ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data", i, i) - _, err = service.ExecuteUpdate(session, sql) + _, err = service.ExecuteUpdate(context.Background(), session, sql) if err != nil { log.Printf("Insert %d failed: %v", i, err) } @@ -146,7 +147,7 @@ func testSessionStickiness() { log.Printf(" Endpoint %s: healthy=%v, connCount=%d", ep.Address(), ep.IsHealthy(), ep.ConnectionCount()) } - service.TerminateSession(session) + service.TerminateSession(context.Background(), session) log.Printf("Session stickiness test completed") } @@ -181,7 +182,7 @@ func testHealthCheck() { service := client.NewMultinodeStatementService(connManager) defer service.Shutdown() - session, err := service.Connect(details) + session, err := service.Connect(context.Background(), details) if err != nil { log.Fatalf("Connect failed: %v", err) } @@ -196,7 +197,7 @@ func testHealthCheck() { log.Printf(" Endpoint %s: healthy=%v", ep.Address(), ep.IsHealthy()) } - service.TerminateSession(session) + service.TerminateSession(context.Background(), session) log.Printf("Health check test completed") } @@ -233,7 +234,7 @@ func testConcurrentConnections() { var session *grpc.SessionInfo var err error for attempt := 0; attempt < 3; attempt++ { - session, err = service.Connect(details) + session, err = service.Connect(context.Background(), details) if err == nil { break } @@ -246,14 +247,14 @@ func testConcurrentConnections() { } sql := fmt.Sprintf("SELECT %d as result", idx*100) - qResults, err := service.ExecuteQuery(session, sql) + qResults, err := service.ExecuteQuery(context.Background(), session, sql) if err != nil { results <- fmt.Sprintf("goroutine %d: query failed: %v", idx, err) } else { results <- fmt.Sprintf("goroutine %d: got %d results", idx, len(qResults)) } - service.TerminateSession(session) + service.TerminateSession(context.Background(), session) }(i) } @@ -290,29 +291,29 @@ func testTransactions() { ClientUUID: "test-transaction", } - session, err := service.Connect(details) + session, err := service.Connect(context.Background(), details) if err != nil { log.Fatalf("Connect failed: %v", err) } log.Printf("Connected! Session: %s", session.GetSessionUUID()) - _, err = service.ExecuteUpdate(session, "CREATE TABLE IF NOT EXISTS test_txn(id INT PRIMARY KEY, value VARCHAR(100))") + _, err = service.ExecuteUpdate(context.Background(), session, "CREATE TABLE IF NOT EXISTS test_txn(id INT PRIMARY KEY, value VARCHAR(100))") if err != nil { log.Fatalf("Create table failed: %v", err) } - sessionWithTXN, err := service.StartTransaction(session) + sessionWithTXN, err := service.StartTransaction(context.Background(), session) if err != nil { log.Printf("StartTransaction not supported (OK): %v", err) } else { log.Printf("Transaction started! Session: %s", sessionWithTXN.GetSessionUUID()) - _, err = service.ExecuteUpdate(sessionWithTXN, "INSERT INTO test_txn(id, value) VALUES (1, 'transactional')") + _, err = service.ExecuteUpdate(context.Background(), sessionWithTXN, "INSERT INTO test_txn(id, value) VALUES (1, 'transactional')") if err != nil { log.Printf("Insert in transaction failed: %v", err) } - _, err = service.CommitTransaction(sessionWithTXN) + _, err = service.CommitTransaction(context.Background(), sessionWithTXN) if err != nil { log.Printf("Commit failed: %v", err) } else { @@ -320,7 +321,7 @@ func testTransactions() { } } - results, err := service.ExecuteQuery(session, "SELECT id, value FROM test_txn WHERE id = 1") + results, err := service.ExecuteQuery(context.Background(), session, "SELECT id, value FROM test_txn WHERE id = 1") if err != nil { log.Printf("Query failed: %v", err) } else if len(results) > 0 { @@ -330,7 +331,7 @@ func testTransactions() { } } - service.TerminateSession(session) + service.TerminateSession(context.Background(), session) log.Printf("Transaction test completed") } @@ -356,7 +357,7 @@ func testXA() { ClientUUID: "test-xa", } - session, err := service.Connect(details) + session, err := service.Connect(context.Background(), details) if err != nil { log.Fatalf("Connect failed: %v", err) } @@ -368,80 +369,80 @@ func testXA() { BranchQualifier: []byte("test-xa-branch"), } - resp, err := service.XAStart(xid, 0) + resp, err := service.XAStart(context.Background(), xid, 0) if err != nil { log.Printf("XAStart failed (may not be supported): %v", err) } else { log.Printf("XAStart: success=%v", resp.GetSuccess()) } - _, err = service.ExecuteUpdate(session, "CREATE TABLE IF NOT EXISTS test_xa(id INT PRIMARY KEY, value VARCHAR(100))") + _, err = service.ExecuteUpdate(context.Background(), session, "CREATE TABLE IF NOT EXISTS test_xa(id INT PRIMARY KEY, value VARCHAR(100))") if err != nil { log.Printf("Create table failed: %v", err) } - _, err = service.ExecuteUpdate(session, "INSERT INTO test_xa(id, value) VALUES (1, 'xa-test')") + _, err = service.ExecuteUpdate(context.Background(), session, "INSERT INTO test_xa(id, value) VALUES (1, 'xa-test')") if err != nil { log.Printf("Insert failed: %v", err) } - resp, err = service.XAEnd(xid, 0) + resp, err = service.XAEnd(context.Background(), xid, 0) if err != nil { log.Printf("XAEnd failed: %v", err) } else { log.Printf("XAEnd: success=%v", resp.GetSuccess()) } - prepResp, err := service.XAPrepare(xid) + prepResp, err := service.XAPrepare(context.Background(), xid) if err != nil { log.Printf("XAPrepare failed: %v", err) } else { log.Printf("XAPrepare: result=%d", prepResp.GetResult()) } - commitResp, err := service.XACommit(xid, false) + commitResp, err := service.XACommit(context.Background(), xid, false) if err != nil { log.Printf("XACommit failed: %v", err) } else { log.Printf("XACommit: success=%v", commitResp.GetSuccess()) } - results, err := service.ExecuteQuery(session, "SELECT id, value FROM test_xa WHERE id = 1") + results, err := service.ExecuteQuery(context.Background(), session, "SELECT id, value FROM test_xa WHERE id = 1") if err != nil { log.Printf("Query after XA failed: %v", err) } else if len(results) > 0 && results[0].GetQueryResult() != nil { log.Printf("XA data persisted correctly") } - recoverResp, err := service.XARecover(0) + recoverResp, err := service.XARecover(context.Background(), 0) if err != nil { log.Printf("XARecover failed: %v", err) } else { log.Printf("XARecover: %d xids", len(recoverResp.GetXids())) } - forgetResp, err := service.XAForget(xid) + forgetResp, err := service.XAForget(context.Background(), xid) if err != nil { log.Printf("XAForget failed: %v", err) } else { log.Printf("XAForget: success=%v", forgetResp.GetSuccess()) } - timeoutResp, err := service.XASetTransactionTimeout(30) + timeoutResp, err := service.XASetTransactionTimeout(context.Background(), 30) if err != nil { log.Printf("XASetTransactionTimeout failed: %v", err) } else { log.Printf("XASetTransactionTimeout: success=%v", timeoutResp.GetSuccess()) } - getTimeoutResp, err := service.XAGetTransactionTimeout() + getTimeoutResp, err := service.XAGetTransactionTimeout(context.Background()) if err != nil { log.Printf("XAGetTransactionTimeout failed: %v", err) } else { log.Printf("XAGetTransactionTimeout: seconds=%d", getTimeoutResp.GetSeconds()) } - service.TerminateSession(session) + service.TerminateSession(context.Background(), session) log.Printf("XA test completed") } @@ -470,7 +471,7 @@ func testLoadMetrics() { ClientUUID: "test-load", } - session, err := service.Connect(details) + session, err := service.Connect(context.Background(), details) if err != nil { log.Fatalf("Connect failed: %v", err) } @@ -478,7 +479,7 @@ func testLoadMetrics() { for i := 0; i < 3; i++ { sql := fmt.Sprintf("SELECT * FROM generate_series(1, %d)", i*10) - results, err := service.ExecuteQuery(session, sql) + results, err := service.ExecuteQuery(context.Background(), session, sql) if err != nil { log.Printf("Query %d failed: %v", i, err) } else { @@ -492,6 +493,6 @@ func testLoadMetrics() { log.Printf(" %s: load_metric=%d", ep.Address(), ep.LoadMetric()) } - service.TerminateSession(session) + service.TerminateSession(context.Background(), session) log.Printf("Load metrics test completed") } \ No newline at end of file diff --git a/tools/client-generation/example/go/pkg/client/multinode.go b/tools/client-generation/example/go/pkg/client/multinode.go index faa9ac7d0..b41fa812f 100644 --- a/tools/client-generation/example/go/pkg/client/multinode.go +++ b/tools/client-generation/example/go/pkg/client/multinode.go @@ -95,23 +95,33 @@ func parseURL(url string) (*ServerEndpoint, error) { fmt.Sscanf(parts[1], "%d", &port) } else { host = url - port = 1059 + port = DefaultOJPGRPCPort } if host == "" { host = "localhost" } if port == 0 { - port = 1059 + port = DefaultOJPGRPCPort } return NewServerEndpoint(host, port), nil } -func (m *MultinodeConnectionManager) Connect(details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { +func (m *MultinodeConnectionManager) Connect(ctx context.Context, details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { server := m.selectServer("") if server == nil { - return nil, fmt.Errorf("no healthy server available") + // Retry with a different server after a brief delay + RetryWithBackoff(ctx, 3, 100*time.Millisecond, 500*time.Millisecond, func() error { + server = m.selectServer("") + if server == nil { + return fmt.Errorf("no healthy server available") + } + return nil + }) + if server == nil { + return nil, fmt.Errorf("no healthy server available") + } } channel, err := m.getChannel(server) @@ -120,7 +130,7 @@ func (m *MultinodeConnectionManager) Connect(details *ojpgrpc.ConnectionDetails) } client := ojpgrpc.NewStatementServiceClient(channel) - resp, err := client.Connect(context.Background(), details) + resp, err := client.Connect(ctx, details) if err != nil { server.MarkUnhealthy() m.handleServerFailure(server, err) @@ -278,12 +288,15 @@ func (m *MultinodeConnectionManager) checkEndpoint(ep *ServerEndpoint) { ClientUUID: "health-check-client", } - _, err = client.Connect(ctx, details) + session, err := client.Connect(ctx, details) if err != nil { ep.MarkUnhealthy() return } + // Terminate the health check session to avoid server-side session leaks + _, _ = client.TerminateSession(ctx, session) + ep.MarkHealthy() } diff --git a/tools/client-generation/example/go/pkg/client/service.go b/tools/client-generation/example/go/pkg/client/service.go index 39fd1bba0..d8a733d05 100644 --- a/tools/client-generation/example/go/pkg/client/service.go +++ b/tools/client-generation/example/go/pkg/client/service.go @@ -4,32 +4,37 @@ import ( "context" "fmt" "io" + "math" "strings" "sync" + "time" ojpgrpc "github.com/ojp-client/gen/go/com/openjproxy/grpc" grpc "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) +// DefaultOJPGRPCPort is the default gRPC port for OJP servers. +const DefaultOJPGRPCPort = 1059 + type StatementService interface { - Connect(details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) - ExecuteUpdate(session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) - ExecuteQuery(session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) - TerminateSession(session *ojpgrpc.SessionInfo) error - StartTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) - CommitTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) - RollbackTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) + Connect(ctx context.Context, details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) + ExecuteUpdate(ctx context.Context, session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) + ExecuteQuery(ctx context.Context, session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) + TerminateSession(ctx context.Context, session *ojpgrpc.SessionInfo) error + StartTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) + CommitTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) + RollbackTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) Shutdown() - XAStart(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) - XAEnd(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) - XAPrepare(xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) - XACommit(xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) - XARollback(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) - XARecover(flag int) (*ojpgrpc.XaRecoverResponse, error) - XAForget(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) - XASetTransactionTimeout(seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) - XAGetTransactionTimeout() (*ojpgrpc.XaGetTransactionTimeoutResponse, error) + XAStart(ctx context.Context, xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) + XAEnd(ctx context.Context, xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) + XAPrepare(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) + XACommit(ctx context.Context, xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) + XARollback(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) + XARecover(ctx context.Context, flag int) (*ojpgrpc.XaRecoverResponse, error) + XAForget(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) + XASetTransactionTimeout(ctx context.Context, seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) + XAGetTransactionTimeout(ctx context.Context) (*ojpgrpc.XaGetTransactionTimeoutResponse, error) } type MultinodeStatementService struct { @@ -74,11 +79,11 @@ func (s *MultinodeStatementService) getClient(server *ServerEndpoint) (*Endpoint return epClient, nil } -func (s *MultinodeStatementService) Connect(details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { - return s.connManager.Connect(details) +func (s *MultinodeStatementService) Connect(ctx context.Context, details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { + return s.connManager.Connect(ctx, details) } -func (s *MultinodeStatementService) ExecuteUpdate(session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) { +func (s *MultinodeStatementService) ExecuteUpdate(ctx context.Context, session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) { server := s.connManager.selectServer(session.GetSessionUUID()) if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -90,7 +95,7 @@ func (s *MultinodeStatementService) ExecuteUpdate(session *ojpgrpc.SessionInfo, } server.IncrConnection() - result, err := epClient.client.ExecuteUpdate(session, sql) + result, err := epClient.client.ExecuteUpdate(ctx, session, sql) if err != nil { server.DecrConnection() if IsConnectionLevelError(err) { @@ -102,7 +107,7 @@ func (s *MultinodeStatementService) ExecuteUpdate(session *ojpgrpc.SessionInfo, return result, nil } -func (s *MultinodeStatementService) ExecuteQuery(session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) { +func (s *MultinodeStatementService) ExecuteQuery(ctx context.Context, session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) { server := s.connManager.selectServer(session.GetSessionUUID()) if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -114,7 +119,7 @@ func (s *MultinodeStatementService) ExecuteQuery(session *ojpgrpc.SessionInfo, s } server.IncrConnection() - results, err := epClient.client.ExecuteQuery(session, sql) + results, err := epClient.client.ExecuteQuery(ctx, session, sql) if err != nil { server.DecrConnection() if IsConnectionLevelError(err) { @@ -133,20 +138,20 @@ func (s *MultinodeStatementService) ExecuteQuery(session *ojpgrpc.SessionInfo, s return results, nil } -func (s *MultinodeStatementService) TerminateSession(session *ojpgrpc.SessionInfo) error { +func (s *MultinodeStatementService) TerminateSession(ctx context.Context, session *ojpgrpc.SessionInfo) error { sessUUID := session.GetSessionUUID() if sessUUID != "" { if bound := s.connManager.connTracker.GetBoundServer(sessUUID); bound != nil { epClient, err := s.getClient(bound) if err == nil { - return epClient.client.TerminateSession(session) + return epClient.client.TerminateSession(ctx, session) } } } return nil } -func (s *MultinodeStatementService) StartTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { +func (s *MultinodeStatementService) StartTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -157,7 +162,7 @@ func (s *MultinodeStatementService) StartTransaction(session *ojpgrpc.SessionInf return nil, err } - result, err := epClient.client.StartTransaction(session) + result, err := epClient.client.StartTransaction(ctx, session) if err != nil { return nil, err } @@ -169,7 +174,7 @@ func (s *MultinodeStatementService) StartTransaction(session *ojpgrpc.SessionInf return result, nil } -func (s *MultinodeStatementService) CommitTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { +func (s *MultinodeStatementService) CommitTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { server := s.connManager.selectServer(session.GetSessionUUID()) if server == nil { return nil, fmt.Errorf("no server available") @@ -179,10 +184,10 @@ func (s *MultinodeStatementService) CommitTransaction(session *ojpgrpc.SessionIn if err != nil { return nil, err } - return epClient.client.CommitTransaction(session) + return epClient.client.CommitTransaction(ctx, session) } -func (s *MultinodeStatementService) RollbackTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { +func (s *MultinodeStatementService) RollbackTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { server := s.connManager.selectServer(session.GetSessionUUID()) if server == nil { return nil, fmt.Errorf("no server available") @@ -192,7 +197,7 @@ func (s *MultinodeStatementService) RollbackTransaction(session *ojpgrpc.Session if err != nil { return nil, err } - return epClient.client.RollbackTransaction(session) + return epClient.client.RollbackTransaction(ctx, session) } func (s *MultinodeStatementService) Shutdown() { @@ -205,7 +210,7 @@ func (s *MultinodeStatementService) Shutdown() { s.clients = make(map[*ServerEndpoint]*EndpointClient) } -func (s *MultinodeStatementService) XAStart(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { +func (s *MultinodeStatementService) XAStart(ctx context.Context, xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -215,10 +220,10 @@ func (s *MultinodeStatementService) XAStart(xid *ojpgrpc.XidProto, flags int) (* if err != nil { return nil, err } - return epClient.client.XAStart(xid, flags) + return epClient.client.XAStart(ctx, xid, flags) } -func (s *MultinodeStatementService) XAEnd(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { +func (s *MultinodeStatementService) XAEnd(ctx context.Context, xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -228,10 +233,10 @@ func (s *MultinodeStatementService) XAEnd(xid *ojpgrpc.XidProto, flags int) (*oj if err != nil { return nil, err } - return epClient.client.XAEnd(xid, flags) + return epClient.client.XAEnd(ctx, xid, flags) } -func (s *MultinodeStatementService) XAPrepare(xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) { +func (s *MultinodeStatementService) XAPrepare(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -241,10 +246,10 @@ func (s *MultinodeStatementService) XAPrepare(xid *ojpgrpc.XidProto) (*ojpgrpc.X if err != nil { return nil, err } - return epClient.client.XAPrepare(xid) + return epClient.client.XAPrepare(ctx, xid) } -func (s *MultinodeStatementService) XACommit(xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) { +func (s *MultinodeStatementService) XACommit(ctx context.Context, xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -254,10 +259,10 @@ func (s *MultinodeStatementService) XACommit(xid *ojpgrpc.XidProto, onePhase boo if err != nil { return nil, err } - return epClient.client.XACommit(xid, onePhase) + return epClient.client.XACommit(ctx, xid, onePhase) } -func (s *MultinodeStatementService) XARollback(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { +func (s *MultinodeStatementService) XARollback(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -267,10 +272,10 @@ func (s *MultinodeStatementService) XARollback(xid *ojpgrpc.XidProto) (*ojpgrpc. if err != nil { return nil, err } - return epClient.client.XARollback(xid) + return epClient.client.XARollback(ctx, xid) } -func (s *MultinodeStatementService) XARecover(flag int) (*ojpgrpc.XaRecoverResponse, error) { +func (s *MultinodeStatementService) XARecover(ctx context.Context, flag int) (*ojpgrpc.XaRecoverResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -280,10 +285,10 @@ func (s *MultinodeStatementService) XARecover(flag int) (*ojpgrpc.XaRecoverRespo if err != nil { return nil, err } - return epClient.client.XARecover(flag) + return epClient.client.XARecover(ctx, flag) } -func (s *MultinodeStatementService) XAForget(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { +func (s *MultinodeStatementService) XAForget(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -293,10 +298,10 @@ func (s *MultinodeStatementService) XAForget(xid *ojpgrpc.XidProto) (*ojpgrpc.Xa if err != nil { return nil, err } - return epClient.client.XAForget(xid) + return epClient.client.XAForget(ctx, xid) } -func (s *MultinodeStatementService) XASetTransactionTimeout(seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) { +func (s *MultinodeStatementService) XASetTransactionTimeout(ctx context.Context, seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -306,10 +311,10 @@ func (s *MultinodeStatementService) XASetTransactionTimeout(seconds int) (*ojpgr if err != nil { return nil, err } - return epClient.client.XASetTransactionTimeout(seconds) + return epClient.client.XASetTransactionTimeout(ctx, seconds) } -func (s *MultinodeStatementService) XAGetTransactionTimeout() (*ojpgrpc.XaGetTransactionTimeoutResponse, error) { +func (s *MultinodeStatementService) XAGetTransactionTimeout(ctx context.Context) (*ojpgrpc.XaGetTransactionTimeoutResponse, error) { server := s.connManager.selectServer("") if server == nil { return nil, fmt.Errorf("no healthy server available") @@ -319,7 +324,7 @@ func (s *MultinodeStatementService) XAGetTransactionTimeout() (*ojpgrpc.XaGetTra if err != nil { return nil, err } - return epClient.client.XAGetTransactionTimeout() + return epClient.client.XAGetTransactionTimeout(ctx) } type GrpcStatementServiceClient struct { @@ -332,7 +337,11 @@ func NewGrpcStatementServiceClient(address string) *GrpcStatementServiceClient { return &GrpcStatementServiceClient{address: address} } -func (c *GrpcStatementServiceClient) EnsureConnected() error { +func (c *GrpcStatementServiceClient) EnsureConnected(ctx context.Context) error { + if c.conn != nil { + return nil + } + parts := strings.Split(c.address, ":") var host string var port int @@ -341,10 +350,10 @@ func (c *GrpcStatementServiceClient) EnsureConnected() error { fmt.Sscanf(parts[1], "%d", &port) } else { host = c.address - port = 1059 + port = DefaultOJPGRPCPort } - conn, err := grpc.DialContext(context.Background(), fmt.Sprintf("%s:%d", host, port), + conn, err := grpc.DialContext(ctx, fmt.Sprintf("%s:%d", host, port), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock(), ) @@ -357,18 +366,18 @@ func (c *GrpcStatementServiceClient) EnsureConnected() error { return nil } -func (c *GrpcStatementServiceClient) Connect(details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { +func (c *GrpcStatementServiceClient) Connect(ctx context.Context, details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } - return c.client.Connect(context.Background(), details) + return c.client.Connect(ctx, details) } -func (c *GrpcStatementServiceClient) ExecuteUpdate(session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) { +func (c *GrpcStatementServiceClient) ExecuteUpdate(ctx context.Context, session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } @@ -377,12 +386,12 @@ func (c *GrpcStatementServiceClient) ExecuteUpdate(session *ojpgrpc.SessionInfo, Session: session, Sql: sql, } - return c.client.ExecuteUpdate(context.Background(), req) + return c.client.ExecuteUpdate(ctx, req) } -func (c *GrpcStatementServiceClient) ExecuteQuery(session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) { +func (c *GrpcStatementServiceClient) ExecuteQuery(ctx context.Context, session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } @@ -391,7 +400,7 @@ func (c *GrpcStatementServiceClient) ExecuteQuery(session *ojpgrpc.SessionInfo, Session: session, Sql: sql, } - stream, err := c.client.ExecuteQuery(context.Background(), req) + stream, err := c.client.ExecuteQuery(ctx, req) if err != nil { return nil, err } @@ -410,40 +419,40 @@ func (c *GrpcStatementServiceClient) ExecuteQuery(session *ojpgrpc.SessionInfo, return results, nil } -func (c *GrpcStatementServiceClient) TerminateSession(session *ojpgrpc.SessionInfo) error { +func (c *GrpcStatementServiceClient) TerminateSession(ctx context.Context, session *ojpgrpc.SessionInfo) error { if c.client == nil { return nil } - _, err := c.client.TerminateSession(context.Background(), session) + _, err := c.client.TerminateSession(ctx, session) return err } -func (c *GrpcStatementServiceClient) StartTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { +func (c *GrpcStatementServiceClient) StartTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } - return c.client.StartTransaction(context.Background(), session) + return c.client.StartTransaction(ctx, session) } -func (c *GrpcStatementServiceClient) CommitTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { +func (c *GrpcStatementServiceClient) CommitTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { if c.client == nil { return nil, nil } - return c.client.CommitTransaction(context.Background(), session) + return c.client.CommitTransaction(ctx, session) } -func (c *GrpcStatementServiceClient) RollbackTransaction(session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { +func (c *GrpcStatementServiceClient) RollbackTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { if c.client == nil { return nil, nil } - return c.client.RollbackTransaction(context.Background(), session) + return c.client.RollbackTransaction(ctx, session) } -func (c *GrpcStatementServiceClient) XAStart(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { +func (c *GrpcStatementServiceClient) XAStart(ctx context.Context, xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } @@ -451,12 +460,12 @@ func (c *GrpcStatementServiceClient) XAStart(xid *ojpgrpc.XidProto, flags int) ( Xid: xid, Flags: int32(flags), } - return c.client.XaStart(context.Background(), req) + return c.client.XaStart(ctx, req) } -func (c *GrpcStatementServiceClient) XAEnd(xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { +func (c *GrpcStatementServiceClient) XAEnd(ctx context.Context, xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } @@ -464,22 +473,22 @@ func (c *GrpcStatementServiceClient) XAEnd(xid *ojpgrpc.XidProto, flags int) (*o Xid: xid, Flags: int32(flags), } - return c.client.XaEnd(context.Background(), req) + return c.client.XaEnd(ctx, req) } -func (c *GrpcStatementServiceClient) XAPrepare(xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) { +func (c *GrpcStatementServiceClient) XAPrepare(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } req := &ojpgrpc.XaPrepareRequest{Xid: xid} - return c.client.XaPrepare(context.Background(), req) + return c.client.XaPrepare(ctx, req) } -func (c *GrpcStatementServiceClient) XACommit(xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) { +func (c *GrpcStatementServiceClient) XACommit(ctx context.Context, xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } @@ -487,61 +496,84 @@ func (c *GrpcStatementServiceClient) XACommit(xid *ojpgrpc.XidProto, onePhase bo Xid: xid, OnePhase: onePhase, } - return c.client.XaCommit(context.Background(), req) + return c.client.XaCommit(ctx, req) } -func (c *GrpcStatementServiceClient) XARollback(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { +func (c *GrpcStatementServiceClient) XARollback(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } req := &ojpgrpc.XaRollbackRequest{Xid: xid} - return c.client.XaRollback(context.Background(), req) + return c.client.XaRollback(ctx, req) } -func (c *GrpcStatementServiceClient) XARecover(flag int) (*ojpgrpc.XaRecoverResponse, error) { +func (c *GrpcStatementServiceClient) XARecover(ctx context.Context, flag int) (*ojpgrpc.XaRecoverResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } req := &ojpgrpc.XaRecoverRequest{Flag: int32(flag)} - return c.client.XaRecover(context.Background(), req) + return c.client.XaRecover(ctx, req) } -func (c *GrpcStatementServiceClient) XAForget(xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { +func (c *GrpcStatementServiceClient) XAForget(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } req := &ojpgrpc.XaForgetRequest{Xid: xid} - return c.client.XaForget(context.Background(), req) + return c.client.XaForget(ctx, req) } -func (c *GrpcStatementServiceClient) XASetTransactionTimeout(seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) { +func (c *GrpcStatementServiceClient) XASetTransactionTimeout(ctx context.Context, seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } req := &ojpgrpc.XaSetTransactionTimeoutRequest{Seconds: int32(seconds)} - return c.client.XaSetTransactionTimeout(context.Background(), req) + return c.client.XaSetTransactionTimeout(ctx, req) } -func (c *GrpcStatementServiceClient) XAGetTransactionTimeout() (*ojpgrpc.XaGetTransactionTimeoutResponse, error) { +func (c *GrpcStatementServiceClient) XAGetTransactionTimeout(ctx context.Context) (*ojpgrpc.XaGetTransactionTimeoutResponse, error) { if c.client == nil { - if err := c.EnsureConnected(); err != nil { + if err := c.EnsureConnected(ctx); err != nil { return nil, err } } req := &ojpgrpc.XaGetTransactionTimeoutRequest{} - return c.client.XaGetTransactionTimeout(context.Background(), req) + return c.client.XaGetTransactionTimeout(ctx, req) } func (c *GrpcStatementServiceClient) Shutdown() { if c.conn != nil { c.conn.Close() } +} + +// RetryWithBackoff attempts an operation up to maxRetries times with exponential backoff. +func RetryWithBackoff(ctx context.Context, maxRetries int, initialBackoff, maxBackoff time.Duration, fn func() error) error { + var err error + backoff := initialBackoff + + for attempt := 0; attempt < maxRetries; attempt++ { + if attempt > 0 { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(backoff): + } + backoff = time.Duration(math.Min(float64(maxBackoff), float64(backoff)*2)) + } + + err = fn() + if err == nil { + return nil + } + } + return err } \ No newline at end of file diff --git a/tools/client-generation/example/rust/Cargo.toml b/tools/client-generation/example/rust/Cargo.toml deleted file mode 100644 index d73e2aeee..000000000 --- a/tools/client-generation/example/rust/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "ojp-rust-example" -version = "0.1.0" -edition = "2021" - -[dependencies] -tokio = { version = "1", features = ["macros", "rt-multi-thread"] } -tonic = { version = "0.12", features = ["transport"] } -prost = "0.13" -prost-types = "0.13" diff --git a/tools/client-generation/example/rust/src/main.rs b/tools/client-generation/example/rust/src/main.rs deleted file mode 100644 index 994c69dc9..000000000 --- a/tools/client-generation/example/rust/src/main.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::env; - -use tonic::codegen::http::uri::PathAndQuery; -use tonic::transport::Channel; -use tonic::{codec::ProstCodec, Request}; - -mod google { - pub mod r#type { - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct Date { - #[prost(int32, tag = "1")] - pub year: i32, - #[prost(int32, tag = "2")] - pub month: i32, - #[prost(int32, tag = "3")] - pub day: i32, - } - - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct TimeOfDay { - #[prost(int32, tag = "1")] - pub hours: i32, - #[prost(int32, tag = "2")] - pub minutes: i32, - #[prost(int32, tag = "3")] - pub seconds: i32, - #[prost(int32, tag = "4")] - pub nanos: i32, - } - } -} - -mod com { - pub mod openjproxy { - pub mod grpc { - include!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/generated/com/openjproxy/grpc/com.openjproxy.grpc.rs" - )); - } - } -} - -use com::openjproxy::grpc::{ConnectionDetails, SessionInfo, StatementRequest}; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let addr = env::var("OJP_ADDR").unwrap_or_else(|_| "127.0.0.1:1059".to_string()); - let backend_url = - env::var("OJP_BACKEND_URL").unwrap_or_else(|_| "jdbc:postgresql://postgres:5432/ojp".to_string()); - let db_user = env::var("OJP_DB_USER").unwrap_or_else(|_| "ojp".to_string()); - let db_password = env::var("OJP_DB_PASSWORD").unwrap_or_else(|_| "ojp".to_string()); - - let endpoint = format!("http://{addr}"); - let channel = Channel::from_shared(endpoint)?.connect().await?; - let mut grpc = tonic::client::Grpc::new(channel); - let codec = ProstCodec::default(); - - let connect_path = PathAndQuery::from_static("/com.openjproxy.grpc.StatementService/connect"); - let connect_req = ConnectionDetails { - url: backend_url, - user: db_user, - password: db_password, - client_uuid: "rust-example-client".to_string(), - properties: vec![], - is_xa: false, - server_endpoints: vec![], - cluster_health: String::new(), - }; - let session = grpc - .unary(Request::new(connect_req), connect_path, codec.clone()) - .await? - .into_inner(); - - execute_update( - &mut grpc, - &codec, - &session, - "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", - ) - .await?; - - execute_update( - &mut grpc, - &codec, - &session, - "INSERT INTO demo(id, name) VALUES (2, 'hello from rust') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", - ) - .await?; - - let query_path = PathAndQuery::from_static("/com.openjproxy.grpc.StatementService/executeQuery"); - let query_req = StatementRequest { - session: Some(session.clone()), - sql: "SELECT id, name FROM demo ORDER BY id".to_string(), - parameters: vec![], - statement_uuid: String::new(), - properties: vec![], - }; - let mut stream = grpc - .server_streaming(Request::new(query_req), query_path, codec.clone()) - .await? - .into_inner(); - while let Some(item) = stream.message().await? { - println!("op_result type={} uuid={}", item.r#type, item.uuid); - } - - let terminate_path = PathAndQuery::from_static("/com.openjproxy.grpc.StatementService/terminateSession"); - let _ = grpc - .unary(Request::new(session), terminate_path, codec) - .await?; - - Ok(()) -} - -async fn execute_update( - grpc: &mut tonic::client::Grpc, - codec: &ProstCodec, - session: &SessionInfo, - sql: &str, -) -> Result<(), Box> { - let path = PathAndQuery::from_static("/com.openjproxy.grpc.StatementService/executeUpdate"); - let req = StatementRequest { - session: Some(session.clone()), - sql: sql.to_string(), - parameters: vec![], - statement_uuid: String::new(), - properties: vec![], - }; - let _ = grpc.unary(Request::new(req), path, codec.clone()).await?; - Ok(()) -} diff --git a/tools/client-generation/example/typescript/package.json b/tools/client-generation/example/typescript/package.json deleted file mode 100644 index 7d25caa27..000000000 --- a/tools/client-generation/example/typescript/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "ojp-typescript-example", - "version": "0.1.0", - "private": true, - "scripts": { - "build": "tsc -p tsconfig.json", - "start": "node dist/index.js" - }, - "dependencies": { - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "^1.6.1", - "@connectrpc/connect-node": "^1.6.1" - }, - "devDependencies": { - "@types/node": "^22.18.6", - "typescript": "^5.9.3" - } -} diff --git a/tools/client-generation/example/typescript/src/index.ts b/tools/client-generation/example/typescript/src/index.ts deleted file mode 100644 index ff03a7d09..000000000 --- a/tools/client-generation/example/typescript/src/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { createPromiseClient } from "@connectrpc/connect"; -import { createGrpcTransport } from "@connectrpc/connect-node"; - -import { StatementService } from "../generated/StatementService_connect"; -import { ConnectionDetails, StatementRequest } from "../generated/StatementService_pb"; - -function env(name: string, fallback: string): string { - return process.env[name] ?? fallback; -} - -async function main(): Promise { - const addr = env("OJP_ADDR", "http://127.0.0.1:1059"); - const backendUrl = env("OJP_BACKEND_URL", "jdbc:postgresql://postgres:5432/ojp"); - const dbUser = env("OJP_DB_USER", "ojp"); - const dbPassword = env("OJP_DB_PASSWORD", "ojp"); - - const transport = createGrpcTransport({ - baseUrl: addr, - httpVersion: "2", - }); - - const client = createPromiseClient(StatementService, transport); - - const session = await client.connect( - new ConnectionDetails({ - url: backendUrl, - user: dbUser, - password: dbPassword, - clientUUID: "typescript-example-client", - properties: [], - isXA: false, - serverEndpoints: [], - clusterHealth: "", - }), - ); - - await client.executeUpdate( - new StatementRequest({ - session, - sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", - parameters: [], - statementUUID: "", - properties: [], - }), - ); - - await client.executeUpdate( - new StatementRequest({ - session, - sql: "INSERT INTO demo(id, name) VALUES (3, 'hello from typescript') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", - parameters: [], - statementUUID: "", - properties: [], - }), - ); - - const stream = client.executeQuery( - new StatementRequest({ - session, - sql: "SELECT id, name FROM demo ORDER BY id", - parameters: [], - statementUUID: "", - properties: [], - }), - ); - - for await (const op of stream) { - console.log(`opResult type=${op.type} uuid=${op.uuid}`); - } - - await client.terminateSession(session); -} - -main().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/tools/client-generation/example/typescript/tsconfig.json b/tools/client-generation/example/typescript/tsconfig.json deleted file mode 100644 index cfff35083..000000000 --- a/tools/client-generation/example/typescript/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", - "moduleResolution": "Node", - "strict": true, - "outDir": "dist", - "skipLibCheck": true - }, - "include": [ - "src/**/*.ts", - "generated/**/*.ts" - ] -} From fea1366bb231264e36fce802afe91dd1df4a14c0 Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Tue, 19 May 2026 18:36:25 +0200 Subject: [PATCH 06/12] cleanup --- .sisyphus/boulder.json | 7 - .sisyphus/plans/ojp-go-grpc-client.md | 319 -- ojp-grpc-client-go/README.md | 232 + .../cmd/ojp-grpc-client/main.go | 322 ++ .../cmd/ojp-grpc-client/main_test.go | 155 + ojp-grpc-client-go/docker-compose.db2.yml | 19 + ojp-grpc-client-go/docker-compose.mariadb.yml | 20 + ojp-grpc-client-go/docker-compose.mssql.yml | 17 + ojp-grpc-client-go/docker-compose.mysql.yml | 20 + ojp-grpc-client-go/docker-compose.oracle.yml | 17 + .../docker-compose.postgres18.yml | 20 + ojp-grpc-client-go/go.mod | 16 + ojp-grpc-client-go/go.sum | 42 + .../internal}/client/endpoint.go | 0 .../internal}/client/exception.go | 0 .../internal}/client/health.go | 0 .../internal}/client/multinode.go | 40 +- .../internal}/client/redistributor.go | 0 .../internal}/client/service.go | 8 +- .../openjproxy/grpc/StatementService.pb.go | 4300 +++++++++++++++++ .../grpc/StatementService_grpc.pb.go | 884 ++++ .../gen/go/ojp/transport/v1/containers.pb.go | 542 +++ .../gen/go/org/openjproxy/grpc/echo.pb.go | 174 + .../go/org/openjproxy/grpc/echo_grpc.pb.go | 121 + .../scripts/run-db2-crud-test.ps1 | 128 + .../scripts/run-db2-crud-test.sh | 20 + .../scripts/run-mariadb-crud-test.ps1 | 125 + .../scripts/run-mariadb-crud-test.sh | 20 + .../scripts/run-mssql-crud-test.ps1 | 128 + .../scripts/run-mssql-crud-test.sh | 20 + .../scripts/run-mysql-crud-test.ps1 | 125 + .../scripts/run-mysql-crud-test.sh | 20 + .../scripts/run-oracle-crud-test.ps1 | 128 + .../scripts/run-oracle-crud-test.sh | 20 + .../scripts/run-postgres18-crud-test.ps1 | 124 + .../scripts/run-postgres18-crud-test.sh | 21 + ojp-grpc-client-go/testdata/connection.csv | 10 + .../testdata/mariadb/init/01-init.sql | 1 + .../testdata/mysql/init/01-init.sql | 1 + .../testdata/postgres/init/01-init.sql | 11 + tools/client-generation/example/go/go.mod | 18 - tools/client-generation/example/go/go.sum | 16 - tools/client-generation/example/go/main.go | 498 -- 43 files changed, 7825 insertions(+), 884 deletions(-) delete mode 100644 .sisyphus/boulder.json delete mode 100644 .sisyphus/plans/ojp-go-grpc-client.md create mode 100644 ojp-grpc-client-go/README.md create mode 100644 ojp-grpc-client-go/cmd/ojp-grpc-client/main.go create mode 100644 ojp-grpc-client-go/cmd/ojp-grpc-client/main_test.go create mode 100644 ojp-grpc-client-go/docker-compose.db2.yml create mode 100644 ojp-grpc-client-go/docker-compose.mariadb.yml create mode 100644 ojp-grpc-client-go/docker-compose.mssql.yml create mode 100644 ojp-grpc-client-go/docker-compose.mysql.yml create mode 100644 ojp-grpc-client-go/docker-compose.oracle.yml create mode 100644 ojp-grpc-client-go/docker-compose.postgres18.yml create mode 100644 ojp-grpc-client-go/go.mod create mode 100644 ojp-grpc-client-go/go.sum rename {tools/client-generation/example/go/pkg => ojp-grpc-client-go/internal}/client/endpoint.go (100%) rename {tools/client-generation/example/go/pkg => ojp-grpc-client-go/internal}/client/exception.go (100%) rename {tools/client-generation/example/go/pkg => ojp-grpc-client-go/internal}/client/health.go (100%) rename {tools/client-generation/example/go/pkg => ojp-grpc-client-go/internal}/client/multinode.go (91%) rename {tools/client-generation/example/go/pkg => ojp-grpc-client-go/internal}/client/redistributor.go (100%) rename {tools/client-generation/example/go/pkg => ojp-grpc-client-go/internal}/client/service.go (99%) create mode 100644 ojp-grpc-client-go/internal/gen/go/com/openjproxy/grpc/StatementService.pb.go create mode 100644 ojp-grpc-client-go/internal/gen/go/com/openjproxy/grpc/StatementService_grpc.pb.go create mode 100644 ojp-grpc-client-go/internal/gen/go/ojp/transport/v1/containers.pb.go create mode 100644 ojp-grpc-client-go/internal/gen/go/org/openjproxy/grpc/echo.pb.go create mode 100644 ojp-grpc-client-go/internal/gen/go/org/openjproxy/grpc/echo_grpc.pb.go create mode 100644 ojp-grpc-client-go/scripts/run-db2-crud-test.ps1 create mode 100644 ojp-grpc-client-go/scripts/run-db2-crud-test.sh create mode 100644 ojp-grpc-client-go/scripts/run-mariadb-crud-test.ps1 create mode 100644 ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh create mode 100644 ojp-grpc-client-go/scripts/run-mssql-crud-test.ps1 create mode 100644 ojp-grpc-client-go/scripts/run-mssql-crud-test.sh create mode 100644 ojp-grpc-client-go/scripts/run-mysql-crud-test.ps1 create mode 100644 ojp-grpc-client-go/scripts/run-mysql-crud-test.sh create mode 100644 ojp-grpc-client-go/scripts/run-oracle-crud-test.ps1 create mode 100644 ojp-grpc-client-go/scripts/run-oracle-crud-test.sh create mode 100644 ojp-grpc-client-go/scripts/run-postgres18-crud-test.ps1 create mode 100644 ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh create mode 100644 ojp-grpc-client-go/testdata/connection.csv create mode 100644 ojp-grpc-client-go/testdata/mariadb/init/01-init.sql create mode 100644 ojp-grpc-client-go/testdata/mysql/init/01-init.sql create mode 100644 ojp-grpc-client-go/testdata/postgres/init/01-init.sql delete mode 100644 tools/client-generation/example/go/go.mod delete mode 100644 tools/client-generation/example/go/go.sum delete mode 100644 tools/client-generation/example/go/main.go diff --git a/.sisyphus/boulder.json b/.sisyphus/boulder.json deleted file mode 100644 index ae73102f4..000000000 --- a/.sisyphus/boulder.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "active_plan": "/home/jay/code/ojp/.sisyphus/plans/ojp-go-grpc-client.md", - "started_at": "2026-05-06T00:00:00Z", - "session_ids": ["ses_start"], - "plan_name": "ojp-go-grpc-client", - "worktree_path": null -} \ No newline at end of file diff --git a/.sisyphus/plans/ojp-go-grpc-client.md b/.sisyphus/plans/ojp-go-grpc-client.md deleted file mode 100644 index 8f0f07293..000000000 --- a/.sisyphus/plans/ojp-go-grpc-client.md +++ /dev/null @@ -1,319 +0,0 @@ -# OJP Go gRPC Client Implementation Plan - -## TL;DR - -> **Quick Summary**: Create a full-featured Go gRPC client for OJP (Open Journaling Protocol) with built-in connection management, load balancing, failover, health checks, transaction support, and retry logic - matching the capabilities of the existing Java JDBC driver. -> -> **Deliverables**: -> - Go client library with connection pooling and health checking -> - Load balancing across multiple OJP server endpoints -> - Automatic failover with retry and backoff -> - Server-side transaction management (start/commit/rollback RPC) -> - Integration test suite for both implementations -> -> **Estimated Effort**: Large -> **Parallel Execution**: YES - 4 waves -> **Critical Path**: Module setup → Generated code → Core client → Integration tests - ---- - -## Context - -### Original Request -User wants to create a Go gRPC client for OJP that: -1. Uses the existing gRPC protocol (StatementService.proto) - not just generated stubs -2. Has full features like existing Java JDBC: connection management, load balancing, failover, transactions -3. Test both implementations against same SQL operations -4. Use server-side transactions (current pattern) - -### Interview Summary - -**Key Discussions**: -- Current generated Go client (tools/client-generation/example/go/main.go) is too basic -- Needs: connection pooling, load balancing, health checks, failover, transactions, retry logic -- Test both Java JDBC and Go clients with same tests -- Server-side transactions (like existing Java client) - -**Research Findings**: -- OJP uses StatementService.proto with these methods: connect, executeUpdate, executeQuery (streaming), fetchNextRows, createLob, readLob, terminateSession, startTransaction, commitTransaction, rollbackTransaction, callResource, and XA methods -- Java client uses StatementServiceGrpcClient with BlockingStub + async Stub for streaming -- Existing load balancing via MultinodeConnectionManager with server health tracking -- Tests use retry logic with exponential backoff for connection-level errors - ---- - -## Work Objectives - -### Core Objective -Implement a production-ready Go gRPC client for OJP protocol that provides equivalent functionality to the existing Java JDBC driver. - -### Concrete Deliverables -- Go module with generated gRPC stubs integrated -- Connection pool implementation -- Load balancer with round-robin and weighted selection -- Health checker for server endpoints -- Failover with automatic retry to standby servers -- Transaction manager using server-side RPC calls -- Retry logic with exponential backoff for connection errors -- Integration tests for both implementations - -### Definition of Done -- [ ] Go client can connect to OJP server and execute SQL -- [ ] Load balancing works across 2+ server endpoints -- [ ] Failover works when primary server is unavailable -- [ ] Transaction commit/rollback works -- [ ] Integration tests pass for both clients on same SQL - -### Must Have -- Connect to OJP server with authentication -- Execute SQL with parameters (prepared statements) -- Stream result sets -- Transaction management -- Health checking -- Automatic failover - -### Must NOT Have (Guardrails) -- JDBC interface compatibility (that's a separate JDBC-over-gRPC layer) -- SQL enhancement logic (not client responsibility) -- Native database drivers (handled by OJP server) - ---- - -## Verification Strategy (MANDATORY) - -### Test Decision -- **Infrastructure exists**: YES - existing Go + buf setup in tools/client-generation -- **Automated tests**: YES - Tests after implementation -- **Framework**: go test + integration tests -- **If Tests**: Each feature requires verification test - -### QA Policy -Every task MUST include agent-executed QA scenarios. -- Integration tests connect to running OJP server -- Load balance verification: distribute N queries, verify distribution -- Failover verification: kill server, verify auto-switch -- Transaction verification: begin commit rollback cycle - ---- - -## Execution Strategy - -### Parallel Execution Waves - -``` -Wave 1 (Foundation - can start immediately): -├── Task 1: Go module setup with go.mod and dependencies -├── Task 2: Generate gRPC code from StatementService.proto using buf -├── Task 3: Connection/Channel management layer -└── Task 4: Basic client wrapper - Connect + ExecuteUpdate + ExecuteQuery - -Wave 2 (Core Features - after Wave 1): -├── Task 5: Server endpoint management and health checking -├── Task 6: Load balancer - round-robin and weighted selection -├── Task 7: Failover with retry and exponential backoff -├── Task 8: Transaction manager (start/commit/rollback RPC) -├── Task 9: Session management and reconnection -└── Task 10: Error classification (retry vs non-retry) - -Wave 3 (Advanced Features - after Wave 2): -├── Task 11: Streaming result set handling (ExecuteQuery) -├── Task 12: LOB creation and reading (createLob/readLob) -├── Task 13: XA transaction support -├── Task 14: Connection pool for reuse -└── Task 15: Configuration and builder pattern - -Wave FINAL (After ALL tasks): -├── Task F1: Integration test suite -├── Task F2: Test both implementations side-by-side -├── Task F3: Documentation -└── Task F4: Example usage -``` - -### Dependency Matrix -- **1-4**: - - 5-10, 5-10 -- **5**: 4 - 6, 7 -- **6**: 5 - 8 -- **7**: 5 - 8 -- **8**: 5, 6, 7 - 10 -- **9**: 8 - 10 -- **10**: 7, 8, 9 - 11-14 -- **11**: 4 - - -- **12**: 4, 10 - - -- **13**: 10 - - -- **14**: 10 - - -- **15**: 4, 5 - - - ---- - -## TODOs - -- [ ] 1. Go module setup with go.mod and dependencies - - **What to do**: - - Create new Go module structure for OJP Go client - - Copy and adapt go.mod from tools/client-generation/example/go/ - - Add necessary dependencies for gRPC, health checking, connection pooling - - **References**: - - `tools/client-generation/example/go/go.mod` - Reference go.mod structure - - `ojp-grpc-commons/src/main/proto/StatementService.proto` - Protocol definitions - -- [ ] 2. Generate gRPC code from StatementService.proto using buf - - **What to do**: - - Run buf generate to create Go gRPC stubs - - Verify generated code compiles - - Create module wrapper for import convenience - -- [ ] 3. Connection/Channel management layer - - **What to do**: - - Create ManagedChannel pool/reuse - - Implement connection caching - - Add graceful shutdown handling - -- [ ] 4. Basic client wrapper - Connect + ExecuteUpdate + ExecuteQuery - - **What to do**: - - Implement Connect() method matching StatementService.proto - - Implement ExecuteUpdate() with parameter support - - Implement ExecuteQuery() with streaming results - -- [ ] 5. Server endpoint management and health checking - - **What to do**: - - Create ServerEndpoint struct with host:port, health status - - Implement health checking (periodic ping/connect check) - - Track server up/down status - -- [ ] 6. Load balancer - round-robin and weighted selection - - **What to do**: - - Implement round-robin selection - - Implement weighted selection based on server capacity - - Skip unhealthy servers in selection - -- [ ] 7. Failover with retry and exponential backoff - - **What to do**: - - Detect connection errors - - Implement retry with exponential backoff (initial 100ms, max 3 retries) - - Auto-switch to healthy server on failure - -- [ ] 8. Transaction manager (start/commit/rollback RPC) - - **What to do**: - - Implement StartTransaction() RPC call - - Implement CommitTransaction() RPC call - - Implement RollbackTransaction() RPC call - -- [ ] 9. Session management and reconnection - - **What to do**: - - Track session state (sessionUUID) - - Handle session invalidation - - Implement reconnection logic - -- [ ] 10. Error classification (retry vs non-retry) - - **What to do**: - - Classify errors as retryable vs non-retryable - - Handle StatusRuntimeException mapping - -- [ ] 11. Streaming result set handling (ExecuteQuery) - - **What to do**: - - Handle streaming OpResult responses - - Implement result iterator - -- [ ] 12. LOB creation and reading (createLob/readLob) - - **What to do**: - - Implement createLob streaming RPC - - Implement readLob streaming RPC - -- [ ] 13. XA transaction support - - **What to do**: - - Implement xaStart, xaEnd, xaPrepare, xaCommit - - Implement xaRollback, xaRecover - -- [ ] 14. Connection pool for reuse - - **What to do**: - - Implement connection pooling - - Implement idle connection cleanup - -- [ ] 15. Configuration and builder pattern - - **What to do**: - - Create Config struct for client options - - Implement builder pattern for client creation - -- [ ] F1. Integration test suite - - **What to do**: - - Create Go integration tests similar to MultinodeIntegrationTest - - Test CRUD operations - - Test transactions - -- [ ] F2. Test both implementations side-by-side - - **What to do**: - - Run same SQL tests against both Java JDBC and Go client - - Verify feature parity - -- [ ] F3. Documentation - - **What to do**: - - README with usage examples - - API documentation - -- [ ] F4. Example usage - - **What to do**: - - Update example/go/main.go with full features - - Create more examples - ---- - -## Final Verification Wave (MANDATORY) - -- [ ] V1. **Plan Compliance Audit** — `oracle` - Verify all Must Have items addressed and Must NOT Have items avoided. - -- [ ] V2. **Code Quality Review** — Build and test verification - Run go vet, go build, go test to verify correctness. - -- [ ] V3. **Real Integration Test** — Execute integration tests - Run tests against running OJP server. - -- [ ] V4. **Both Implementations Test** — Verify feature parity - Run same tests against both Java JDBC and Go clients. - ---- - -## Commit Strategy - -- **Tasks 1-4**: `feat(client): Go module setup and basic client` -- **Tasks 5-10**: `feat(client): load balancing and failover` -- **Tasks 11-15**: `feat(client): advanced features` -- **Integration**: `test(client): integration tests` - ---- - -## Success Criteria - -### Verification Commands -```bash -go build ./... -go test ./... -``` - -### Final Checklist -- [ ] Go client connects to OJP server -- [ ] Load balancing distributes queries -- [ ] Failover works when server unavailable -- [ ] Transactions commit/rollback work -- [ ] Integration tests pass -- [ ] Both implementations feature parity \ No newline at end of file diff --git a/ojp-grpc-client-go/README.md b/ojp-grpc-client-go/README.md new file mode 100644 index 000000000..02931e021 --- /dev/null +++ b/ojp-grpc-client-go/README.md @@ -0,0 +1,232 @@ +# OJP gRPC Go Client (Application Layout) + +This folder contains a Go application client for OJP. +It connects to `ojp-server` over gRPC and runs a simple CRUD flow. + +## Folder Structure + +```text +ojp-grpc-client-go/ + cmd/ojp-grpc-client/ # executable entrypoint (main package) + internal/client/ # client-side connection/load-balancing helpers + internal/gen/ # generated protobuf/gRPC Go stubs + scripts/ # integration test runners + testdata/connection.csv # test/demo CSV lines (not required in production) + testdata/postgres/init/ # postgres18 compose init SQL + testdata/mysql/init/ # mysql compose init SQL + testdata/mariadb/init/ # mariadb compose init SQL + docker-compose.postgres18.yml + docker-compose.mysql.yml + docker-compose.mariadb.yml + go.mod + go.sum +``` + +## Configuration + +Primary (normal use case): + +- `OJP_JDBC_LINE` + +Format: + +```text +jdbc:ojp[host:port]_backendJdbcUrl,user,password +``` + +Example: + +```text +jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword +``` + +Fallback (test helper only): + +- `OJP_JDBC_CSV` (multi-line CSV content for testing only) +- `OJP_JDBC_CSV_INDEX` (0-based line index, default `0`) + +If `OJP_JDBC_LINE` is set, it is used first. + +## What `main` Does + +1. Parses connection values from env (`addr`, backend JDBC URL, user, password). +2. Opens gRPC connection to OJP server. +3. Runs CRUD on table `demo`: + - `CREATE TABLE IF NOT EXISTS` + - insert + - read + - update + - read + - delete + - read + +Notes: + +- Assertions are executed after each read: + - after insert: exactly 1 row + - after update: exactly 1 row + - after delete: 0 rows + +## Run the Client + +From `ojp-grpc-client-go`: + +```powershell +$env:OJP_JDBC_LINE='jdbc:ojp[localhost:1059]_h2:~/test,sa,' +go run ./cmd/ojp-grpc-client +``` + +Expected output shape: + +```text +READ after CREATE/INSERT: +opResult: type=RESULT_SET_DATA uuid=... +READ after UPDATE: +opResult: type=RESULT_SET_DATA uuid=... +READ after DELETE: +opResult: type=RESULT_SET_DATA uuid=... +``` + +## Unit Tests + +Unit tests are in: + +- `cmd/ojp-grpc-client/main_test.go` + +Covered functions: + +- `parseOjpCsvLine` +- `selectCsvLine` +- `drainQueryStream` (with mock streaming client) + +Run: + +```powershell +go test ./cmd/ojp-grpc-client +``` + +## End-to-End Test (OJP + H2) + +### 1) Prepare OJP server drivers + +```powershell +cd ..\ojp-server +bash -lc "tr -d '\r' < download-drivers.sh | bash" +``` + +This creates `ojp-server/ojp-libs/` and downloads H2 + other open-source JDBC drivers. + +### 2) Build project artifacts + +From repository root (`ojp/`): + +```powershell +mvn clean install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" +``` + +### 3) Start OJP server + +From `ojp-server`: + +```powershell +java -Duser.timezone=UTC -Dojp.libs.path=.\ojp-libs -jar .\target\ojp-server-0.4.17-SNAPSHOT-shaded.jar +``` + +### 4) Run Go client against H2 + +From `ojp-grpc-client-go`: + +```powershell +$env:OJP_JDBC_LINE='jdbc:ojp[localhost:1059]_h2:~/test,sa,' +go run ./cmd/ojp-grpc-client +``` + +If you want to test using CSV test data: + +```powershell +$env:OJP_JDBC_CSV = Get-Content -Raw -Path .\testdata\connection.csv +$env:OJP_JDBC_CSV_INDEX='0' +Remove-Item Env:OJP_JDBC_LINE -ErrorAction SilentlyContinue +go run ./cmd/ojp-grpc-client +``` + +## End-to-End Test (PostgreSQL 18 via Docker Compose) + +This repository now includes an automated PostgreSQL 18 + OJP + Go CRUD test setup. + +### PowerShell (recommended on Windows) + +From `ojp-grpc-client-go`: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\run-postgres18-crud-test.ps1 -SkipBuild +``` + +Options: + +- Remove `-SkipBuild` to run Maven install before the test. + +What this script does: + +1. Starts `postgres:18` using `docker-compose.postgres18.yml` +2. Waits for healthy Postgres +3. Ensures PostgreSQL JDBC driver exists in `ojp-server/ojp-libs` +4. (Optional) builds OJP modules +5. Starts OJP server on dynamically selected free ports +6. Runs `go run ./cmd/ojp-grpc-client` with `OJP_JDBC_LINE` targeting `testdb` + +### Bash wrapper + +From `ojp-grpc-client-go`: + +```bash +bash scripts/run-postgres18-crud-test.sh -SkipBuild +``` + +The bash script is a wrapper that calls the PowerShell script. + +## End-to-End Test (MySQL via Docker Compose) + +From `ojp-grpc-client-go`: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\run-mysql-crud-test.ps1 -SkipBuild +``` + +Or: + +```bash +bash scripts/run-mysql-crud-test.sh -SkipBuild +``` + +This follows the same steps as the PostgreSQL script: + +1. Starts `mysql:8.4` using `docker-compose.mysql.yml` +2. Waits for healthy MySQL +3. Ensures MySQL JDBC driver exists in `ojp-server/ojp-libs` +4. (Optional) builds OJP modules +5. Starts OJP server on dynamically selected free ports +6. Runs `go run ./cmd/ojp-grpc-client` with MySQL `OJP_JDBC_LINE` + +## End-to-End Test (MariaDB via Docker Compose) + +From `ojp-grpc-client-go`: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\run-mariadb-crud-test.ps1 -SkipBuild +``` + +Or: + +```bash +bash scripts/run-mariadb-crud-test.sh -SkipBuild +``` + +This follows the same steps as the PostgreSQL script: + +1. Starts `mariadb:11` using `docker-compose.mariadb.yml` +2. Waits for healthy MariaDB +3. Ensures MariaDB JDBC driver exists in `ojp-server/ojp-libs` +4. (Optional) builds OJP modules +5. Starts OJP server on dynamically selected free ports +6. Runs `go run ./cmd/ojp-grpc-client` with MariaDB `OJP_JDBC_LINE` diff --git a/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go b/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go new file mode 100644 index 000000000..eca24f74d --- /dev/null +++ b/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go @@ -0,0 +1,322 @@ +package main + +import ( + "context" + "encoding/csv" + "errors" + "fmt" + "io" + "log" + "os" + "strconv" + "strings" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + pb "github.com/open-j-proxy/ojp-client/internal/gen/go/com/openjproxy/grpc" +) + +func main() { + // Default connection values used when no env-based CSV input is provided. + addr := "127.0.0.1:1059" + backendURL := "jdbc:postgresql://postgres:5432/ojp" + dbUser := "ojp" + dbPassword := "ojp" + jdbcLine := strings.TrimSpace(env("OJP_JDBC_LINE", "")) + csvLines := strings.TrimSpace(env("OJP_JDBC_CSV", "")) + csvIndex := env("OJP_JDBC_CSV_INDEX", "0") + + if jdbcLine != "" { + // Primary mode: one CSV line from env (normal use case). + parsed, err := parseOjpCsvLine(jdbcLine) + if err != nil { + log.Fatalf("invalid OJP_JDBC_LINE: %v", err) + } + + addr = parsed.Addr + backendURL = parsed.BackendURL + dbUser = parsed.DbUser + dbPassword = parsed.DbPassword + } else if csvLines != "" { + // Fallback mode: multiline CSV + index (test helper mode). + selected, err := selectCsvLine(csvLines, csvIndex) + if err != nil { + log.Fatalf("invalid OJP_JDBC_CSV input: %v", err) + } + parsed, err := parseOjpCsvLine(selected) + if err != nil { + log.Fatalf("invalid OJP_JDBC_CSV line: %v", err) + } + + addr = parsed.Addr + backendURL = parsed.BackendURL + dbUser = parsed.DbUser + dbPassword = parsed.DbPassword + } + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + // Open gRPC connection to OJP. + conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Fatalf("dial failed: %v", err) + } + defer func(conn *grpc.ClientConn) { + err := conn.Close() + if err != nil { + + } + }(conn) + + client := pb.NewStatementServiceClient(conn) + + connectResp, err := client.Connect(ctx, &pb.ConnectionDetails{ + Url: backendURL, + User: dbUser, + Password: dbPassword, + ClientUUID: "go-example-client", + }) + if err != nil { + log.Fatalf("connect failed: %v", err) + } + + // DB2 default schema handling for demo table operations. + // Without this, DB2 may resolve objects in an unexpected schema. + if strings.HasPrefix(strings.ToLower(backendURL), "jdbc:db2:") { + setSchemaReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "SET SCHEMA DB2INST1", + } + if _, err = client.ExecuteUpdate(ctx, setSchemaReq); err != nil { + log.Fatalf("set schema failed: %v", err) + } + } + + // CREATE + updateReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", + } + if _, err = client.ExecuteUpdate(ctx, updateReq); err != nil { + log.Fatalf("create table failed: %v", err) + } + + // INSERT + insertSQL := "INSERT INTO demo(id, name) VALUES (1, 'hello from go')" + + insertReq := &pb.StatementRequest{ + Session: connectResp, + Sql: insertSQL, + } + if _, err = client.ExecuteUpdate(ctx, insertReq); err != nil { + log.Fatalf("insert failed: %v", err) + } + + // READ + queryReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "SELECT id, name FROM demo ORDER BY id", + } + stream, err := client.ExecuteQuery(ctx, queryReq) + if err != nil { + log.Fatalf("executeQuery failed: %v", err) + } + fmt.Println("READ after CREATE/INSERT:") + results, err := drainQueryStream(stream) + if err != nil { + log.Fatalf("read after insert failed: %v", err) + } + var insertedRows []*pb.ResultRow + for _, r := range results { + if qr := r.GetQueryResult(); qr != nil { + insertedRows = append(insertedRows, qr.GetRows()...) + } + } + if len(insertedRows) != 1 { + log.Fatalf("assert after insert failed: expected 1 row, got %d", len(insertedRows)) + } + insertCols := insertedRows[0].GetColumns() + if len(insertCols) < 2 { + log.Fatalf("assert after insert failed: expected at least 2 columns, got %d", len(insertCols)) + } + + // UPDATE + updateReq2 := &pb.StatementRequest{ + Session: connectResp, + Sql: "UPDATE demo SET name = 'updated from go' WHERE id = 1", + } + if _, err = client.ExecuteUpdate(ctx, updateReq2); err != nil { + log.Fatalf("update failed: %v", err) + } + stream, err = client.ExecuteQuery(ctx, queryReq) + if err != nil { + log.Fatalf("executeQuery after update failed: %v", err) + } + fmt.Println("READ after UPDATE:") + results, err = drainQueryStream(stream) + if err != nil { + log.Fatalf("read after update failed: %v", err) + } + var updatedRows []*pb.ResultRow + for _, r := range results { + if qr := r.GetQueryResult(); qr != nil { + updatedRows = append(updatedRows, qr.GetRows()...) + } + } + if len(updatedRows) != 1 { + log.Fatalf("assert after update failed: expected 1 row, got %d", len(updatedRows)) + } + updateCols := updatedRows[0].GetColumns() + if len(updateCols) < 2 { + log.Fatalf("assert after update failed: expected at least 2 columns, got %d", len(updateCols)) + } + + // DELETE + deleteReq := &pb.StatementRequest{ + Session: connectResp, + Sql: "DELETE FROM demo WHERE id = 1", + } + if _, err = client.ExecuteUpdate(ctx, deleteReq); err != nil { + log.Fatalf("delete failed: %v", err) + } + stream, err = client.ExecuteQuery(ctx, queryReq) + if err != nil { + log.Fatalf("executeQuery after delete failed: %v", err) + } + fmt.Println("READ after DELETE:") + results, err = drainQueryStream(stream) + if err != nil { + log.Fatalf("read after delete failed: %v", err) + } + var deletedRows int + for _, r := range results { + if qr := r.GetQueryResult(); qr != nil { + deletedRows += len(qr.GetRows()) + } + } + if deletedRows != 0 { + log.Fatalf("assert after delete failed: expected 0 rows, got %d", deletedRows) + } + + _, _ = client.TerminateSession(context.Background(), connectResp) +} + +// drainQueryStream consumes the full ExecuteQuery stream, prints each OpResult, +// and returns the collected results for assertions. +func drainQueryStream(stream pb.StatementService_ExecuteQueryClient) ([]*pb.OpResult, error) { + var results []*pb.OpResult + for { + msg, recvErr := stream.Recv() + if recvErr == io.EOF { + break + } + if recvErr != nil { + return nil, fmt.Errorf("stream recv failed: %w", recvErr) + } + results = append(results, msg) + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) + } + return results, nil +} + +type parsedOjpCsv struct { + Addr string + BackendURL string + DbUser string + DbPassword string +} + +// selectCsvLine returns the non-empty line at OJP_JDBC_CSV_INDEX from a +// newline-separated CSV payload. +func selectCsvLine(csvLines, indexRaw string) (string, error) { + idx, err := strconv.Atoi(strings.TrimSpace(indexRaw)) + if err != nil || idx < 0 { + return "", fmt.Errorf("OJP_JDBC_CSV_INDEX must be a non-negative number, got %q", indexRaw) + } + + lines := strings.Split(csvLines, "\n") + nonEmpty := make([]string, 0, len(lines)) + for _, line := range lines { + trimmed := strings.TrimSpace(line) + if trimmed != "" { + nonEmpty = append(nonEmpty, trimmed) + } + } + + if len(nonEmpty) == 0 { + return "", errors.New("OJP_JDBC_CSV has no non-empty lines") + } + if idx >= len(nonEmpty) { + return "", fmt.Errorf("OJP_JDBC_CSV_INDEX=%d out of range (lines=%d)", idx, len(nonEmpty)) + } + return nonEmpty[idx], nil +} + +// parseOjpCsvLine parses one CSV record in OJP format: +// jdbc:ojp[host:port]_backendUrl,user,password +// It extracts OJP address, backend JDBC URL, DB user, and DB password. +func parseOjpCsvLine(line string) (*parsedOjpCsv, error) { + r := csv.NewReader(strings.NewReader(line)) + r.FieldsPerRecord = 3 + fields, err := r.Read() + if err != nil { + return nil, fmt.Errorf("csv parse failed: %w", err) + } + + ojpJdbcURL := strings.TrimSpace(fields[0]) + dbUser := strings.TrimSpace(fields[1]) + dbPassword := strings.TrimSpace(fields[2]) + + const prefix = "jdbc:ojp[" + if !strings.HasPrefix(ojpJdbcURL, prefix) { + return nil, fmt.Errorf("first field must start with %q, got %q", prefix, ojpJdbcURL) + } + + bracketEnd := strings.Index(ojpJdbcURL, "]") + if bracketEnd < 0 { + return nil, fmt.Errorf("missing closing bracket in %q", ojpJdbcURL) + } + if bracketEnd+1 >= len(ojpJdbcURL) || ojpJdbcURL[bracketEnd+1] != '_' { + return nil, fmt.Errorf("missing '_' separator after OJP endpoint section in %q", ojpJdbcURL) + } + + addrSection := ojpJdbcURL[len(prefix):bracketEnd] + if addrSection == "" { + return nil, fmt.Errorf("empty OJP endpoint section in %q", ojpJdbcURL) + } + + firstEndpoint := strings.TrimSpace(strings.Split(addrSection, ",")[0]) + if firstEndpoint == "" { + return nil, fmt.Errorf("empty first endpoint in %q", ojpJdbcURL) + } + if openParen := strings.Index(firstEndpoint, "("); openParen >= 0 { + firstEndpoint = strings.TrimSpace(firstEndpoint[:openParen]) + } + if firstEndpoint == "" || !strings.Contains(firstEndpoint, ":") { + return nil, fmt.Errorf("invalid first endpoint %q", firstEndpoint) + } + + backendURL := "jdbc:" + ojpJdbcURL[bracketEnd+2:] + if !strings.HasPrefix(backendURL, "jdbc:") { + return nil, fmt.Errorf("invalid backend URL extracted from %q", ojpJdbcURL) + } + + return &parsedOjpCsv{ + Addr: firstEndpoint, + BackendURL: backendURL, + DbUser: dbUser, + DbPassword: dbPassword, + }, nil +} + +// env returns an environment variable value or the fallback when unset/empty. +func env(name, fallback string) string { + v := os.Getenv(name) + if v == "" { + return fallback + } + return v +} diff --git a/ojp-grpc-client-go/cmd/ojp-grpc-client/main_test.go b/ojp-grpc-client-go/cmd/ojp-grpc-client/main_test.go new file mode 100644 index 000000000..eb5829ea9 --- /dev/null +++ b/ojp-grpc-client-go/cmd/ojp-grpc-client/main_test.go @@ -0,0 +1,155 @@ +package main + +import ( + "bytes" + "context" + "io" + "os" + "strings" + "testing" + + pb "github.com/open-j-proxy/ojp-client/internal/gen/go/com/openjproxy/grpc" + "google.golang.org/grpc/metadata" +) + +func TestSelectCsvLineShouldReturnRequestedNonEmptyLine(t *testing.T) { + csvLines := "\nline-0\n\n line-1 \nline-2\n" + got, err := selectCsvLine(csvLines, "1") + if err != nil { + t.Fatalf("selectCsvLine returned error: %v", err) + } + if got != "line-1" { + t.Fatalf("expected line-1, got %q", got) + } +} + +func TestSelectCsvLineShouldFailForInvalidIndex(t *testing.T) { + _, err := selectCsvLine("a\nb", "x") + if err == nil { + t.Fatal("expected error for invalid index, got nil") + } +} + +func TestSelectCsvLineShouldFailForOutOfRangeIndex(t *testing.T) { + _, err := selectCsvLine("a\nb", "5") + if err == nil { + t.Fatal("expected out-of-range error, got nil") + } +} + +func TestParseOjpCsvLineShouldParseSingleEndpoint(t *testing.T) { + line := "jdbc:ojp[localhost:1059]_h2:~/test,sa," + got, err := parseOjpCsvLine(line) + if err != nil { + t.Fatalf("parseOjpCsvLine returned error: %v", err) + } + if got.Addr != "localhost:1059" { + t.Fatalf("expected addr localhost:1059, got %q", got.Addr) + } + if got.BackendURL != "jdbc:h2:~/test" { + t.Fatalf("expected backend jdbc:h2:~/test, got %q", got.BackendURL) + } + if got.DbUser != "sa" { + t.Fatalf("expected user sa, got %q", got.DbUser) + } + if got.DbPassword != "" { + t.Fatalf("expected empty password, got %q", got.DbPassword) + } +} + +func TestParseOjpCsvLineShouldUseFirstEndpointAndStripDatasourceName(t *testing.T) { + line := "\"jdbc:ojp[host1:1059(main),host2:1060]_postgresql://localhost:5432/defaultdb\",testuser,testpassword" + got, err := parseOjpCsvLine(line) + if err != nil { + t.Fatalf("parseOjpCsvLine returned error: %v", err) + } + if got.Addr != "host1:1059" { + t.Fatalf("expected addr host1:1059, got %q", got.Addr) + } + if got.BackendURL != "jdbc:postgresql://localhost:5432/defaultdb" { + t.Fatalf("unexpected backendURL: %q", got.BackendURL) + } +} + +func TestParseOjpCsvLineShouldFailForInvalidPrefix(t *testing.T) { + _, err := parseOjpCsvLine("jdbc:postgresql://localhost:5432/db,user,pass") + if err == nil { + t.Fatal("expected error for invalid prefix, got nil") + } +} + +func TestDrainQueryStreamShouldPrintAllRowsUntilEOF(t *testing.T) { + stream := &mockQueryStream{ + msgs: []*pb.OpResult{ + {Type: pb.ResultType_RESULT_SET_DATA, Uuid: "u1"}, + {Type: pb.ResultType_RESULT_SET_DATA, Uuid: "u2"}, + }, + } + + oldStdout := os.Stdout + r, w, err := os.Pipe() + if err != nil { + t.Fatalf("pipe creation failed: %v", err) + } + os.Stdout = w + + results, err := drainQueryStream(stream) + if err != nil { + t.Fatalf("drainQueryStream returned error: %v", err) + } + if len(results) != 2 { + t.Fatalf("expected 2 results, got %d", len(results)) + } + + _ = w.Close() + os.Stdout = oldStdout + + var buf bytes.Buffer + _, _ = io.Copy(&buf, r) + out := buf.String() + + if !strings.Contains(out, "uuid=u1") { + t.Fatalf("expected output to contain uuid=u1, got: %s", out) + } + if !strings.Contains(out, "uuid=u2") { + t.Fatalf("expected output to contain uuid=u2, got: %s", out) + } +} + +type mockQueryStream struct { + msgs []*pb.OpResult + idx int +} + +func (m *mockQueryStream) Recv() (*pb.OpResult, error) { + if m.idx >= len(m.msgs) { + return nil, io.EOF + } + msg := m.msgs[m.idx] + m.idx++ + return msg, nil +} + +func (m *mockQueryStream) Header() (metadata.MD, error) { + return metadata.MD{}, nil +} + +func (m *mockQueryStream) Trailer() metadata.MD { + return metadata.MD{} +} + +func (m *mockQueryStream) CloseSend() error { + return nil +} + +func (m *mockQueryStream) Context() context.Context { + return context.Background() +} + +func (m *mockQueryStream) SendMsg(any) error { + return nil +} + +func (m *mockQueryStream) RecvMsg(any) error { + return nil +} diff --git a/ojp-grpc-client-go/docker-compose.db2.yml b/ojp-grpc-client-go/docker-compose.db2.yml new file mode 100644 index 000000000..37eb937bc --- /dev/null +++ b/ojp-grpc-client-go/docker-compose.db2.yml @@ -0,0 +1,19 @@ +services: + db2: + image: icr.io/db2_community/db2 + container_name: ojp-db2 + privileged: true + ports: + - "${DB2_HOST_PORT:-50000}:50000" + environment: + LICENSE: accept + DB2INSTANCE: db2inst1 + DB2INST1_PASSWORD: testpass + DBNAME: testdb + TZ: UTC + healthcheck: + test: ["CMD-SHELL", "su - db2inst1 -c 'db2 connect to testdb >/dev/null 2>&1' || exit 1"] + interval: 15s + timeout: 10s + retries: 80 + start_period: 120s diff --git a/ojp-grpc-client-go/docker-compose.mariadb.yml b/ojp-grpc-client-go/docker-compose.mariadb.yml new file mode 100644 index 000000000..93cf9f6ef --- /dev/null +++ b/ojp-grpc-client-go/docker-compose.mariadb.yml @@ -0,0 +1,20 @@ +services: + mariadb: + image: mariadb:11 + container_name: ojp-mariadb + ports: + - "3307:3306" + environment: + MARIADB_ROOT_PASSWORD: rootpassword + MARIADB_USER: testuser + MARIADB_PASSWORD: testpassword + MARIADB_DATABASE: testdb + TZ: UTC + healthcheck: + test: ["CMD-SHELL", "mariadb-admin ping -h localhost -u root -prootpassword"] + interval: 5s + timeout: 5s + retries: 30 + start_period: 20s + volumes: + - ./testdata/mariadb/init:/docker-entrypoint-initdb.d:ro diff --git a/ojp-grpc-client-go/docker-compose.mssql.yml b/ojp-grpc-client-go/docker-compose.mssql.yml new file mode 100644 index 000000000..2f60754c0 --- /dev/null +++ b/ojp-grpc-client-go/docker-compose.mssql.yml @@ -0,0 +1,17 @@ +services: + mssql: + image: mcr.microsoft.com/mssql/server:2022-latest + container_name: ojp-mssql + ports: + - "${MSSQL_HOST_PORT:-1433}:1433" + environment: + ACCEPT_EULA: "Y" + MSSQL_PID: "Developer" + SA_PASSWORD: TestPassword123! + TZ: UTC + healthcheck: + test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'TestPassword123!' -C -Q 'SELECT 1' || exit 1"] + interval: 10s + timeout: 5s + retries: 40 + start_period: 30s diff --git a/ojp-grpc-client-go/docker-compose.mysql.yml b/ojp-grpc-client-go/docker-compose.mysql.yml new file mode 100644 index 000000000..01b6c13f7 --- /dev/null +++ b/ojp-grpc-client-go/docker-compose.mysql.yml @@ -0,0 +1,20 @@ +services: + mysql: + image: mysql:8.4 + container_name: ojp-mysql + ports: + - "3306:3306" + environment: + MYSQL_ROOT_PASSWORD: rootpassword + MYSQL_USER: testuser + MYSQL_PASSWORD: testpassword + MYSQL_DATABASE: testdb + TZ: UTC + healthcheck: + test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -prootpassword"] + interval: 5s + timeout: 5s + retries: 30 + start_period: 20s + volumes: + - ./testdata/mysql/init:/docker-entrypoint-initdb.d:ro diff --git a/ojp-grpc-client-go/docker-compose.oracle.yml b/ojp-grpc-client-go/docker-compose.oracle.yml new file mode 100644 index 000000000..af411a95c --- /dev/null +++ b/ojp-grpc-client-go/docker-compose.oracle.yml @@ -0,0 +1,17 @@ +services: + oracle: + image: gvenzl/oracle-xe:21-slim + container_name: ojp-oracle + ports: + - "${ORACLE_HOST_PORT:-1521}:1521" + environment: + ORACLE_PASSWORD: testpassword + APP_USER: testuser + APP_USER_PASSWORD: testpassword + TZ: UTC + healthcheck: + test: ["CMD-SHELL", "healthcheck.sh"] + interval: 10s + timeout: 5s + retries: 40 + start_period: 40s diff --git a/ojp-grpc-client-go/docker-compose.postgres18.yml b/ojp-grpc-client-go/docker-compose.postgres18.yml new file mode 100644 index 000000000..9c9fde620 --- /dev/null +++ b/ojp-grpc-client-go/docker-compose.postgres18.yml @@ -0,0 +1,20 @@ +services: + postgres18: + image: postgres:18 + container_name: ojp-postgres18 + ports: + - "5432:5432" + environment: + POSTGRES_USER: testuser + POSTGRES_PASSWORD: testpassword + POSTGRES_DB: testdb + TZ: UTC + healthcheck: + test: ["CMD-SHELL", "pg_isready -U testuser -d testdb"] + interval: 5s + timeout: 5s + retries: 20 + start_period: 10s + volumes: + - ./testdata/postgres/init:/docker-entrypoint-initdb.d:ro + diff --git a/ojp-grpc-client-go/go.mod b/ojp-grpc-client-go/go.mod new file mode 100644 index 000000000..6752b09d7 --- /dev/null +++ b/ojp-grpc-client-go/go.mod @@ -0,0 +1,16 @@ +module github.com/open-j-proxy/ojp-client + +go 1.25.0 + +require ( + google.golang.org/genproto v0.0.0-20260519071638-aa98bba5eb94 + google.golang.org/grpc v1.81.1 + google.golang.org/protobuf v1.36.11 +) + +require ( + golang.org/x/net v0.54.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260519071638-aa98bba5eb94 // indirect +) diff --git a/ojp-grpc-client-go/go.sum b/ojp-grpc-client-go/go.sum new file mode 100644 index 000000000..9aa01ff6f --- /dev/null +++ b/ojp-grpc-client-go/go.sum @@ -0,0 +1,42 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 h1:PgNlNSx2Nq2/j4juYzQBG0/Zdr+WP4z5N01Vk4VYBCY= +google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237/go.mod h1:9sVD8c25Af3p0rGs7S7LLsxWKFiJt/65LdSyqXBkX/Y= +google.golang.org/genproto v0.0.0-20260519071638-aa98bba5eb94 h1:YJjbgu+dkp5kUJLfpMyCLfBIWZb/FcJyuLeo1gVBOuo= +google.golang.org/genproto v0.0.0-20260519071638-aa98bba5eb94/go.mod h1:RRHjglSYABVCWpQ7USCpdfhcd9t4PkajvVwyynZizTc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260519071638-aa98bba5eb94 h1:eZCjr/aAF8c5ccm5pb6T4EXgIei5MlAAPWPJk+5ArfY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260519071638-aa98bba5eb94/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= diff --git a/tools/client-generation/example/go/pkg/client/endpoint.go b/ojp-grpc-client-go/internal/client/endpoint.go similarity index 100% rename from tools/client-generation/example/go/pkg/client/endpoint.go rename to ojp-grpc-client-go/internal/client/endpoint.go diff --git a/tools/client-generation/example/go/pkg/client/exception.go b/ojp-grpc-client-go/internal/client/exception.go similarity index 100% rename from tools/client-generation/example/go/pkg/client/exception.go rename to ojp-grpc-client-go/internal/client/exception.go diff --git a/tools/client-generation/example/go/pkg/client/health.go b/ojp-grpc-client-go/internal/client/health.go similarity index 100% rename from tools/client-generation/example/go/pkg/client/health.go rename to ojp-grpc-client-go/internal/client/health.go diff --git a/tools/client-generation/example/go/pkg/client/multinode.go b/ojp-grpc-client-go/internal/client/multinode.go similarity index 91% rename from tools/client-generation/example/go/pkg/client/multinode.go rename to ojp-grpc-client-go/internal/client/multinode.go index b41fa812f..a4cab3066 100644 --- a/tools/client-generation/example/go/pkg/client/multinode.go +++ b/ojp-grpc-client-go/internal/client/multinode.go @@ -9,27 +9,27 @@ import ( "sync/atomic" "time" - ojpgrpc "github.com/ojp-client/gen/go/com/openjproxy/grpc" + ojpgrpc "github.com/open-j-proxy/ojp-client/internal/gen/go/com/openjproxy/grpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) type ChannelAndStub struct { - channel *grpc.ClientConn + channel *grpc.ClientConn blockingStub ojpgrpc.StatementServiceClient - asyncStub ojpgrpc.StatementServiceClient + asyncStub ojpgrpc.StatementServiceClient } type MultinodeConnectionManager struct { - endpoints []*ServerEndpoint - channelMap map[*ServerEndpoint]*ChannelAndStub - connTracker *ConnectionTracker + endpoints []*ServerEndpoint + channelMap map[*ServerEndpoint]*ChannelAndStub + connTracker *ConnectionTracker healthConfig *HealthCheckConfig healthCheckStop chan struct{} - started atomic.Bool - mu sync.RWMutex + started atomic.Bool + mu sync.RWMutex roundRobinIdx atomic.Int32 - originalURL string + originalURL string } type ConnectionTracker struct { @@ -66,12 +66,12 @@ func NewMultinodeConnectionManager(urls []string, healthConfig *HealthCheckConfi } return &MultinodeConnectionManager{ - endpoints: endpoints, - channelMap: channelMap, - connTracker: NewConnectionTracker(), - healthConfig: healthConfig, + endpoints: endpoints, + channelMap: channelMap, + connTracker: NewConnectionTracker(), + healthConfig: healthConfig, healthCheckStop: make(chan struct{}), - originalURL: strings.Join(urls, ","), + originalURL: strings.Join(urls, ","), }, nil } @@ -218,21 +218,17 @@ func (m *MultinodeConnectionManager) getChannel(server *ServerEndpoint) (*grpc.C } addr := server.Address() - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - conn, err := grpc.DialContext(ctx, addr, + conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithBlock(), ) if err != nil { return nil, err } m.channelMap[server] = &ChannelAndStub{ - channel: conn, + channel: conn, blockingStub: ojpgrpc.NewStatementServiceClient(conn), - asyncStub: ojpgrpc.NewStatementServiceClient(conn), + asyncStub: ojpgrpc.NewStatementServiceClient(conn), } return conn, nil @@ -371,4 +367,4 @@ func (t *ConnectionTracker) TerminateSession(session string) { t.sessionLock.Lock() defer t.sessionLock.Unlock() delete(t.sessions, session) -} \ No newline at end of file +} diff --git a/tools/client-generation/example/go/pkg/client/redistributor.go b/ojp-grpc-client-go/internal/client/redistributor.go similarity index 100% rename from tools/client-generation/example/go/pkg/client/redistributor.go rename to ojp-grpc-client-go/internal/client/redistributor.go diff --git a/tools/client-generation/example/go/pkg/client/service.go b/ojp-grpc-client-go/internal/client/service.go similarity index 99% rename from tools/client-generation/example/go/pkg/client/service.go rename to ojp-grpc-client-go/internal/client/service.go index d8a733d05..d8a5a00b9 100644 --- a/tools/client-generation/example/go/pkg/client/service.go +++ b/ojp-grpc-client-go/internal/client/service.go @@ -9,7 +9,7 @@ import ( "sync" "time" - ojpgrpc "github.com/ojp-client/gen/go/com/openjproxy/grpc" + ojpgrpc "github.com/open-j-proxy/ojp-client/internal/gen/go/com/openjproxy/grpc" grpc "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) @@ -338,6 +338,7 @@ func NewGrpcStatementServiceClient(address string) *GrpcStatementServiceClient { } func (c *GrpcStatementServiceClient) EnsureConnected(ctx context.Context) error { + _ = ctx if c.conn != nil { return nil } @@ -353,9 +354,8 @@ func (c *GrpcStatementServiceClient) EnsureConnected(ctx context.Context) error port = DefaultOJPGRPCPort } - conn, err := grpc.DialContext(ctx, fmt.Sprintf("%s:%d", host, port), + conn, err := grpc.NewClient(fmt.Sprintf("%s:%d", host, port), grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithBlock(), ) if err != nil { return err @@ -576,4 +576,4 @@ func RetryWithBackoff(ctx context.Context, maxRetries int, initialBackoff, maxBa } } return err -} \ No newline at end of file +} diff --git a/ojp-grpc-client-go/internal/gen/go/com/openjproxy/grpc/StatementService.pb.go b/ojp-grpc-client-go/internal/gen/go/com/openjproxy/grpc/StatementService.pb.go new file mode 100644 index 000000000..a57304090 --- /dev/null +++ b/ojp-grpc-client-go/internal/gen/go/com/openjproxy/grpc/StatementService.pb.go @@ -0,0 +1,4300 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: StatementService.proto + +package grpc + +import ( + date "google.golang.org/genproto/googleapis/type/date" + timeofday "google.golang.org/genproto/googleapis/type/timeofday" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Enum representing parameter types for JDBC +type ParameterTypeProto int32 + +const ( + ParameterTypeProto_PT_NULL ParameterTypeProto = 0 + ParameterTypeProto_PT_BOOLEAN ParameterTypeProto = 1 + ParameterTypeProto_PT_BYTE ParameterTypeProto = 2 + ParameterTypeProto_PT_SHORT ParameterTypeProto = 3 + ParameterTypeProto_PT_INT ParameterTypeProto = 4 + ParameterTypeProto_PT_LONG ParameterTypeProto = 5 + ParameterTypeProto_PT_FLOAT ParameterTypeProto = 6 + ParameterTypeProto_PT_DOUBLE ParameterTypeProto = 7 + ParameterTypeProto_PT_BIG_DECIMAL ParameterTypeProto = 8 + ParameterTypeProto_PT_STRING ParameterTypeProto = 9 + ParameterTypeProto_PT_BYTES ParameterTypeProto = 10 + ParameterTypeProto_PT_DATE ParameterTypeProto = 11 + ParameterTypeProto_PT_TIME ParameterTypeProto = 12 + ParameterTypeProto_PT_TIMESTAMP ParameterTypeProto = 13 + ParameterTypeProto_PT_ASCII_STREAM ParameterTypeProto = 14 + ParameterTypeProto_PT_UNICODE_STREAM ParameterTypeProto = 15 + ParameterTypeProto_PT_BINARY_STREAM ParameterTypeProto = 16 + ParameterTypeProto_PT_OBJECT ParameterTypeProto = 17 + ParameterTypeProto_PT_CHARACTER_READER ParameterTypeProto = 18 + ParameterTypeProto_PT_REF ParameterTypeProto = 19 + ParameterTypeProto_PT_BLOB ParameterTypeProto = 20 + ParameterTypeProto_PT_CLOB ParameterTypeProto = 21 + ParameterTypeProto_PT_ARRAY ParameterTypeProto = 22 + ParameterTypeProto_PT_URL ParameterTypeProto = 23 + ParameterTypeProto_PT_ROW_ID ParameterTypeProto = 24 + ParameterTypeProto_PT_N_STRING ParameterTypeProto = 25 + ParameterTypeProto_PT_N_CHARACTER_STREAM ParameterTypeProto = 26 + ParameterTypeProto_PT_N_CLOB ParameterTypeProto = 27 + ParameterTypeProto_PT_SQL_XML ParameterTypeProto = 28 +) + +// Enum value maps for ParameterTypeProto. +var ( + ParameterTypeProto_name = map[int32]string{ + 0: "PT_NULL", + 1: "PT_BOOLEAN", + 2: "PT_BYTE", + 3: "PT_SHORT", + 4: "PT_INT", + 5: "PT_LONG", + 6: "PT_FLOAT", + 7: "PT_DOUBLE", + 8: "PT_BIG_DECIMAL", + 9: "PT_STRING", + 10: "PT_BYTES", + 11: "PT_DATE", + 12: "PT_TIME", + 13: "PT_TIMESTAMP", + 14: "PT_ASCII_STREAM", + 15: "PT_UNICODE_STREAM", + 16: "PT_BINARY_STREAM", + 17: "PT_OBJECT", + 18: "PT_CHARACTER_READER", + 19: "PT_REF", + 20: "PT_BLOB", + 21: "PT_CLOB", + 22: "PT_ARRAY", + 23: "PT_URL", + 24: "PT_ROW_ID", + 25: "PT_N_STRING", + 26: "PT_N_CHARACTER_STREAM", + 27: "PT_N_CLOB", + 28: "PT_SQL_XML", + } + ParameterTypeProto_value = map[string]int32{ + "PT_NULL": 0, + "PT_BOOLEAN": 1, + "PT_BYTE": 2, + "PT_SHORT": 3, + "PT_INT": 4, + "PT_LONG": 5, + "PT_FLOAT": 6, + "PT_DOUBLE": 7, + "PT_BIG_DECIMAL": 8, + "PT_STRING": 9, + "PT_BYTES": 10, + "PT_DATE": 11, + "PT_TIME": 12, + "PT_TIMESTAMP": 13, + "PT_ASCII_STREAM": 14, + "PT_UNICODE_STREAM": 15, + "PT_BINARY_STREAM": 16, + "PT_OBJECT": 17, + "PT_CHARACTER_READER": 18, + "PT_REF": 19, + "PT_BLOB": 20, + "PT_CLOB": 21, + "PT_ARRAY": 22, + "PT_URL": 23, + "PT_ROW_ID": 24, + "PT_N_STRING": 25, + "PT_N_CHARACTER_STREAM": 26, + "PT_N_CLOB": 27, + "PT_SQL_XML": 28, + } +) + +func (x ParameterTypeProto) Enum() *ParameterTypeProto { + p := new(ParameterTypeProto) + *p = x + return p +} + +func (x ParameterTypeProto) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ParameterTypeProto) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[0].Descriptor() +} + +func (ParameterTypeProto) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[0] +} + +func (x ParameterTypeProto) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ParameterTypeProto.Descriptor instead. +func (ParameterTypeProto) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{0} +} + +// Enum to track the original Java type for TimestampWithZone and Date/Time types +type TemporalType int32 + +const ( + TemporalType_TEMPORAL_TYPE_UNSPECIFIED TemporalType = 0 // Default/unknown + TemporalType_TEMPORAL_TYPE_TIMESTAMP TemporalType = 1 // Original type was java.sql.Timestamp + TemporalType_TEMPORAL_TYPE_CALENDAR TemporalType = 2 // Original type was java.util.Calendar + TemporalType_TEMPORAL_TYPE_OFFSET_DATE_TIME TemporalType = 3 // Original type was java.time.OffsetDateTime + TemporalType_TEMPORAL_TYPE_LOCAL_DATE_TIME TemporalType = 4 // Original type was java.time.LocalDateTime + TemporalType_TEMPORAL_TYPE_INSTANT TemporalType = 5 // Original type was java.time.Instant + TemporalType_TEMPORAL_TYPE_LOCAL_DATE TemporalType = 6 // Original type was java.time.LocalDate + TemporalType_TEMPORAL_TYPE_LOCAL_TIME TemporalType = 7 // Original type was java.time.LocalTime + TemporalType_TEMPORAL_TYPE_OFFSET_TIME TemporalType = 8 // Original type was java.time.OffsetTime +) + +// Enum value maps for TemporalType. +var ( + TemporalType_name = map[int32]string{ + 0: "TEMPORAL_TYPE_UNSPECIFIED", + 1: "TEMPORAL_TYPE_TIMESTAMP", + 2: "TEMPORAL_TYPE_CALENDAR", + 3: "TEMPORAL_TYPE_OFFSET_DATE_TIME", + 4: "TEMPORAL_TYPE_LOCAL_DATE_TIME", + 5: "TEMPORAL_TYPE_INSTANT", + 6: "TEMPORAL_TYPE_LOCAL_DATE", + 7: "TEMPORAL_TYPE_LOCAL_TIME", + 8: "TEMPORAL_TYPE_OFFSET_TIME", + } + TemporalType_value = map[string]int32{ + "TEMPORAL_TYPE_UNSPECIFIED": 0, + "TEMPORAL_TYPE_TIMESTAMP": 1, + "TEMPORAL_TYPE_CALENDAR": 2, + "TEMPORAL_TYPE_OFFSET_DATE_TIME": 3, + "TEMPORAL_TYPE_LOCAL_DATE_TIME": 4, + "TEMPORAL_TYPE_INSTANT": 5, + "TEMPORAL_TYPE_LOCAL_DATE": 6, + "TEMPORAL_TYPE_LOCAL_TIME": 7, + "TEMPORAL_TYPE_OFFSET_TIME": 8, + } +) + +func (x TemporalType) Enum() *TemporalType { + p := new(TemporalType) + *p = x + return p +} + +func (x TemporalType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TemporalType) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[1].Descriptor() +} + +func (TemporalType) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[1] +} + +func (x TemporalType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TemporalType.Descriptor instead. +func (TemporalType) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{1} +} + +type DbName int32 + +const ( + DbName_H2 DbName = 0 + DbName_MYSQL DbName = 1 + DbName_MARIADB DbName = 2 + DbName_POSTGRES DbName = 3 + DbName_ORACLE DbName = 4 + DbName_SQL_SERVER DbName = 5 + DbName_DB2 DbName = 6 + DbName_UNMAPPED DbName = 7 +) + +// Enum value maps for DbName. +var ( + DbName_name = map[int32]string{ + 0: "H2", + 1: "MYSQL", + 2: "MARIADB", + 3: "POSTGRES", + 4: "ORACLE", + 5: "SQL_SERVER", + 6: "DB2", + 7: "UNMAPPED", + } + DbName_value = map[string]int32{ + "H2": 0, + "MYSQL": 1, + "MARIADB": 2, + "POSTGRES": 3, + "ORACLE": 4, + "SQL_SERVER": 5, + "DB2": 6, + "UNMAPPED": 7, + } +) + +func (x DbName) Enum() *DbName { + p := new(DbName) + *p = x + return p +} + +func (x DbName) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DbName) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[2].Descriptor() +} + +func (DbName) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[2] +} + +func (x DbName) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DbName.Descriptor instead. +func (DbName) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{2} +} + +type SessionStatus int32 + +const ( + SessionStatus_SESSION_ACTIVE SessionStatus = 0 + SessionStatus_SESSION_TERMINATED SessionStatus = 1 +) + +// Enum value maps for SessionStatus. +var ( + SessionStatus_name = map[int32]string{ + 0: "SESSION_ACTIVE", + 1: "SESSION_TERMINATED", + } + SessionStatus_value = map[string]int32{ + "SESSION_ACTIVE": 0, + "SESSION_TERMINATED": 1, + } +) + +func (x SessionStatus) Enum() *SessionStatus { + p := new(SessionStatus) + *p = x + return p +} + +func (x SessionStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SessionStatus) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[3].Descriptor() +} + +func (SessionStatus) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[3] +} + +func (x SessionStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SessionStatus.Descriptor instead. +func (SessionStatus) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{3} +} + +//TRX stands for transaction +type TransactionStatus int32 + +const ( + TransactionStatus_TRX_ACTIVE TransactionStatus = 0 + TransactionStatus_TRX_COMMITED TransactionStatus = 1 + TransactionStatus_TRX_ROLLBACK TransactionStatus = 2 +) + +// Enum value maps for TransactionStatus. +var ( + TransactionStatus_name = map[int32]string{ + 0: "TRX_ACTIVE", + 1: "TRX_COMMITED", + 2: "TRX_ROLLBACK", + } + TransactionStatus_value = map[string]int32{ + "TRX_ACTIVE": 0, + "TRX_COMMITED": 1, + "TRX_ROLLBACK": 2, + } +) + +func (x TransactionStatus) Enum() *TransactionStatus { + p := new(TransactionStatus) + *p = x + return p +} + +func (x TransactionStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TransactionStatus) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[4].Descriptor() +} + +func (TransactionStatus) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[4] +} + +func (x TransactionStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TransactionStatus.Descriptor instead. +func (TransactionStatus) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{4} +} + +type ResultType int32 + +const ( + ResultType_INTEGER ResultType = 0 + ResultType_RESULT_SET_DATA ResultType = 1 + ResultType_UUID_STRING ResultType = 2 +) + +// Enum value maps for ResultType. +var ( + ResultType_name = map[int32]string{ + 0: "INTEGER", + 1: "RESULT_SET_DATA", + 2: "UUID_STRING", + } + ResultType_value = map[string]int32{ + "INTEGER": 0, + "RESULT_SET_DATA": 1, + "UUID_STRING": 2, + } +) + +func (x ResultType) Enum() *ResultType { + p := new(ResultType) + *p = x + return p +} + +func (x ResultType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ResultType) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[5].Descriptor() +} + +func (ResultType) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[5] +} + +func (x ResultType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ResultType.Descriptor instead. +func (ResultType) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{5} +} + +type SqlErrorType int32 + +const ( + SqlErrorType_SQL_EXCEPTION SqlErrorType = 0 + SqlErrorType_SQL_DATA_EXCEPTION SqlErrorType = 1 +) + +// Enum value maps for SqlErrorType. +var ( + SqlErrorType_name = map[int32]string{ + 0: "SQL_EXCEPTION", + 1: "SQL_DATA_EXCEPTION", + } + SqlErrorType_value = map[string]int32{ + "SQL_EXCEPTION": 0, + "SQL_DATA_EXCEPTION": 1, + } +) + +func (x SqlErrorType) Enum() *SqlErrorType { + p := new(SqlErrorType) + *p = x + return p +} + +func (x SqlErrorType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SqlErrorType) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[6].Descriptor() +} + +func (SqlErrorType) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[6] +} + +func (x SqlErrorType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SqlErrorType.Descriptor instead. +func (SqlErrorType) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{6} +} + +//LT stands for Lob Type +type LobType int32 + +const ( + LobType_LT_BLOB LobType = 0 + LobType_LT_CLOB LobType = 1 + LobType_LT_BINARY_STREAM LobType = 2 + LobType_LT_ASCII_STREAM LobType = 3 + LobType_LT_UNICODE_STREAM LobType = 4 + LobType_LT_CHARACTER_STREAM LobType = 5 +) + +// Enum value maps for LobType. +var ( + LobType_name = map[int32]string{ + 0: "LT_BLOB", + 1: "LT_CLOB", + 2: "LT_BINARY_STREAM", + 3: "LT_ASCII_STREAM", + 4: "LT_UNICODE_STREAM", + 5: "LT_CHARACTER_STREAM", + } + LobType_value = map[string]int32{ + "LT_BLOB": 0, + "LT_CLOB": 1, + "LT_BINARY_STREAM": 2, + "LT_ASCII_STREAM": 3, + "LT_UNICODE_STREAM": 4, + "LT_CHARACTER_STREAM": 5, + } +) + +func (x LobType) Enum() *LobType { + p := new(LobType) + *p = x + return p +} + +func (x LobType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (LobType) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[7].Descriptor() +} + +func (LobType) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[7] +} + +func (x LobType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use LobType.Descriptor instead. +func (LobType) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{7} +} + +type ResourceType int32 + +const ( + ResourceType_RES_RESULT_SET ResourceType = 0 + ResourceType_RES_STATEMENT ResourceType = 1 + ResourceType_RES_PREPARED_STATEMENT ResourceType = 2 + ResourceType_RES_CALLABLE_STATEMENT ResourceType = 3 + ResourceType_RES_LOB ResourceType = 4 + ResourceType_RES_CONNECTION ResourceType = 5 + ResourceType_RES_SAVEPOINT ResourceType = 6 +) + +// Enum value maps for ResourceType. +var ( + ResourceType_name = map[int32]string{ + 0: "RES_RESULT_SET", + 1: "RES_STATEMENT", + 2: "RES_PREPARED_STATEMENT", + 3: "RES_CALLABLE_STATEMENT", + 4: "RES_LOB", + 5: "RES_CONNECTION", + 6: "RES_SAVEPOINT", + } + ResourceType_value = map[string]int32{ + "RES_RESULT_SET": 0, + "RES_STATEMENT": 1, + "RES_PREPARED_STATEMENT": 2, + "RES_CALLABLE_STATEMENT": 3, + "RES_LOB": 4, + "RES_CONNECTION": 5, + "RES_SAVEPOINT": 6, + } +) + +func (x ResourceType) Enum() *ResourceType { + p := new(ResourceType) + *p = x + return p +} + +func (x ResourceType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ResourceType) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[8].Descriptor() +} + +func (ResourceType) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[8] +} + +func (x ResourceType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ResourceType.Descriptor instead. +func (ResourceType) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{8} +} + +type CallType int32 + +const ( + CallType_CALL_SET CallType = 0 + CallType_CALL_GET CallType = 1 + CallType_CALL_IS CallType = 2 + CallType_CALL_ALL CallType = 3 + CallType_CALL_NULLS CallType = 4 + CallType_CALL_USES CallType = 5 + CallType_CALL_SUPPORTS CallType = 6 + CallType_CALL_STORES CallType = 7 + CallType_CALL_NULL CallType = 8 + CallType_CALL_DOES CallType = 9 + CallType_CALL_DATA CallType = 10 + CallType_CALL_NEXT CallType = 11 + CallType_CALL_CLOSE CallType = 12 + CallType_CALL_WAS CallType = 13 + CallType_CALL_CLEAR CallType = 14 + CallType_CALL_FIND CallType = 15 + CallType_CALL_BEFORE CallType = 16 + CallType_CALL_AFTER CallType = 17 + CallType_CALL_FIRST CallType = 18 + CallType_CALL_LAST CallType = 19 + CallType_CALL_ABSOLUTE CallType = 20 + CallType_CALL_RELATIVE CallType = 21 + CallType_CALL_PREVIOUS CallType = 22 + CallType_CALL_ROW CallType = 23 + CallType_CALL_UPDATE CallType = 24 + CallType_CALL_INSERT CallType = 25 + CallType_CALL_DELETE CallType = 26 + CallType_CALL_REFRESH CallType = 27 + CallType_CALL_CANCEL CallType = 28 + CallType_CALL_MOVE CallType = 29 + CallType_CALL_OWN CallType = 30 + CallType_CALL_OTHERS CallType = 31 + CallType_CALL_UPDATES CallType = 32 + CallType_CALL_DELETES CallType = 33 + CallType_CALL_INSERTS CallType = 34 + CallType_CALL_LOCATORS CallType = 35 + CallType_CALL_AUTO CallType = 36 + CallType_CALL_GENERATED CallType = 37 + CallType_CALL_RELEASE CallType = 38 + CallType_CALL_NATIVE CallType = 39 + CallType_CALL_PREPARE CallType = 40 + CallType_CALL_ROLLBACK CallType = 41 + CallType_CALL_ABORT CallType = 42 + CallType_CALL_EXECUTE CallType = 43 + CallType_CALL_ADD CallType = 44 + CallType_CALL_ENQUOTE CallType = 45 + CallType_CALL_REGISTER CallType = 46 + CallType_CALL_LENGTH CallType = 47 +) + +// Enum value maps for CallType. +var ( + CallType_name = map[int32]string{ + 0: "CALL_SET", + 1: "CALL_GET", + 2: "CALL_IS", + 3: "CALL_ALL", + 4: "CALL_NULLS", + 5: "CALL_USES", + 6: "CALL_SUPPORTS", + 7: "CALL_STORES", + 8: "CALL_NULL", + 9: "CALL_DOES", + 10: "CALL_DATA", + 11: "CALL_NEXT", + 12: "CALL_CLOSE", + 13: "CALL_WAS", + 14: "CALL_CLEAR", + 15: "CALL_FIND", + 16: "CALL_BEFORE", + 17: "CALL_AFTER", + 18: "CALL_FIRST", + 19: "CALL_LAST", + 20: "CALL_ABSOLUTE", + 21: "CALL_RELATIVE", + 22: "CALL_PREVIOUS", + 23: "CALL_ROW", + 24: "CALL_UPDATE", + 25: "CALL_INSERT", + 26: "CALL_DELETE", + 27: "CALL_REFRESH", + 28: "CALL_CANCEL", + 29: "CALL_MOVE", + 30: "CALL_OWN", + 31: "CALL_OTHERS", + 32: "CALL_UPDATES", + 33: "CALL_DELETES", + 34: "CALL_INSERTS", + 35: "CALL_LOCATORS", + 36: "CALL_AUTO", + 37: "CALL_GENERATED", + 38: "CALL_RELEASE", + 39: "CALL_NATIVE", + 40: "CALL_PREPARE", + 41: "CALL_ROLLBACK", + 42: "CALL_ABORT", + 43: "CALL_EXECUTE", + 44: "CALL_ADD", + 45: "CALL_ENQUOTE", + 46: "CALL_REGISTER", + 47: "CALL_LENGTH", + } + CallType_value = map[string]int32{ + "CALL_SET": 0, + "CALL_GET": 1, + "CALL_IS": 2, + "CALL_ALL": 3, + "CALL_NULLS": 4, + "CALL_USES": 5, + "CALL_SUPPORTS": 6, + "CALL_STORES": 7, + "CALL_NULL": 8, + "CALL_DOES": 9, + "CALL_DATA": 10, + "CALL_NEXT": 11, + "CALL_CLOSE": 12, + "CALL_WAS": 13, + "CALL_CLEAR": 14, + "CALL_FIND": 15, + "CALL_BEFORE": 16, + "CALL_AFTER": 17, + "CALL_FIRST": 18, + "CALL_LAST": 19, + "CALL_ABSOLUTE": 20, + "CALL_RELATIVE": 21, + "CALL_PREVIOUS": 22, + "CALL_ROW": 23, + "CALL_UPDATE": 24, + "CALL_INSERT": 25, + "CALL_DELETE": 26, + "CALL_REFRESH": 27, + "CALL_CANCEL": 28, + "CALL_MOVE": 29, + "CALL_OWN": 30, + "CALL_OTHERS": 31, + "CALL_UPDATES": 32, + "CALL_DELETES": 33, + "CALL_INSERTS": 34, + "CALL_LOCATORS": 35, + "CALL_AUTO": 36, + "CALL_GENERATED": 37, + "CALL_RELEASE": 38, + "CALL_NATIVE": 39, + "CALL_PREPARE": 40, + "CALL_ROLLBACK": 41, + "CALL_ABORT": 42, + "CALL_EXECUTE": 43, + "CALL_ADD": 44, + "CALL_ENQUOTE": 45, + "CALL_REGISTER": 46, + "CALL_LENGTH": 47, + } +) + +func (x CallType) Enum() *CallType { + p := new(CallType) + *p = x + return p +} + +func (x CallType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CallType) Descriptor() protoreflect.EnumDescriptor { + return file_StatementService_proto_enumTypes[9].Descriptor() +} + +func (CallType) Type() protoreflect.EnumType { + return &file_StatementService_proto_enumTypes[9] +} + +func (x CallType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CallType.Descriptor instead. +func (CallType) EnumDescriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{9} +} + +type ConnectionDetails struct { + state protoimpl.MessageState `protogen:"open.v1"` + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + User string `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"` + Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` + ClientUUID string `protobuf:"bytes,4,opt,name=clientUUID,proto3" json:"clientUUID,omitempty"` + Properties []*PropertyEntry `protobuf:"bytes,6,rep,name=properties,proto3" json:"properties,omitempty"` + IsXA bool `protobuf:"varint,7,opt,name=isXA,proto3" json:"isXA,omitempty"` // Flag to indicate XA connection + ServerEndpoints []string `protobuf:"bytes,8,rep,name=serverEndpoints,proto3" json:"serverEndpoints,omitempty"` // List of server endpoints in the cluster for coordination + ClusterHealth string `protobuf:"bytes,9,opt,name=clusterHealth,proto3" json:"clusterHealth,omitempty"` // Cluster health status (e.g., "localhost:10591(UP);localhost:10592(DOWN)") + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConnectionDetails) Reset() { + *x = ConnectionDetails{} + mi := &file_StatementService_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConnectionDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConnectionDetails) ProtoMessage() {} + +func (x *ConnectionDetails) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ConnectionDetails.ProtoReflect.Descriptor instead. +func (*ConnectionDetails) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{0} +} + +func (x *ConnectionDetails) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *ConnectionDetails) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +func (x *ConnectionDetails) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *ConnectionDetails) GetClientUUID() string { + if x != nil { + return x.ClientUUID + } + return "" +} + +func (x *ConnectionDetails) GetProperties() []*PropertyEntry { + if x != nil { + return x.Properties + } + return nil +} + +func (x *ConnectionDetails) GetIsXA() bool { + if x != nil { + return x.IsXA + } + return false +} + +func (x *ConnectionDetails) GetServerEndpoints() []string { + if x != nil { + return x.ServerEndpoints + } + return nil +} + +func (x *ConnectionDetails) GetClusterHealth() string { + if x != nil { + return x.ClusterHealth + } + return "" +} + +// Wrapper message for timestamp with timezone information +type TimestampWithZone struct { + state protoimpl.MessageState `protogen:"open.v1"` + Instant *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=instant,proto3" json:"instant,omitempty"` // Absolute instant (seconds + nanos since epoch) + Timezone string `protobuf:"bytes,2,opt,name=timezone,proto3" json:"timezone,omitempty"` // IANA ZoneId string (e.g., "Europe/Rome") or offset (e.g., "+02:00") + OriginalType TemporalType `protobuf:"varint,3,opt,name=original_type,json=originalType,proto3,enum=com.openjproxy.grpc.TemporalType" json:"original_type,omitempty"` // Track original Java type (Timestamp or Calendar) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TimestampWithZone) Reset() { + *x = TimestampWithZone{} + mi := &file_StatementService_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TimestampWithZone) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TimestampWithZone) ProtoMessage() {} + +func (x *TimestampWithZone) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TimestampWithZone.ProtoReflect.Descriptor instead. +func (*TimestampWithZone) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{1} +} + +func (x *TimestampWithZone) GetInstant() *timestamppb.Timestamp { + if x != nil { + return x.Instant + } + return nil +} + +func (x *TimestampWithZone) GetTimezone() string { + if x != nil { + return x.Timezone + } + return "" +} + +func (x *TimestampWithZone) GetOriginalType() TemporalType { + if x != nil { + return x.OriginalType + } + return TemporalType_TEMPORAL_TYPE_UNSPECIFIED +} + +// Message representing a single value in a parameter +type ParameterValue struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Value: + // + // *ParameterValue_BoolValue + // *ParameterValue_IntValue + // *ParameterValue_LongValue + // *ParameterValue_FloatValue + // *ParameterValue_DoubleValue + // *ParameterValue_StringValue + // *ParameterValue_BytesValue + // *ParameterValue_IntArrayValue + // *ParameterValue_LongArrayValue + // *ParameterValue_IsNull + // *ParameterValue_TimestampValue + // *ParameterValue_DateValue + // *ParameterValue_TimeValue + // *ParameterValue_UrlValue + // *ParameterValue_RowidValue + // *ParameterValue_UuidValue + // *ParameterValue_BigintegerValue + // *ParameterValue_StringArrayValue + // *ParameterValue_RowidlifetimeValue + Value isParameterValue_Value `protobuf_oneof:"value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ParameterValue) Reset() { + *x = ParameterValue{} + mi := &file_StatementService_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ParameterValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParameterValue) ProtoMessage() {} + +func (x *ParameterValue) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParameterValue.ProtoReflect.Descriptor instead. +func (*ParameterValue) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{2} +} + +func (x *ParameterValue) GetValue() isParameterValue_Value { + if x != nil { + return x.Value + } + return nil +} + +func (x *ParameterValue) GetBoolValue() bool { + if x != nil { + if x, ok := x.Value.(*ParameterValue_BoolValue); ok { + return x.BoolValue + } + } + return false +} + +func (x *ParameterValue) GetIntValue() int32 { + if x != nil { + if x, ok := x.Value.(*ParameterValue_IntValue); ok { + return x.IntValue + } + } + return 0 +} + +func (x *ParameterValue) GetLongValue() int64 { + if x != nil { + if x, ok := x.Value.(*ParameterValue_LongValue); ok { + return x.LongValue + } + } + return 0 +} + +func (x *ParameterValue) GetFloatValue() float32 { + if x != nil { + if x, ok := x.Value.(*ParameterValue_FloatValue); ok { + return x.FloatValue + } + } + return 0 +} + +func (x *ParameterValue) GetDoubleValue() float64 { + if x != nil { + if x, ok := x.Value.(*ParameterValue_DoubleValue); ok { + return x.DoubleValue + } + } + return 0 +} + +func (x *ParameterValue) GetStringValue() string { + if x != nil { + if x, ok := x.Value.(*ParameterValue_StringValue); ok { + return x.StringValue + } + } + return "" +} + +func (x *ParameterValue) GetBytesValue() []byte { + if x != nil { + if x, ok := x.Value.(*ParameterValue_BytesValue); ok { + return x.BytesValue + } + } + return nil +} + +func (x *ParameterValue) GetIntArrayValue() *IntArray { + if x != nil { + if x, ok := x.Value.(*ParameterValue_IntArrayValue); ok { + return x.IntArrayValue + } + } + return nil +} + +func (x *ParameterValue) GetLongArrayValue() *LongArray { + if x != nil { + if x, ok := x.Value.(*ParameterValue_LongArrayValue); ok { + return x.LongArrayValue + } + } + return nil +} + +func (x *ParameterValue) GetIsNull() bool { + if x != nil { + if x, ok := x.Value.(*ParameterValue_IsNull); ok { + return x.IsNull + } + } + return false +} + +func (x *ParameterValue) GetTimestampValue() *TimestampWithZone { + if x != nil { + if x, ok := x.Value.(*ParameterValue_TimestampValue); ok { + return x.TimestampValue + } + } + return nil +} + +func (x *ParameterValue) GetDateValue() *date.Date { + if x != nil { + if x, ok := x.Value.(*ParameterValue_DateValue); ok { + return x.DateValue + } + } + return nil +} + +func (x *ParameterValue) GetTimeValue() *timeofday.TimeOfDay { + if x != nil { + if x, ok := x.Value.(*ParameterValue_TimeValue); ok { + return x.TimeValue + } + } + return nil +} + +func (x *ParameterValue) GetUrlValue() *wrapperspb.StringValue { + if x != nil { + if x, ok := x.Value.(*ParameterValue_UrlValue); ok { + return x.UrlValue + } + } + return nil +} + +func (x *ParameterValue) GetRowidValue() *wrapperspb.StringValue { + if x != nil { + if x, ok := x.Value.(*ParameterValue_RowidValue); ok { + return x.RowidValue + } + } + return nil +} + +func (x *ParameterValue) GetUuidValue() *wrapperspb.StringValue { + if x != nil { + if x, ok := x.Value.(*ParameterValue_UuidValue); ok { + return x.UuidValue + } + } + return nil +} + +func (x *ParameterValue) GetBigintegerValue() *wrapperspb.StringValue { + if x != nil { + if x, ok := x.Value.(*ParameterValue_BigintegerValue); ok { + return x.BigintegerValue + } + } + return nil +} + +func (x *ParameterValue) GetStringArrayValue() *StringArray { + if x != nil { + if x, ok := x.Value.(*ParameterValue_StringArrayValue); ok { + return x.StringArrayValue + } + } + return nil +} + +func (x *ParameterValue) GetRowidlifetimeValue() *wrapperspb.StringValue { + if x != nil { + if x, ok := x.Value.(*ParameterValue_RowidlifetimeValue); ok { + return x.RowidlifetimeValue + } + } + return nil +} + +type isParameterValue_Value interface { + isParameterValue_Value() +} + +type ParameterValue_BoolValue struct { + BoolValue bool `protobuf:"varint,1,opt,name=bool_value,json=boolValue,proto3,oneof"` +} + +type ParameterValue_IntValue struct { + IntValue int32 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` +} + +type ParameterValue_LongValue struct { + LongValue int64 `protobuf:"varint,3,opt,name=long_value,json=longValue,proto3,oneof"` +} + +type ParameterValue_FloatValue struct { + FloatValue float32 `protobuf:"fixed32,4,opt,name=float_value,json=floatValue,proto3,oneof"` +} + +type ParameterValue_DoubleValue struct { + DoubleValue float64 `protobuf:"fixed64,5,opt,name=double_value,json=doubleValue,proto3,oneof"` +} + +type ParameterValue_StringValue struct { + StringValue string `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof"` +} + +type ParameterValue_BytesValue struct { + BytesValue []byte `protobuf:"bytes,7,opt,name=bytes_value,json=bytesValue,proto3,oneof"` +} + +type ParameterValue_IntArrayValue struct { + IntArrayValue *IntArray `protobuf:"bytes,8,opt,name=int_array_value,json=intArrayValue,proto3,oneof"` +} + +type ParameterValue_LongArrayValue struct { + LongArrayValue *LongArray `protobuf:"bytes,9,opt,name=long_array_value,json=longArrayValue,proto3,oneof"` +} + +type ParameterValue_IsNull struct { + IsNull bool `protobuf:"varint,10,opt,name=is_null,json=isNull,proto3,oneof"` // Explicit null marker to distinguish null from empty bytes +} + +type ParameterValue_TimestampValue struct { + TimestampValue *TimestampWithZone `protobuf:"bytes,11,opt,name=timestamp_value,json=timestampValue,proto3,oneof"` // Timestamp with timezone +} + +type ParameterValue_DateValue struct { + DateValue *date.Date `protobuf:"bytes,12,opt,name=date_value,json=dateValue,proto3,oneof"` // Date-only value (year, month, day) +} + +type ParameterValue_TimeValue struct { + TimeValue *timeofday.TimeOfDay `protobuf:"bytes,13,opt,name=time_value,json=timeValue,proto3,oneof"` // Time-only value (hours, minutes, seconds, nanos) +} + +type ParameterValue_UrlValue struct { + // URL encoded as string: URL.toExternalForm() on write, new URL(string) on read + // Presence-aware: unset means null, empty string is a valid (though unusual) URL value + UrlValue *wrapperspb.StringValue `protobuf:"bytes,14,opt,name=url_value,json=urlValue,proto3,oneof"` +} + +type ParameterValue_RowidValue struct { + // RowId encoded as base64 string of rowId.getBytes() + // Opaque bytes representation - vendor-specific, cannot be reconstructed into java.sql.RowId + // Presence-aware: unset means null, empty string means zero-length rowid bytes + RowidValue *wrapperspb.StringValue `protobuf:"bytes,15,opt,name=rowid_value,json=rowidValue,proto3,oneof"` +} + +type ParameterValue_UuidValue struct { + // UUID encoded as canonical string representation (8-4-4-4-12 hex format) + // Presence-aware: unset means null + UuidValue *wrapperspb.StringValue `protobuf:"bytes,16,opt,name=uuid_value,json=uuidValue,proto3,oneof"` +} + +type ParameterValue_BigintegerValue struct { + // BigInteger encoded as string (decimal representation) + // Presence-aware: unset means null + BigintegerValue *wrapperspb.StringValue `protobuf:"bytes,17,opt,name=biginteger_value,json=bigintegerValue,proto3,oneof"` +} + +type ParameterValue_StringArrayValue struct { + // String array for JDBC methods like execute(sql, String[] columnNames) + StringArrayValue *StringArray `protobuf:"bytes,18,opt,name=string_array_value,json=stringArrayValue,proto3,oneof"` +} + +type ParameterValue_RowidlifetimeValue struct { + // RowIdLifetime encoded as enum name string (e.g., "ROWID_VALID_FOREVER") + // Presence-aware: unset means null + RowidlifetimeValue *wrapperspb.StringValue `protobuf:"bytes,19,opt,name=rowidlifetime_value,json=rowidlifetimeValue,proto3,oneof"` +} + +func (*ParameterValue_BoolValue) isParameterValue_Value() {} + +func (*ParameterValue_IntValue) isParameterValue_Value() {} + +func (*ParameterValue_LongValue) isParameterValue_Value() {} + +func (*ParameterValue_FloatValue) isParameterValue_Value() {} + +func (*ParameterValue_DoubleValue) isParameterValue_Value() {} + +func (*ParameterValue_StringValue) isParameterValue_Value() {} + +func (*ParameterValue_BytesValue) isParameterValue_Value() {} + +func (*ParameterValue_IntArrayValue) isParameterValue_Value() {} + +func (*ParameterValue_LongArrayValue) isParameterValue_Value() {} + +func (*ParameterValue_IsNull) isParameterValue_Value() {} + +func (*ParameterValue_TimestampValue) isParameterValue_Value() {} + +func (*ParameterValue_DateValue) isParameterValue_Value() {} + +func (*ParameterValue_TimeValue) isParameterValue_Value() {} + +func (*ParameterValue_UrlValue) isParameterValue_Value() {} + +func (*ParameterValue_RowidValue) isParameterValue_Value() {} + +func (*ParameterValue_UuidValue) isParameterValue_Value() {} + +func (*ParameterValue_BigintegerValue) isParameterValue_Value() {} + +func (*ParameterValue_StringArrayValue) isParameterValue_Value() {} + +func (*ParameterValue_RowidlifetimeValue) isParameterValue_Value() {} + +// Message for int array +type IntArray struct { + state protoimpl.MessageState `protogen:"open.v1"` + Values []int32 `protobuf:"varint,1,rep,packed,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IntArray) Reset() { + *x = IntArray{} + mi := &file_StatementService_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IntArray) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IntArray) ProtoMessage() {} + +func (x *IntArray) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IntArray.ProtoReflect.Descriptor instead. +func (*IntArray) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{3} +} + +func (x *IntArray) GetValues() []int32 { + if x != nil { + return x.Values + } + return nil +} + +// Message for long array +type LongArray struct { + state protoimpl.MessageState `protogen:"open.v1"` + Values []int64 `protobuf:"varint,1,rep,packed,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LongArray) Reset() { + *x = LongArray{} + mi := &file_StatementService_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LongArray) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LongArray) ProtoMessage() {} + +func (x *LongArray) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LongArray.ProtoReflect.Descriptor instead. +func (*LongArray) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{4} +} + +func (x *LongArray) GetValues() []int64 { + if x != nil { + return x.Values + } + return nil +} + +// Message for string array +type StringArray struct { + state protoimpl.MessageState `protogen:"open.v1"` + Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StringArray) Reset() { + *x = StringArray{} + mi := &file_StatementService_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StringArray) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StringArray) ProtoMessage() {} + +func (x *StringArray) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StringArray.ProtoReflect.Descriptor instead. +func (*StringArray) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{5} +} + +func (x *StringArray) GetValues() []string { + if x != nil { + return x.Values + } + return nil +} + +// Message representing a JDBC parameter +type ParameterProto struct { + state protoimpl.MessageState `protogen:"open.v1"` + Index int32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + Type ParameterTypeProto `protobuf:"varint,2,opt,name=type,proto3,enum=com.openjproxy.grpc.ParameterTypeProto" json:"type,omitempty"` + Values []*ParameterValue `protobuf:"bytes,3,rep,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ParameterProto) Reset() { + *x = ParameterProto{} + mi := &file_StatementService_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ParameterProto) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParameterProto) ProtoMessage() {} + +func (x *ParameterProto) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParameterProto.ProtoReflect.Descriptor instead. +func (*ParameterProto) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{6} +} + +func (x *ParameterProto) GetIndex() int32 { + if x != nil { + return x.Index + } + return 0 +} + +func (x *ParameterProto) GetType() ParameterTypeProto { + if x != nil { + return x.Type + } + return ParameterTypeProto_PT_NULL +} + +func (x *ParameterProto) GetValues() []*ParameterValue { + if x != nil { + return x.Values + } + return nil +} + +// Message representing a property entry (key-value pair) +type PropertyEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // Types that are valid to be assigned to Value: + // + // *PropertyEntry_BoolValue + // *PropertyEntry_IntValue + // *PropertyEntry_LongValue + // *PropertyEntry_FloatValue + // *PropertyEntry_DoubleValue + // *PropertyEntry_StringValue + // *PropertyEntry_BytesValue + Value isPropertyEntry_Value `protobuf_oneof:"value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PropertyEntry) Reset() { + *x = PropertyEntry{} + mi := &file_StatementService_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PropertyEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PropertyEntry) ProtoMessage() {} + +func (x *PropertyEntry) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PropertyEntry.ProtoReflect.Descriptor instead. +func (*PropertyEntry) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{7} +} + +func (x *PropertyEntry) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *PropertyEntry) GetValue() isPropertyEntry_Value { + if x != nil { + return x.Value + } + return nil +} + +func (x *PropertyEntry) GetBoolValue() bool { + if x != nil { + if x, ok := x.Value.(*PropertyEntry_BoolValue); ok { + return x.BoolValue + } + } + return false +} + +func (x *PropertyEntry) GetIntValue() int32 { + if x != nil { + if x, ok := x.Value.(*PropertyEntry_IntValue); ok { + return x.IntValue + } + } + return 0 +} + +func (x *PropertyEntry) GetLongValue() int64 { + if x != nil { + if x, ok := x.Value.(*PropertyEntry_LongValue); ok { + return x.LongValue + } + } + return 0 +} + +func (x *PropertyEntry) GetFloatValue() float32 { + if x != nil { + if x, ok := x.Value.(*PropertyEntry_FloatValue); ok { + return x.FloatValue + } + } + return 0 +} + +func (x *PropertyEntry) GetDoubleValue() float64 { + if x != nil { + if x, ok := x.Value.(*PropertyEntry_DoubleValue); ok { + return x.DoubleValue + } + } + return 0 +} + +func (x *PropertyEntry) GetStringValue() string { + if x != nil { + if x, ok := x.Value.(*PropertyEntry_StringValue); ok { + return x.StringValue + } + } + return "" +} + +func (x *PropertyEntry) GetBytesValue() []byte { + if x != nil { + if x, ok := x.Value.(*PropertyEntry_BytesValue); ok { + return x.BytesValue + } + } + return nil +} + +type isPropertyEntry_Value interface { + isPropertyEntry_Value() +} + +type PropertyEntry_BoolValue struct { + BoolValue bool `protobuf:"varint,2,opt,name=bool_value,json=boolValue,proto3,oneof"` +} + +type PropertyEntry_IntValue struct { + IntValue int32 `protobuf:"varint,3,opt,name=int_value,json=intValue,proto3,oneof"` +} + +type PropertyEntry_LongValue struct { + LongValue int64 `protobuf:"varint,4,opt,name=long_value,json=longValue,proto3,oneof"` +} + +type PropertyEntry_FloatValue struct { + FloatValue float32 `protobuf:"fixed32,5,opt,name=float_value,json=floatValue,proto3,oneof"` +} + +type PropertyEntry_DoubleValue struct { + DoubleValue float64 `protobuf:"fixed64,6,opt,name=double_value,json=doubleValue,proto3,oneof"` +} + +type PropertyEntry_StringValue struct { + StringValue string `protobuf:"bytes,7,opt,name=string_value,json=stringValue,proto3,oneof"` +} + +type PropertyEntry_BytesValue struct { + BytesValue []byte `protobuf:"bytes,8,opt,name=bytes_value,json=bytesValue,proto3,oneof"` +} + +func (*PropertyEntry_BoolValue) isPropertyEntry_Value() {} + +func (*PropertyEntry_IntValue) isPropertyEntry_Value() {} + +func (*PropertyEntry_LongValue) isPropertyEntry_Value() {} + +func (*PropertyEntry_FloatValue) isPropertyEntry_Value() {} + +func (*PropertyEntry_DoubleValue) isPropertyEntry_Value() {} + +func (*PropertyEntry_StringValue) isPropertyEntry_Value() {} + +func (*PropertyEntry_BytesValue) isPropertyEntry_Value() {} + +// Message representing a row in a result set +type ResultRow struct { + state protoimpl.MessageState `protogen:"open.v1"` + Columns []*ParameterValue `protobuf:"bytes,1,rep,name=columns,proto3" json:"columns,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResultRow) Reset() { + *x = ResultRow{} + mi := &file_StatementService_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResultRow) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResultRow) ProtoMessage() {} + +func (x *ResultRow) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResultRow.ProtoReflect.Descriptor instead. +func (*ResultRow) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{8} +} + +func (x *ResultRow) GetColumns() []*ParameterValue { + if x != nil { + return x.Columns + } + return nil +} + +// Message representing query result data +type OpQueryResultProto struct { + state protoimpl.MessageState `protogen:"open.v1"` + ResultSetUUID string `protobuf:"bytes,1,opt,name=resultSetUUID,proto3" json:"resultSetUUID,omitempty"` + Labels []string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty"` + Rows []*ResultRow `protobuf:"bytes,3,rep,name=rows,proto3" json:"rows,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *OpQueryResultProto) Reset() { + *x = OpQueryResultProto{} + mi := &file_StatementService_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OpQueryResultProto) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpQueryResultProto) ProtoMessage() {} + +func (x *OpQueryResultProto) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpQueryResultProto.ProtoReflect.Descriptor instead. +func (*OpQueryResultProto) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{9} +} + +func (x *OpQueryResultProto) GetResultSetUUID() string { + if x != nil { + return x.ResultSetUUID + } + return "" +} + +func (x *OpQueryResultProto) GetLabels() []string { + if x != nil { + return x.Labels + } + return nil +} + +func (x *OpQueryResultProto) GetRows() []*ResultRow { + if x != nil { + return x.Rows + } + return nil +} + +type TransactionInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + TransactionUUID string `protobuf:"bytes,1,opt,name=transactionUUID,proto3" json:"transactionUUID,omitempty"` + TransactionStatus TransactionStatus `protobuf:"varint,2,opt,name=transactionStatus,proto3,enum=com.openjproxy.grpc.TransactionStatus" json:"transactionStatus,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TransactionInfo) Reset() { + *x = TransactionInfo{} + mi := &file_StatementService_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TransactionInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionInfo) ProtoMessage() {} + +func (x *TransactionInfo) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionInfo.ProtoReflect.Descriptor instead. +func (*TransactionInfo) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{10} +} + +func (x *TransactionInfo) GetTransactionUUID() string { + if x != nil { + return x.TransactionUUID + } + return "" +} + +func (x *TransactionInfo) GetTransactionStatus() TransactionStatus { + if x != nil { + return x.TransactionStatus + } + return TransactionStatus_TRX_ACTIVE +} + +type SessionInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + ConnHash string `protobuf:"bytes,1,opt,name=connHash,proto3" json:"connHash,omitempty"` + ClientUUID string `protobuf:"bytes,2,opt,name=clientUUID,proto3" json:"clientUUID,omitempty"` + //only set if connection has to be the same among different requests, within transaction boundaries or when using LOB objects. + SessionUUID string `protobuf:"bytes,3,opt,name=sessionUUID,proto3" json:"sessionUUID,omitempty"` + TransactionInfo *TransactionInfo `protobuf:"bytes,4,opt,name=transactionInfo,proto3" json:"transactionInfo,omitempty"` + SessionStatus SessionStatus `protobuf:"varint,5,opt,name=sessionStatus,proto3,enum=com.openjproxy.grpc.SessionStatus" json:"sessionStatus,omitempty"` + IsXA bool `protobuf:"varint,6,opt,name=isXA,proto3" json:"isXA,omitempty"` // Flag indicating this is an XA session + TargetServer string `protobuf:"bytes,7,opt,name=targetServer,proto3" json:"targetServer,omitempty"` // Server endpoint (host:port) for session stickiness binding + ClusterHealth string `protobuf:"bytes,8,opt,name=clusterHealth,proto3" json:"clusterHealth,omitempty"` // Cluster health status: "host1:port1(UP);host2:port2(DOWN);..." + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SessionInfo) Reset() { + *x = SessionInfo{} + mi := &file_StatementService_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SessionInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionInfo) ProtoMessage() {} + +func (x *SessionInfo) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SessionInfo.ProtoReflect.Descriptor instead. +func (*SessionInfo) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{11} +} + +func (x *SessionInfo) GetConnHash() string { + if x != nil { + return x.ConnHash + } + return "" +} + +func (x *SessionInfo) GetClientUUID() string { + if x != nil { + return x.ClientUUID + } + return "" +} + +func (x *SessionInfo) GetSessionUUID() string { + if x != nil { + return x.SessionUUID + } + return "" +} + +func (x *SessionInfo) GetTransactionInfo() *TransactionInfo { + if x != nil { + return x.TransactionInfo + } + return nil +} + +func (x *SessionInfo) GetSessionStatus() SessionStatus { + if x != nil { + return x.SessionStatus + } + return SessionStatus_SESSION_ACTIVE +} + +func (x *SessionInfo) GetIsXA() bool { + if x != nil { + return x.IsXA + } + return false +} + +func (x *SessionInfo) GetTargetServer() string { + if x != nil { + return x.TargetServer + } + return "" +} + +func (x *SessionInfo) GetClusterHealth() string { + if x != nil { + return x.ClusterHealth + } + return "" +} + +type OpResult struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Type ResultType `protobuf:"varint,2,opt,name=type,proto3,enum=com.openjproxy.grpc.ResultType" json:"type,omitempty"` + // Types that are valid to be assigned to Result: + // + // *OpResult_IntValue + // *OpResult_QueryResult + // *OpResult_UuidValue + Result isOpResult_Result `protobuf_oneof:"result"` + Uuid string `protobuf:"bytes,6,opt,name=uuid,proto3" json:"uuid,omitempty"` + Flag string `protobuf:"bytes,7,opt,name=flag,proto3" json:"flag,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *OpResult) Reset() { + *x = OpResult{} + mi := &file_StatementService_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OpResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OpResult) ProtoMessage() {} + +func (x *OpResult) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OpResult.ProtoReflect.Descriptor instead. +func (*OpResult) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{12} +} + +func (x *OpResult) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *OpResult) GetType() ResultType { + if x != nil { + return x.Type + } + return ResultType_INTEGER +} + +func (x *OpResult) GetResult() isOpResult_Result { + if x != nil { + return x.Result + } + return nil +} + +func (x *OpResult) GetIntValue() int32 { + if x != nil { + if x, ok := x.Result.(*OpResult_IntValue); ok { + return x.IntValue + } + } + return 0 +} + +func (x *OpResult) GetQueryResult() *OpQueryResultProto { + if x != nil { + if x, ok := x.Result.(*OpResult_QueryResult); ok { + return x.QueryResult + } + } + return nil +} + +func (x *OpResult) GetUuidValue() string { + if x != nil { + if x, ok := x.Result.(*OpResult_UuidValue); ok { + return x.UuidValue + } + } + return "" +} + +func (x *OpResult) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +func (x *OpResult) GetFlag() string { + if x != nil { + return x.Flag + } + return "" +} + +type isOpResult_Result interface { + isOpResult_Result() +} + +type OpResult_IntValue struct { + IntValue int32 `protobuf:"varint,3,opt,name=int_value,json=intValue,proto3,oneof"` +} + +type OpResult_QueryResult struct { + QueryResult *OpQueryResultProto `protobuf:"bytes,4,opt,name=query_result,json=queryResult,proto3,oneof"` +} + +type OpResult_UuidValue struct { + UuidValue string `protobuf:"bytes,5,opt,name=uuid_value,json=uuidValue,proto3,oneof"` +} + +func (*OpResult_IntValue) isOpResult_Result() {} + +func (*OpResult_QueryResult) isOpResult_Result() {} + +func (*OpResult_UuidValue) isOpResult_Result() {} + +type StatementRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Sql string `protobuf:"bytes,2,opt,name=sql,proto3" json:"sql,omitempty"` + Parameters []*ParameterProto `protobuf:"bytes,3,rep,name=parameters,proto3" json:"parameters,omitempty"` + StatementUUID string `protobuf:"bytes,4,opt,name=statementUUID,proto3" json:"statementUUID,omitempty"` + Properties []*PropertyEntry `protobuf:"bytes,5,rep,name=properties,proto3" json:"properties,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StatementRequest) Reset() { + *x = StatementRequest{} + mi := &file_StatementService_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatementRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatementRequest) ProtoMessage() {} + +func (x *StatementRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatementRequest.ProtoReflect.Descriptor instead. +func (*StatementRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{13} +} + +func (x *StatementRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *StatementRequest) GetSql() string { + if x != nil { + return x.Sql + } + return "" +} + +func (x *StatementRequest) GetParameters() []*ParameterProto { + if x != nil { + return x.Parameters + } + return nil +} + +func (x *StatementRequest) GetStatementUUID() string { + if x != nil { + return x.StatementUUID + } + return "" +} + +func (x *StatementRequest) GetProperties() []*PropertyEntry { + if x != nil { + return x.Properties + } + return nil +} + +type SqlErrorResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"` + SqlState string `protobuf:"bytes,2,opt,name=sqlState,proto3" json:"sqlState,omitempty"` + VendorCode int32 `protobuf:"varint,3,opt,name=vendorCode,proto3" json:"vendorCode,omitempty"` + SqlErrorType SqlErrorType `protobuf:"varint,4,opt,name=sqlErrorType,proto3,enum=com.openjproxy.grpc.SqlErrorType" json:"sqlErrorType,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SqlErrorResponse) Reset() { + *x = SqlErrorResponse{} + mi := &file_StatementService_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SqlErrorResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SqlErrorResponse) ProtoMessage() {} + +func (x *SqlErrorResponse) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SqlErrorResponse.ProtoReflect.Descriptor instead. +func (*SqlErrorResponse) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{14} +} + +func (x *SqlErrorResponse) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *SqlErrorResponse) GetSqlState() string { + if x != nil { + return x.SqlState + } + return "" +} + +func (x *SqlErrorResponse) GetVendorCode() int32 { + if x != nil { + return x.VendorCode + } + return 0 +} + +func (x *SqlErrorResponse) GetSqlErrorType() SqlErrorType { + if x != nil { + return x.SqlErrorType + } + return SqlErrorType_SQL_EXCEPTION +} + +type LobReference struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Uuid string `protobuf:"bytes,2,opt,name=uuid,proto3" json:"uuid,omitempty"` + BytesWritten int32 `protobuf:"varint,3,opt,name=bytesWritten,proto3" json:"bytesWritten,omitempty"` + LobType LobType `protobuf:"varint,4,opt,name=lobType,proto3,enum=com.openjproxy.grpc.LobType" json:"lobType,omitempty"` + //5 till 6 only used to query Binary streams. + ColumnIndex int32 `protobuf:"varint,5,opt,name=columnIndex,proto3" json:"columnIndex,omitempty"` + StmtUUID string `protobuf:"bytes,6,opt,name=stmtUUID,proto3" json:"stmtUUID,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LobReference) Reset() { + *x = LobReference{} + mi := &file_StatementService_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LobReference) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LobReference) ProtoMessage() {} + +func (x *LobReference) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LobReference.ProtoReflect.Descriptor instead. +func (*LobReference) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{15} +} + +func (x *LobReference) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *LobReference) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +func (x *LobReference) GetBytesWritten() int32 { + if x != nil { + return x.BytesWritten + } + return 0 +} + +func (x *LobReference) GetLobType() LobType { + if x != nil { + return x.LobType + } + return LobType_LT_BLOB +} + +func (x *LobReference) GetColumnIndex() int32 { + if x != nil { + return x.ColumnIndex + } + return 0 +} + +func (x *LobReference) GetStmtUUID() string { + if x != nil { + return x.StmtUUID + } + return "" +} + +type ReadLobRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + LobReference *LobReference `protobuf:"bytes,1,opt,name=lobReference,proto3" json:"lobReference,omitempty"` + Position int64 `protobuf:"varint,2,opt,name=position,proto3" json:"position,omitempty"` + Length int32 `protobuf:"varint,3,opt,name=length,proto3" json:"length,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReadLobRequest) Reset() { + *x = ReadLobRequest{} + mi := &file_StatementService_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadLobRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadLobRequest) ProtoMessage() {} + +func (x *ReadLobRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadLobRequest.ProtoReflect.Descriptor instead. +func (*ReadLobRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{16} +} + +func (x *ReadLobRequest) GetLobReference() *LobReference { + if x != nil { + return x.LobReference + } + return nil +} + +func (x *ReadLobRequest) GetPosition() int64 { + if x != nil { + return x.Position + } + return 0 +} + +func (x *ReadLobRequest) GetLength() int32 { + if x != nil { + return x.Length + } + return 0 +} + +type LobDataBlock struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Position int64 `protobuf:"varint,2,opt,name=position,proto3" json:"position,omitempty"` + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + LobType LobType `protobuf:"varint,4,opt,name=lobType,proto3,enum=com.openjproxy.grpc.LobType" json:"lobType,omitempty"` + Metadata []*PropertyEntry `protobuf:"bytes,5,rep,name=metadata,proto3" json:"metadata,omitempty"` // Used for Binary stream where the prepared statement has to be created before the execution to set the stream directly to it. + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LobDataBlock) Reset() { + *x = LobDataBlock{} + mi := &file_StatementService_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LobDataBlock) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LobDataBlock) ProtoMessage() {} + +func (x *LobDataBlock) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LobDataBlock.ProtoReflect.Descriptor instead. +func (*LobDataBlock) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{17} +} + +func (x *LobDataBlock) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *LobDataBlock) GetPosition() int64 { + if x != nil { + return x.Position + } + return 0 +} + +func (x *LobDataBlock) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +func (x *LobDataBlock) GetLobType() LobType { + if x != nil { + return x.LobType + } + return LobType_LT_BLOB +} + +func (x *LobDataBlock) GetMetadata() []*PropertyEntry { + if x != nil { + return x.Metadata + } + return nil +} + +type SessionTerminationStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + Terminated bool `protobuf:"varint,1,opt,name=terminated,proto3" json:"terminated,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SessionTerminationStatus) Reset() { + *x = SessionTerminationStatus{} + mi := &file_StatementService_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SessionTerminationStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionTerminationStatus) ProtoMessage() {} + +func (x *SessionTerminationStatus) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SessionTerminationStatus.ProtoReflect.Descriptor instead. +func (*SessionTerminationStatus) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{18} +} + +func (x *SessionTerminationStatus) GetTerminated() bool { + if x != nil { + return x.Terminated + } + return false +} + +type TargetCall struct { + state protoimpl.MessageState `protogen:"open.v1"` + CallType CallType `protobuf:"varint,1,opt,name=callType,proto3,enum=com.openjproxy.grpc.CallType" json:"callType,omitempty"` + ResourceName string `protobuf:"bytes,2,opt,name=resourceName,proto3" json:"resourceName,omitempty"` + Params []*ParameterValue `protobuf:"bytes,3,rep,name=params,proto3" json:"params,omitempty"` + NextCall *TargetCall `protobuf:"bytes,4,opt,name=nextCall,proto3" json:"nextCall,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TargetCall) Reset() { + *x = TargetCall{} + mi := &file_StatementService_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TargetCall) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TargetCall) ProtoMessage() {} + +func (x *TargetCall) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TargetCall.ProtoReflect.Descriptor instead. +func (*TargetCall) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{19} +} + +func (x *TargetCall) GetCallType() CallType { + if x != nil { + return x.CallType + } + return CallType_CALL_SET +} + +func (x *TargetCall) GetResourceName() string { + if x != nil { + return x.ResourceName + } + return "" +} + +func (x *TargetCall) GetParams() []*ParameterValue { + if x != nil { + return x.Params + } + return nil +} + +func (x *TargetCall) GetNextCall() *TargetCall { + if x != nil { + return x.NextCall + } + return nil +} + +type CallResourceRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + ResourceType ResourceType `protobuf:"varint,2,opt,name=resourceType,proto3,enum=com.openjproxy.grpc.ResourceType" json:"resourceType,omitempty"` + ResourceUUID string `protobuf:"bytes,3,opt,name=resourceUUID,proto3" json:"resourceUUID,omitempty"` + Target *TargetCall `protobuf:"bytes,4,opt,name=target,proto3" json:"target,omitempty"` + Properties []*PropertyEntry `protobuf:"bytes,5,rep,name=properties,proto3" json:"properties,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CallResourceRequest) Reset() { + *x = CallResourceRequest{} + mi := &file_StatementService_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CallResourceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CallResourceRequest) ProtoMessage() {} + +func (x *CallResourceRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CallResourceRequest.ProtoReflect.Descriptor instead. +func (*CallResourceRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{20} +} + +func (x *CallResourceRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *CallResourceRequest) GetResourceType() ResourceType { + if x != nil { + return x.ResourceType + } + return ResourceType_RES_RESULT_SET +} + +func (x *CallResourceRequest) GetResourceUUID() string { + if x != nil { + return x.ResourceUUID + } + return "" +} + +func (x *CallResourceRequest) GetTarget() *TargetCall { + if x != nil { + return x.Target + } + return nil +} + +func (x *CallResourceRequest) GetProperties() []*PropertyEntry { + if x != nil { + return x.Properties + } + return nil +} + +type CallResourceResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + ResourceUUID string `protobuf:"bytes,2,opt,name=resourceUUID,proto3" json:"resourceUUID,omitempty"` + Values []*ParameterValue `protobuf:"bytes,3,rep,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CallResourceResponse) Reset() { + *x = CallResourceResponse{} + mi := &file_StatementService_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CallResourceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CallResourceResponse) ProtoMessage() {} + +func (x *CallResourceResponse) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CallResourceResponse.ProtoReflect.Descriptor instead. +func (*CallResourceResponse) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{21} +} + +func (x *CallResourceResponse) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *CallResourceResponse) GetResourceUUID() string { + if x != nil { + return x.ResourceUUID + } + return "" +} + +func (x *CallResourceResponse) GetValues() []*ParameterValue { + if x != nil { + return x.Values + } + return nil +} + +type ResultSetFetchRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + ResultSetUUID string `protobuf:"bytes,2,opt,name=resultSetUUID,proto3" json:"resultSetUUID,omitempty"` + Size int32 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResultSetFetchRequest) Reset() { + *x = ResultSetFetchRequest{} + mi := &file_StatementService_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResultSetFetchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResultSetFetchRequest) ProtoMessage() {} + +func (x *ResultSetFetchRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResultSetFetchRequest.ProtoReflect.Descriptor instead. +func (*ResultSetFetchRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{22} +} + +func (x *ResultSetFetchRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *ResultSetFetchRequest) GetResultSetUUID() string { + if x != nil { + return x.ResultSetUUID + } + return "" +} + +func (x *ResultSetFetchRequest) GetSize() int32 { + if x != nil { + return x.Size + } + return 0 +} + +// Represents a distributed transaction identifier (Xid) +type XidProto struct { + state protoimpl.MessageState `protogen:"open.v1"` + FormatId int32 `protobuf:"varint,1,opt,name=formatId,proto3" json:"formatId,omitempty"` + GlobalTransactionId []byte `protobuf:"bytes,2,opt,name=globalTransactionId,proto3" json:"globalTransactionId,omitempty"` + BranchQualifier []byte `protobuf:"bytes,3,opt,name=branchQualifier,proto3" json:"branchQualifier,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XidProto) Reset() { + *x = XidProto{} + mi := &file_StatementService_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XidProto) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XidProto) ProtoMessage() {} + +func (x *XidProto) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XidProto.ProtoReflect.Descriptor instead. +func (*XidProto) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{23} +} + +func (x *XidProto) GetFormatId() int32 { + if x != nil { + return x.FormatId + } + return 0 +} + +func (x *XidProto) GetGlobalTransactionId() []byte { + if x != nil { + return x.GlobalTransactionId + } + return nil +} + +func (x *XidProto) GetBranchQualifier() []byte { + if x != nil { + return x.BranchQualifier + } + return nil +} + +// Request to start an XA transaction +type XaStartRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Xid *XidProto `protobuf:"bytes,2,opt,name=xid,proto3" json:"xid,omitempty"` + Flags int32 `protobuf:"varint,3,opt,name=flags,proto3" json:"flags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaStartRequest) Reset() { + *x = XaStartRequest{} + mi := &file_StatementService_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaStartRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaStartRequest) ProtoMessage() {} + +func (x *XaStartRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaStartRequest.ProtoReflect.Descriptor instead. +func (*XaStartRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{24} +} + +func (x *XaStartRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaStartRequest) GetXid() *XidProto { + if x != nil { + return x.Xid + } + return nil +} + +func (x *XaStartRequest) GetFlags() int32 { + if x != nil { + return x.Flags + } + return 0 +} + +// Request to end an XA transaction +type XaEndRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Xid *XidProto `protobuf:"bytes,2,opt,name=xid,proto3" json:"xid,omitempty"` + Flags int32 `protobuf:"varint,3,opt,name=flags,proto3" json:"flags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaEndRequest) Reset() { + *x = XaEndRequest{} + mi := &file_StatementService_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaEndRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaEndRequest) ProtoMessage() {} + +func (x *XaEndRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaEndRequest.ProtoReflect.Descriptor instead. +func (*XaEndRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{25} +} + +func (x *XaEndRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaEndRequest) GetXid() *XidProto { + if x != nil { + return x.Xid + } + return nil +} + +func (x *XaEndRequest) GetFlags() int32 { + if x != nil { + return x.Flags + } + return 0 +} + +// Request to prepare an XA transaction +type XaPrepareRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Xid *XidProto `protobuf:"bytes,2,opt,name=xid,proto3" json:"xid,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaPrepareRequest) Reset() { + *x = XaPrepareRequest{} + mi := &file_StatementService_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaPrepareRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaPrepareRequest) ProtoMessage() {} + +func (x *XaPrepareRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaPrepareRequest.ProtoReflect.Descriptor instead. +func (*XaPrepareRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{26} +} + +func (x *XaPrepareRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaPrepareRequest) GetXid() *XidProto { + if x != nil { + return x.Xid + } + return nil +} + +// Response for prepare operation +type XaPrepareResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Result int32 `protobuf:"varint,2,opt,name=result,proto3" json:"result,omitempty"` // XA_OK or XA_RDONLY + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaPrepareResponse) Reset() { + *x = XaPrepareResponse{} + mi := &file_StatementService_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaPrepareResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaPrepareResponse) ProtoMessage() {} + +func (x *XaPrepareResponse) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaPrepareResponse.ProtoReflect.Descriptor instead. +func (*XaPrepareResponse) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{27} +} + +func (x *XaPrepareResponse) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaPrepareResponse) GetResult() int32 { + if x != nil { + return x.Result + } + return 0 +} + +// Request to commit an XA transaction +type XaCommitRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Xid *XidProto `protobuf:"bytes,2,opt,name=xid,proto3" json:"xid,omitempty"` + OnePhase bool `protobuf:"varint,3,opt,name=onePhase,proto3" json:"onePhase,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaCommitRequest) Reset() { + *x = XaCommitRequest{} + mi := &file_StatementService_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaCommitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaCommitRequest) ProtoMessage() {} + +func (x *XaCommitRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaCommitRequest.ProtoReflect.Descriptor instead. +func (*XaCommitRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{28} +} + +func (x *XaCommitRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaCommitRequest) GetXid() *XidProto { + if x != nil { + return x.Xid + } + return nil +} + +func (x *XaCommitRequest) GetOnePhase() bool { + if x != nil { + return x.OnePhase + } + return false +} + +// Request to rollback an XA transaction +type XaRollbackRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Xid *XidProto `protobuf:"bytes,2,opt,name=xid,proto3" json:"xid,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaRollbackRequest) Reset() { + *x = XaRollbackRequest{} + mi := &file_StatementService_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaRollbackRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaRollbackRequest) ProtoMessage() {} + +func (x *XaRollbackRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaRollbackRequest.ProtoReflect.Descriptor instead. +func (*XaRollbackRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{29} +} + +func (x *XaRollbackRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaRollbackRequest) GetXid() *XidProto { + if x != nil { + return x.Xid + } + return nil +} + +// Request to recover XIDs +type XaRecoverRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Flag int32 `protobuf:"varint,2,opt,name=flag,proto3" json:"flag,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaRecoverRequest) Reset() { + *x = XaRecoverRequest{} + mi := &file_StatementService_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaRecoverRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaRecoverRequest) ProtoMessage() {} + +func (x *XaRecoverRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaRecoverRequest.ProtoReflect.Descriptor instead. +func (*XaRecoverRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{30} +} + +func (x *XaRecoverRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaRecoverRequest) GetFlag() int32 { + if x != nil { + return x.Flag + } + return 0 +} + +// Response for recover operation +type XaRecoverResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Xids []*XidProto `protobuf:"bytes,2,rep,name=xids,proto3" json:"xids,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaRecoverResponse) Reset() { + *x = XaRecoverResponse{} + mi := &file_StatementService_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaRecoverResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaRecoverResponse) ProtoMessage() {} + +func (x *XaRecoverResponse) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[31] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaRecoverResponse.ProtoReflect.Descriptor instead. +func (*XaRecoverResponse) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{31} +} + +func (x *XaRecoverResponse) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaRecoverResponse) GetXids() []*XidProto { + if x != nil { + return x.Xids + } + return nil +} + +// Request to forget an XA transaction +type XaForgetRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Xid *XidProto `protobuf:"bytes,2,opt,name=xid,proto3" json:"xid,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaForgetRequest) Reset() { + *x = XaForgetRequest{} + mi := &file_StatementService_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaForgetRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaForgetRequest) ProtoMessage() {} + +func (x *XaForgetRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[32] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaForgetRequest.ProtoReflect.Descriptor instead. +func (*XaForgetRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{32} +} + +func (x *XaForgetRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaForgetRequest) GetXid() *XidProto { + if x != nil { + return x.Xid + } + return nil +} + +// Request to set transaction timeout +type XaSetTransactionTimeoutRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Seconds int32 `protobuf:"varint,2,opt,name=seconds,proto3" json:"seconds,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaSetTransactionTimeoutRequest) Reset() { + *x = XaSetTransactionTimeoutRequest{} + mi := &file_StatementService_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaSetTransactionTimeoutRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaSetTransactionTimeoutRequest) ProtoMessage() {} + +func (x *XaSetTransactionTimeoutRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[33] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaSetTransactionTimeoutRequest.ProtoReflect.Descriptor instead. +func (*XaSetTransactionTimeoutRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{33} +} + +func (x *XaSetTransactionTimeoutRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaSetTransactionTimeoutRequest) GetSeconds() int32 { + if x != nil { + return x.Seconds + } + return 0 +} + +// Response for set transaction timeout +type XaSetTransactionTimeoutResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaSetTransactionTimeoutResponse) Reset() { + *x = XaSetTransactionTimeoutResponse{} + mi := &file_StatementService_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaSetTransactionTimeoutResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaSetTransactionTimeoutResponse) ProtoMessage() {} + +func (x *XaSetTransactionTimeoutResponse) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[34] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaSetTransactionTimeoutResponse.ProtoReflect.Descriptor instead. +func (*XaSetTransactionTimeoutResponse) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{34} +} + +func (x *XaSetTransactionTimeoutResponse) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaSetTransactionTimeoutResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +// Request to get transaction timeout +type XaGetTransactionTimeoutRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaGetTransactionTimeoutRequest) Reset() { + *x = XaGetTransactionTimeoutRequest{} + mi := &file_StatementService_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaGetTransactionTimeoutRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaGetTransactionTimeoutRequest) ProtoMessage() {} + +func (x *XaGetTransactionTimeoutRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[35] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaGetTransactionTimeoutRequest.ProtoReflect.Descriptor instead. +func (*XaGetTransactionTimeoutRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{35} +} + +func (x *XaGetTransactionTimeoutRequest) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +// Response for get transaction timeout +type XaGetTransactionTimeoutResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Seconds int32 `protobuf:"varint,2,opt,name=seconds,proto3" json:"seconds,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaGetTransactionTimeoutResponse) Reset() { + *x = XaGetTransactionTimeoutResponse{} + mi := &file_StatementService_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaGetTransactionTimeoutResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaGetTransactionTimeoutResponse) ProtoMessage() {} + +func (x *XaGetTransactionTimeoutResponse) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[36] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaGetTransactionTimeoutResponse.ProtoReflect.Descriptor instead. +func (*XaGetTransactionTimeoutResponse) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{36} +} + +func (x *XaGetTransactionTimeoutResponse) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaGetTransactionTimeoutResponse) GetSeconds() int32 { + if x != nil { + return x.Seconds + } + return 0 +} + +// Request to check if two sessions are from the same resource manager +type XaIsSameRMRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session1 *SessionInfo `protobuf:"bytes,1,opt,name=session1,proto3" json:"session1,omitempty"` + Session2 *SessionInfo `protobuf:"bytes,2,opt,name=session2,proto3" json:"session2,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaIsSameRMRequest) Reset() { + *x = XaIsSameRMRequest{} + mi := &file_StatementService_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaIsSameRMRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaIsSameRMRequest) ProtoMessage() {} + +func (x *XaIsSameRMRequest) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[37] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaIsSameRMRequest.ProtoReflect.Descriptor instead. +func (*XaIsSameRMRequest) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{37} +} + +func (x *XaIsSameRMRequest) GetSession1() *SessionInfo { + if x != nil { + return x.Session1 + } + return nil +} + +func (x *XaIsSameRMRequest) GetSession2() *SessionInfo { + if x != nil { + return x.Session2 + } + return nil +} + +// Response for isSameRM check +type XaIsSameRMResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + IsSame bool `protobuf:"varint,1,opt,name=isSame,proto3" json:"isSame,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaIsSameRMResponse) Reset() { + *x = XaIsSameRMResponse{} + mi := &file_StatementService_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaIsSameRMResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaIsSameRMResponse) ProtoMessage() {} + +func (x *XaIsSameRMResponse) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaIsSameRMResponse.ProtoReflect.Descriptor instead. +func (*XaIsSameRMResponse) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{38} +} + +func (x *XaIsSameRMResponse) GetIsSame() bool { + if x != nil { + return x.IsSame + } + return false +} + +// Generic XA response for operations that don't return specific data +type XaResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Session *SessionInfo `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *XaResponse) Reset() { + *x = XaResponse{} + mi := &file_StatementService_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *XaResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*XaResponse) ProtoMessage() {} + +func (x *XaResponse) ProtoReflect() protoreflect.Message { + mi := &file_StatementService_proto_msgTypes[39] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use XaResponse.ProtoReflect.Descriptor instead. +func (*XaResponse) Descriptor() ([]byte, []int) { + return file_StatementService_proto_rawDescGZIP(), []int{39} +} + +func (x *XaResponse) GetSession() *SessionInfo { + if x != nil { + return x.Session + } + return nil +} + +func (x *XaResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *XaResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_StatementService_proto protoreflect.FileDescriptor + +const file_StatementService_proto_rawDesc = "" + + "\n" + + "\x16StatementService.proto\x12\x13com.openjproxy.grpc\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x16google/type/date.proto\x1a\x1bgoogle/type/timeofday.proto\"\x9d\x02\n" + + "\x11ConnectionDetails\x12\x10\n" + + "\x03url\x18\x01 \x01(\tR\x03url\x12\x12\n" + + "\x04user\x18\x02 \x01(\tR\x04user\x12\x1a\n" + + "\bpassword\x18\x03 \x01(\tR\bpassword\x12\x1e\n" + + "\n" + + "clientUUID\x18\x04 \x01(\tR\n" + + "clientUUID\x12B\n" + + "\n" + + "properties\x18\x06 \x03(\v2\".com.openjproxy.grpc.PropertyEntryR\n" + + "properties\x12\x12\n" + + "\x04isXA\x18\a \x01(\bR\x04isXA\x12(\n" + + "\x0fserverEndpoints\x18\b \x03(\tR\x0fserverEndpoints\x12$\n" + + "\rclusterHealth\x18\t \x01(\tR\rclusterHealth\"\xad\x01\n" + + "\x11TimestampWithZone\x124\n" + + "\ainstant\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\ainstant\x12\x1a\n" + + "\btimezone\x18\x02 \x01(\tR\btimezone\x12F\n" + + "\roriginal_type\x18\x03 \x01(\x0e2!.com.openjproxy.grpc.TemporalTypeR\foriginalType\"\xa5\b\n" + + "\x0eParameterValue\x12\x1f\n" + + "\n" + + "bool_value\x18\x01 \x01(\bH\x00R\tboolValue\x12\x1d\n" + + "\tint_value\x18\x02 \x01(\x05H\x00R\bintValue\x12\x1f\n" + + "\n" + + "long_value\x18\x03 \x01(\x03H\x00R\tlongValue\x12!\n" + + "\vfloat_value\x18\x04 \x01(\x02H\x00R\n" + + "floatValue\x12#\n" + + "\fdouble_value\x18\x05 \x01(\x01H\x00R\vdoubleValue\x12#\n" + + "\fstring_value\x18\x06 \x01(\tH\x00R\vstringValue\x12!\n" + + "\vbytes_value\x18\a \x01(\fH\x00R\n" + + "bytesValue\x12G\n" + + "\x0fint_array_value\x18\b \x01(\v2\x1d.com.openjproxy.grpc.IntArrayH\x00R\rintArrayValue\x12J\n" + + "\x10long_array_value\x18\t \x01(\v2\x1e.com.openjproxy.grpc.LongArrayH\x00R\x0elongArrayValue\x12\x19\n" + + "\ais_null\x18\n" + + " \x01(\bH\x00R\x06isNull\x12Q\n" + + "\x0ftimestamp_value\x18\v \x01(\v2&.com.openjproxy.grpc.TimestampWithZoneH\x00R\x0etimestampValue\x122\n" + + "\n" + + "date_value\x18\f \x01(\v2\x11.google.type.DateH\x00R\tdateValue\x127\n" + + "\n" + + "time_value\x18\r \x01(\v2\x16.google.type.TimeOfDayH\x00R\ttimeValue\x12;\n" + + "\turl_value\x18\x0e \x01(\v2\x1c.google.protobuf.StringValueH\x00R\burlValue\x12?\n" + + "\vrowid_value\x18\x0f \x01(\v2\x1c.google.protobuf.StringValueH\x00R\n" + + "rowidValue\x12=\n" + + "\n" + + "uuid_value\x18\x10 \x01(\v2\x1c.google.protobuf.StringValueH\x00R\tuuidValue\x12I\n" + + "\x10biginteger_value\x18\x11 \x01(\v2\x1c.google.protobuf.StringValueH\x00R\x0fbigintegerValue\x12P\n" + + "\x12string_array_value\x18\x12 \x01(\v2 .com.openjproxy.grpc.StringArrayH\x00R\x10stringArrayValue\x12O\n" + + "\x13rowidlifetime_value\x18\x13 \x01(\v2\x1c.google.protobuf.StringValueH\x00R\x12rowidlifetimeValueB\a\n" + + "\x05value\"\"\n" + + "\bIntArray\x12\x16\n" + + "\x06values\x18\x01 \x03(\x05R\x06values\"#\n" + + "\tLongArray\x12\x16\n" + + "\x06values\x18\x01 \x03(\x03R\x06values\"%\n" + + "\vStringArray\x12\x16\n" + + "\x06values\x18\x01 \x03(\tR\x06values\"\xa0\x01\n" + + "\x0eParameterProto\x12\x14\n" + + "\x05index\x18\x01 \x01(\x05R\x05index\x12;\n" + + "\x04type\x18\x02 \x01(\x0e2'.com.openjproxy.grpc.ParameterTypeProtoR\x04type\x12;\n" + + "\x06values\x18\x03 \x03(\v2#.com.openjproxy.grpc.ParameterValueR\x06values\"\x9b\x02\n" + + "\rPropertyEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x1f\n" + + "\n" + + "bool_value\x18\x02 \x01(\bH\x00R\tboolValue\x12\x1d\n" + + "\tint_value\x18\x03 \x01(\x05H\x00R\bintValue\x12\x1f\n" + + "\n" + + "long_value\x18\x04 \x01(\x03H\x00R\tlongValue\x12!\n" + + "\vfloat_value\x18\x05 \x01(\x02H\x00R\n" + + "floatValue\x12#\n" + + "\fdouble_value\x18\x06 \x01(\x01H\x00R\vdoubleValue\x12#\n" + + "\fstring_value\x18\a \x01(\tH\x00R\vstringValue\x12!\n" + + "\vbytes_value\x18\b \x01(\fH\x00R\n" + + "bytesValueB\a\n" + + "\x05value\"J\n" + + "\tResultRow\x12=\n" + + "\acolumns\x18\x01 \x03(\v2#.com.openjproxy.grpc.ParameterValueR\acolumns\"\x86\x01\n" + + "\x12OpQueryResultProto\x12$\n" + + "\rresultSetUUID\x18\x01 \x01(\tR\rresultSetUUID\x12\x16\n" + + "\x06labels\x18\x02 \x03(\tR\x06labels\x122\n" + + "\x04rows\x18\x03 \x03(\v2\x1e.com.openjproxy.grpc.ResultRowR\x04rows\"\x91\x01\n" + + "\x0fTransactionInfo\x12(\n" + + "\x0ftransactionUUID\x18\x01 \x01(\tR\x0ftransactionUUID\x12T\n" + + "\x11transactionStatus\x18\x02 \x01(\x0e2&.com.openjproxy.grpc.TransactionStatusR\x11transactionStatus\"\xe3\x02\n" + + "\vSessionInfo\x12\x1a\n" + + "\bconnHash\x18\x01 \x01(\tR\bconnHash\x12\x1e\n" + + "\n" + + "clientUUID\x18\x02 \x01(\tR\n" + + "clientUUID\x12 \n" + + "\vsessionUUID\x18\x03 \x01(\tR\vsessionUUID\x12N\n" + + "\x0ftransactionInfo\x18\x04 \x01(\v2$.com.openjproxy.grpc.TransactionInfoR\x0ftransactionInfo\x12H\n" + + "\rsessionStatus\x18\x05 \x01(\x0e2\".com.openjproxy.grpc.SessionStatusR\rsessionStatus\x12\x12\n" + + "\x04isXA\x18\x06 \x01(\bR\x04isXA\x12\"\n" + + "\ftargetServer\x18\a \x01(\tR\ftargetServer\x12$\n" + + "\rclusterHealth\x18\b \x01(\tR\rclusterHealth\"\xbb\x02\n" + + "\bOpResult\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x123\n" + + "\x04type\x18\x02 \x01(\x0e2\x1f.com.openjproxy.grpc.ResultTypeR\x04type\x12\x1d\n" + + "\tint_value\x18\x03 \x01(\x05H\x00R\bintValue\x12L\n" + + "\fquery_result\x18\x04 \x01(\v2'.com.openjproxy.grpc.OpQueryResultProtoH\x00R\vqueryResult\x12\x1f\n" + + "\n" + + "uuid_value\x18\x05 \x01(\tH\x00R\tuuidValue\x12\x12\n" + + "\x04uuid\x18\x06 \x01(\tR\x04uuid\x12\x12\n" + + "\x04flag\x18\a \x01(\tR\x04flagB\b\n" + + "\x06result\"\x8f\x02\n" + + "\x10StatementRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x10\n" + + "\x03sql\x18\x02 \x01(\tR\x03sql\x12C\n" + + "\n" + + "parameters\x18\x03 \x03(\v2#.com.openjproxy.grpc.ParameterProtoR\n" + + "parameters\x12$\n" + + "\rstatementUUID\x18\x04 \x01(\tR\rstatementUUID\x12B\n" + + "\n" + + "properties\x18\x05 \x03(\v2\".com.openjproxy.grpc.PropertyEntryR\n" + + "properties\"\xad\x01\n" + + "\x10SqlErrorResponse\x12\x16\n" + + "\x06reason\x18\x01 \x01(\tR\x06reason\x12\x1a\n" + + "\bsqlState\x18\x02 \x01(\tR\bsqlState\x12\x1e\n" + + "\n" + + "vendorCode\x18\x03 \x01(\x05R\n" + + "vendorCode\x12E\n" + + "\fsqlErrorType\x18\x04 \x01(\x0e2!.com.openjproxy.grpc.SqlErrorTypeR\fsqlErrorType\"\xf8\x01\n" + + "\fLobReference\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x12\n" + + "\x04uuid\x18\x02 \x01(\tR\x04uuid\x12\"\n" + + "\fbytesWritten\x18\x03 \x01(\x05R\fbytesWritten\x126\n" + + "\alobType\x18\x04 \x01(\x0e2\x1c.com.openjproxy.grpc.LobTypeR\alobType\x12 \n" + + "\vcolumnIndex\x18\x05 \x01(\x05R\vcolumnIndex\x12\x1a\n" + + "\bstmtUUID\x18\x06 \x01(\tR\bstmtUUID\"\x8b\x01\n" + + "\x0eReadLobRequest\x12E\n" + + "\flobReference\x18\x01 \x01(\v2!.com.openjproxy.grpc.LobReferenceR\flobReference\x12\x1a\n" + + "\bposition\x18\x02 \x01(\x03R\bposition\x12\x16\n" + + "\x06length\x18\x03 \x01(\x05R\x06length\"\xf2\x01\n" + + "\fLobDataBlock\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x1a\n" + + "\bposition\x18\x02 \x01(\x03R\bposition\x12\x12\n" + + "\x04data\x18\x03 \x01(\fR\x04data\x126\n" + + "\alobType\x18\x04 \x01(\x0e2\x1c.com.openjproxy.grpc.LobTypeR\alobType\x12>\n" + + "\bmetadata\x18\x05 \x03(\v2\".com.openjproxy.grpc.PropertyEntryR\bmetadata\":\n" + + "\x18SessionTerminationStatus\x12\x1e\n" + + "\n" + + "terminated\x18\x01 \x01(\bR\n" + + "terminated\"\xe5\x01\n" + + "\n" + + "TargetCall\x129\n" + + "\bcallType\x18\x01 \x01(\x0e2\x1d.com.openjproxy.grpc.CallTypeR\bcallType\x12\"\n" + + "\fresourceName\x18\x02 \x01(\tR\fresourceName\x12;\n" + + "\x06params\x18\x03 \x03(\v2#.com.openjproxy.grpc.ParameterValueR\x06params\x12;\n" + + "\bnextCall\x18\x04 \x01(\v2\x1f.com.openjproxy.grpc.TargetCallR\bnextCall\"\xb9\x02\n" + + "\x13CallResourceRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12E\n" + + "\fresourceType\x18\x02 \x01(\x0e2!.com.openjproxy.grpc.ResourceTypeR\fresourceType\x12\"\n" + + "\fresourceUUID\x18\x03 \x01(\tR\fresourceUUID\x127\n" + + "\x06target\x18\x04 \x01(\v2\x1f.com.openjproxy.grpc.TargetCallR\x06target\x12B\n" + + "\n" + + "properties\x18\x05 \x03(\v2\".com.openjproxy.grpc.PropertyEntryR\n" + + "properties\"\xb3\x01\n" + + "\x14CallResourceResponse\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\"\n" + + "\fresourceUUID\x18\x02 \x01(\tR\fresourceUUID\x12;\n" + + "\x06values\x18\x03 \x03(\v2#.com.openjproxy.grpc.ParameterValueR\x06values\"\x8d\x01\n" + + "\x15ResultSetFetchRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12$\n" + + "\rresultSetUUID\x18\x02 \x01(\tR\rresultSetUUID\x12\x12\n" + + "\x04size\x18\x03 \x01(\x05R\x04size\"\x82\x01\n" + + "\bXidProto\x12\x1a\n" + + "\bformatId\x18\x01 \x01(\x05R\bformatId\x120\n" + + "\x13globalTransactionId\x18\x02 \x01(\fR\x13globalTransactionId\x12(\n" + + "\x0fbranchQualifier\x18\x03 \x01(\fR\x0fbranchQualifier\"\x93\x01\n" + + "\x0eXaStartRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12/\n" + + "\x03xid\x18\x02 \x01(\v2\x1d.com.openjproxy.grpc.XidProtoR\x03xid\x12\x14\n" + + "\x05flags\x18\x03 \x01(\x05R\x05flags\"\x91\x01\n" + + "\fXaEndRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12/\n" + + "\x03xid\x18\x02 \x01(\v2\x1d.com.openjproxy.grpc.XidProtoR\x03xid\x12\x14\n" + + "\x05flags\x18\x03 \x01(\x05R\x05flags\"\x7f\n" + + "\x10XaPrepareRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12/\n" + + "\x03xid\x18\x02 \x01(\v2\x1d.com.openjproxy.grpc.XidProtoR\x03xid\"g\n" + + "\x11XaPrepareResponse\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x16\n" + + "\x06result\x18\x02 \x01(\x05R\x06result\"\x9a\x01\n" + + "\x0fXaCommitRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12/\n" + + "\x03xid\x18\x02 \x01(\v2\x1d.com.openjproxy.grpc.XidProtoR\x03xid\x12\x1a\n" + + "\bonePhase\x18\x03 \x01(\bR\bonePhase\"\x80\x01\n" + + "\x11XaRollbackRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12/\n" + + "\x03xid\x18\x02 \x01(\v2\x1d.com.openjproxy.grpc.XidProtoR\x03xid\"b\n" + + "\x10XaRecoverRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x12\n" + + "\x04flag\x18\x02 \x01(\x05R\x04flag\"\x82\x01\n" + + "\x11XaRecoverResponse\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x121\n" + + "\x04xids\x18\x02 \x03(\v2\x1d.com.openjproxy.grpc.XidProtoR\x04xids\"~\n" + + "\x0fXaForgetRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12/\n" + + "\x03xid\x18\x02 \x01(\v2\x1d.com.openjproxy.grpc.XidProtoR\x03xid\"v\n" + + "\x1eXaSetTransactionTimeoutRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x18\n" + + "\aseconds\x18\x02 \x01(\x05R\aseconds\"w\n" + + "\x1fXaSetTransactionTimeoutResponse\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x18\n" + + "\asuccess\x18\x02 \x01(\bR\asuccess\"\\\n" + + "\x1eXaGetTransactionTimeoutRequest\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\"w\n" + + "\x1fXaGetTransactionTimeoutResponse\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x18\n" + + "\aseconds\x18\x02 \x01(\x05R\aseconds\"\x8f\x01\n" + + "\x11XaIsSameRMRequest\x12<\n" + + "\bsession1\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\bsession1\x12<\n" + + "\bsession2\x18\x02 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\bsession2\",\n" + + "\x12XaIsSameRMResponse\x12\x16\n" + + "\x06isSame\x18\x01 \x01(\bR\x06isSame\"|\n" + + "\n" + + "XaResponse\x12:\n" + + "\asession\x18\x01 \x01(\v2 .com.openjproxy.grpc.SessionInfoR\asession\x12\x18\n" + + "\asuccess\x18\x02 \x01(\bR\asuccess\x12\x18\n" + + "\amessage\x18\x03 \x01(\tR\amessage*\xe3\x03\n" + + "\x12ParameterTypeProto\x12\v\n" + + "\aPT_NULL\x10\x00\x12\x0e\n" + + "\n" + + "PT_BOOLEAN\x10\x01\x12\v\n" + + "\aPT_BYTE\x10\x02\x12\f\n" + + "\bPT_SHORT\x10\x03\x12\n" + + "\n" + + "\x06PT_INT\x10\x04\x12\v\n" + + "\aPT_LONG\x10\x05\x12\f\n" + + "\bPT_FLOAT\x10\x06\x12\r\n" + + "\tPT_DOUBLE\x10\a\x12\x12\n" + + "\x0ePT_BIG_DECIMAL\x10\b\x12\r\n" + + "\tPT_STRING\x10\t\x12\f\n" + + "\bPT_BYTES\x10\n" + + "\x12\v\n" + + "\aPT_DATE\x10\v\x12\v\n" + + "\aPT_TIME\x10\f\x12\x10\n" + + "\fPT_TIMESTAMP\x10\r\x12\x13\n" + + "\x0fPT_ASCII_STREAM\x10\x0e\x12\x15\n" + + "\x11PT_UNICODE_STREAM\x10\x0f\x12\x14\n" + + "\x10PT_BINARY_STREAM\x10\x10\x12\r\n" + + "\tPT_OBJECT\x10\x11\x12\x17\n" + + "\x13PT_CHARACTER_READER\x10\x12\x12\n" + + "\n" + + "\x06PT_REF\x10\x13\x12\v\n" + + "\aPT_BLOB\x10\x14\x12\v\n" + + "\aPT_CLOB\x10\x15\x12\f\n" + + "\bPT_ARRAY\x10\x16\x12\n" + + "\n" + + "\x06PT_URL\x10\x17\x12\r\n" + + "\tPT_ROW_ID\x10\x18\x12\x0f\n" + + "\vPT_N_STRING\x10\x19\x12\x19\n" + + "\x15PT_N_CHARACTER_STREAM\x10\x1a\x12\r\n" + + "\tPT_N_CLOB\x10\x1b\x12\x0e\n" + + "\n" + + "PT_SQL_XML\x10\x1c*\xa3\x02\n" + + "\fTemporalType\x12\x1d\n" + + "\x19TEMPORAL_TYPE_UNSPECIFIED\x10\x00\x12\x1b\n" + + "\x17TEMPORAL_TYPE_TIMESTAMP\x10\x01\x12\x1a\n" + + "\x16TEMPORAL_TYPE_CALENDAR\x10\x02\x12\"\n" + + "\x1eTEMPORAL_TYPE_OFFSET_DATE_TIME\x10\x03\x12!\n" + + "\x1dTEMPORAL_TYPE_LOCAL_DATE_TIME\x10\x04\x12\x19\n" + + "\x15TEMPORAL_TYPE_INSTANT\x10\x05\x12\x1c\n" + + "\x18TEMPORAL_TYPE_LOCAL_DATE\x10\x06\x12\x1c\n" + + "\x18TEMPORAL_TYPE_LOCAL_TIME\x10\a\x12\x1d\n" + + "\x19TEMPORAL_TYPE_OFFSET_TIME\x10\b*i\n" + + "\x06DbName\x12\x06\n" + + "\x02H2\x10\x00\x12\t\n" + + "\x05MYSQL\x10\x01\x12\v\n" + + "\aMARIADB\x10\x02\x12\f\n" + + "\bPOSTGRES\x10\x03\x12\n" + + "\n" + + "\x06ORACLE\x10\x04\x12\x0e\n" + + "\n" + + "SQL_SERVER\x10\x05\x12\a\n" + + "\x03DB2\x10\x06\x12\f\n" + + "\bUNMAPPED\x10\a*;\n" + + "\rSessionStatus\x12\x12\n" + + "\x0eSESSION_ACTIVE\x10\x00\x12\x16\n" + + "\x12SESSION_TERMINATED\x10\x01*G\n" + + "\x11TransactionStatus\x12\x0e\n" + + "\n" + + "TRX_ACTIVE\x10\x00\x12\x10\n" + + "\fTRX_COMMITED\x10\x01\x12\x10\n" + + "\fTRX_ROLLBACK\x10\x02*?\n" + + "\n" + + "ResultType\x12\v\n" + + "\aINTEGER\x10\x00\x12\x13\n" + + "\x0fRESULT_SET_DATA\x10\x01\x12\x0f\n" + + "\vUUID_STRING\x10\x02*9\n" + + "\fSqlErrorType\x12\x11\n" + + "\rSQL_EXCEPTION\x10\x00\x12\x16\n" + + "\x12SQL_DATA_EXCEPTION\x10\x01*~\n" + + "\aLobType\x12\v\n" + + "\aLT_BLOB\x10\x00\x12\v\n" + + "\aLT_CLOB\x10\x01\x12\x14\n" + + "\x10LT_BINARY_STREAM\x10\x02\x12\x13\n" + + "\x0fLT_ASCII_STREAM\x10\x03\x12\x15\n" + + "\x11LT_UNICODE_STREAM\x10\x04\x12\x17\n" + + "\x13LT_CHARACTER_STREAM\x10\x05*\xa1\x01\n" + + "\fResourceType\x12\x12\n" + + "\x0eRES_RESULT_SET\x10\x00\x12\x11\n" + + "\rRES_STATEMENT\x10\x01\x12\x1a\n" + + "\x16RES_PREPARED_STATEMENT\x10\x02\x12\x1a\n" + + "\x16RES_CALLABLE_STATEMENT\x10\x03\x12\v\n" + + "\aRES_LOB\x10\x04\x12\x12\n" + + "\x0eRES_CONNECTION\x10\x05\x12\x11\n" + + "\rRES_SAVEPOINT\x10\x06*\xa2\x06\n" + + "\bCallType\x12\f\n" + + "\bCALL_SET\x10\x00\x12\f\n" + + "\bCALL_GET\x10\x01\x12\v\n" + + "\aCALL_IS\x10\x02\x12\f\n" + + "\bCALL_ALL\x10\x03\x12\x0e\n" + + "\n" + + "CALL_NULLS\x10\x04\x12\r\n" + + "\tCALL_USES\x10\x05\x12\x11\n" + + "\rCALL_SUPPORTS\x10\x06\x12\x0f\n" + + "\vCALL_STORES\x10\a\x12\r\n" + + "\tCALL_NULL\x10\b\x12\r\n" + + "\tCALL_DOES\x10\t\x12\r\n" + + "\tCALL_DATA\x10\n" + + "\x12\r\n" + + "\tCALL_NEXT\x10\v\x12\x0e\n" + + "\n" + + "CALL_CLOSE\x10\f\x12\f\n" + + "\bCALL_WAS\x10\r\x12\x0e\n" + + "\n" + + "CALL_CLEAR\x10\x0e\x12\r\n" + + "\tCALL_FIND\x10\x0f\x12\x0f\n" + + "\vCALL_BEFORE\x10\x10\x12\x0e\n" + + "\n" + + "CALL_AFTER\x10\x11\x12\x0e\n" + + "\n" + + "CALL_FIRST\x10\x12\x12\r\n" + + "\tCALL_LAST\x10\x13\x12\x11\n" + + "\rCALL_ABSOLUTE\x10\x14\x12\x11\n" + + "\rCALL_RELATIVE\x10\x15\x12\x11\n" + + "\rCALL_PREVIOUS\x10\x16\x12\f\n" + + "\bCALL_ROW\x10\x17\x12\x0f\n" + + "\vCALL_UPDATE\x10\x18\x12\x0f\n" + + "\vCALL_INSERT\x10\x19\x12\x0f\n" + + "\vCALL_DELETE\x10\x1a\x12\x10\n" + + "\fCALL_REFRESH\x10\x1b\x12\x0f\n" + + "\vCALL_CANCEL\x10\x1c\x12\r\n" + + "\tCALL_MOVE\x10\x1d\x12\f\n" + + "\bCALL_OWN\x10\x1e\x12\x0f\n" + + "\vCALL_OTHERS\x10\x1f\x12\x10\n" + + "\fCALL_UPDATES\x10 \x12\x10\n" + + "\fCALL_DELETES\x10!\x12\x10\n" + + "\fCALL_INSERTS\x10\"\x12\x11\n" + + "\rCALL_LOCATORS\x10#\x12\r\n" + + "\tCALL_AUTO\x10$\x12\x12\n" + + "\x0eCALL_GENERATED\x10%\x12\x10\n" + + "\fCALL_RELEASE\x10&\x12\x0f\n" + + "\vCALL_NATIVE\x10'\x12\x10\n" + + "\fCALL_PREPARE\x10(\x12\x11\n" + + "\rCALL_ROLLBACK\x10)\x12\x0e\n" + + "\n" + + "CALL_ABORT\x10*\x12\x10\n" + + "\fCALL_EXECUTE\x10+\x12\f\n" + + "\bCALL_ADD\x10,\x12\x10\n" + + "\fCALL_ENQUOTE\x10-\x12\x11\n" + + "\rCALL_REGISTER\x10.\x12\x0f\n" + + "\vCALL_LENGTH\x10/2\xb4\x0f\n" + + "\x10StatementService\x12S\n" + + "\aconnect\x12&.com.openjproxy.grpc.ConnectionDetails\x1a .com.openjproxy.grpc.SessionInfo\x12U\n" + + "\rexecuteUpdate\x12%.com.openjproxy.grpc.StatementRequest\x1a\x1d.com.openjproxy.grpc.OpResult\x12V\n" + + "\fexecuteQuery\x12%.com.openjproxy.grpc.StatementRequest\x1a\x1d.com.openjproxy.grpc.OpResult0\x01\x12Z\n" + + "\rfetchNextRows\x12*.com.openjproxy.grpc.ResultSetFetchRequest\x1a\x1d.com.openjproxy.grpc.OpResult\x12U\n" + + "\tcreateLob\x12!.com.openjproxy.grpc.LobDataBlock\x1a!.com.openjproxy.grpc.LobReference(\x010\x01\x12S\n" + + "\areadLob\x12#.com.openjproxy.grpc.ReadLobRequest\x1a!.com.openjproxy.grpc.LobDataBlock0\x01\x12c\n" + + "\x10terminateSession\x12 .com.openjproxy.grpc.SessionInfo\x1a-.com.openjproxy.grpc.SessionTerminationStatus\x12V\n" + + "\x10startTransaction\x12 .com.openjproxy.grpc.SessionInfo\x1a .com.openjproxy.grpc.SessionInfo\x12W\n" + + "\x11commitTransaction\x12 .com.openjproxy.grpc.SessionInfo\x1a .com.openjproxy.grpc.SessionInfo\x12Y\n" + + "\x13rollbackTransaction\x12 .com.openjproxy.grpc.SessionInfo\x1a .com.openjproxy.grpc.SessionInfo\x12c\n" + + "\fcallResource\x12(.com.openjproxy.grpc.CallResourceRequest\x1a).com.openjproxy.grpc.CallResourceResponse\x12O\n" + + "\axaStart\x12#.com.openjproxy.grpc.XaStartRequest\x1a\x1f.com.openjproxy.grpc.XaResponse\x12K\n" + + "\x05xaEnd\x12!.com.openjproxy.grpc.XaEndRequest\x1a\x1f.com.openjproxy.grpc.XaResponse\x12Z\n" + + "\txaPrepare\x12%.com.openjproxy.grpc.XaPrepareRequest\x1a&.com.openjproxy.grpc.XaPrepareResponse\x12Q\n" + + "\bxaCommit\x12$.com.openjproxy.grpc.XaCommitRequest\x1a\x1f.com.openjproxy.grpc.XaResponse\x12U\n" + + "\n" + + "xaRollback\x12&.com.openjproxy.grpc.XaRollbackRequest\x1a\x1f.com.openjproxy.grpc.XaResponse\x12Z\n" + + "\txaRecover\x12%.com.openjproxy.grpc.XaRecoverRequest\x1a&.com.openjproxy.grpc.XaRecoverResponse\x12Q\n" + + "\bxaForget\x12$.com.openjproxy.grpc.XaForgetRequest\x1a\x1f.com.openjproxy.grpc.XaResponse\x12\x84\x01\n" + + "\x17xaSetTransactionTimeout\x123.com.openjproxy.grpc.XaSetTransactionTimeoutRequest\x1a4.com.openjproxy.grpc.XaSetTransactionTimeoutResponse\x12\x84\x01\n" + + "\x17xaGetTransactionTimeout\x123.com.openjproxy.grpc.XaGetTransactionTimeoutRequest\x1a4.com.openjproxy.grpc.XaGetTransactionTimeoutResponse\x12]\n" + + "\n" + + "xaIsSameRM\x12&.com.openjproxy.grpc.XaIsSameRMRequest\x1a'.com.openjproxy.grpc.XaIsSameRMResponseB\x02P\x01b\x06proto3" + +var ( + file_StatementService_proto_rawDescOnce sync.Once + file_StatementService_proto_rawDescData []byte +) + +func file_StatementService_proto_rawDescGZIP() []byte { + file_StatementService_proto_rawDescOnce.Do(func() { + file_StatementService_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_StatementService_proto_rawDesc), len(file_StatementService_proto_rawDesc))) + }) + return file_StatementService_proto_rawDescData +} + +var file_StatementService_proto_enumTypes = make([]protoimpl.EnumInfo, 10) +var file_StatementService_proto_msgTypes = make([]protoimpl.MessageInfo, 40) +var file_StatementService_proto_goTypes = []any{ + (ParameterTypeProto)(0), // 0: com.openjproxy.grpc.ParameterTypeProto + (TemporalType)(0), // 1: com.openjproxy.grpc.TemporalType + (DbName)(0), // 2: com.openjproxy.grpc.DbName + (SessionStatus)(0), // 3: com.openjproxy.grpc.SessionStatus + (TransactionStatus)(0), // 4: com.openjproxy.grpc.TransactionStatus + (ResultType)(0), // 5: com.openjproxy.grpc.ResultType + (SqlErrorType)(0), // 6: com.openjproxy.grpc.SqlErrorType + (LobType)(0), // 7: com.openjproxy.grpc.LobType + (ResourceType)(0), // 8: com.openjproxy.grpc.ResourceType + (CallType)(0), // 9: com.openjproxy.grpc.CallType + (*ConnectionDetails)(nil), // 10: com.openjproxy.grpc.ConnectionDetails + (*TimestampWithZone)(nil), // 11: com.openjproxy.grpc.TimestampWithZone + (*ParameterValue)(nil), // 12: com.openjproxy.grpc.ParameterValue + (*IntArray)(nil), // 13: com.openjproxy.grpc.IntArray + (*LongArray)(nil), // 14: com.openjproxy.grpc.LongArray + (*StringArray)(nil), // 15: com.openjproxy.grpc.StringArray + (*ParameterProto)(nil), // 16: com.openjproxy.grpc.ParameterProto + (*PropertyEntry)(nil), // 17: com.openjproxy.grpc.PropertyEntry + (*ResultRow)(nil), // 18: com.openjproxy.grpc.ResultRow + (*OpQueryResultProto)(nil), // 19: com.openjproxy.grpc.OpQueryResultProto + (*TransactionInfo)(nil), // 20: com.openjproxy.grpc.TransactionInfo + (*SessionInfo)(nil), // 21: com.openjproxy.grpc.SessionInfo + (*OpResult)(nil), // 22: com.openjproxy.grpc.OpResult + (*StatementRequest)(nil), // 23: com.openjproxy.grpc.StatementRequest + (*SqlErrorResponse)(nil), // 24: com.openjproxy.grpc.SqlErrorResponse + (*LobReference)(nil), // 25: com.openjproxy.grpc.LobReference + (*ReadLobRequest)(nil), // 26: com.openjproxy.grpc.ReadLobRequest + (*LobDataBlock)(nil), // 27: com.openjproxy.grpc.LobDataBlock + (*SessionTerminationStatus)(nil), // 28: com.openjproxy.grpc.SessionTerminationStatus + (*TargetCall)(nil), // 29: com.openjproxy.grpc.TargetCall + (*CallResourceRequest)(nil), // 30: com.openjproxy.grpc.CallResourceRequest + (*CallResourceResponse)(nil), // 31: com.openjproxy.grpc.CallResourceResponse + (*ResultSetFetchRequest)(nil), // 32: com.openjproxy.grpc.ResultSetFetchRequest + (*XidProto)(nil), // 33: com.openjproxy.grpc.XidProto + (*XaStartRequest)(nil), // 34: com.openjproxy.grpc.XaStartRequest + (*XaEndRequest)(nil), // 35: com.openjproxy.grpc.XaEndRequest + (*XaPrepareRequest)(nil), // 36: com.openjproxy.grpc.XaPrepareRequest + (*XaPrepareResponse)(nil), // 37: com.openjproxy.grpc.XaPrepareResponse + (*XaCommitRequest)(nil), // 38: com.openjproxy.grpc.XaCommitRequest + (*XaRollbackRequest)(nil), // 39: com.openjproxy.grpc.XaRollbackRequest + (*XaRecoverRequest)(nil), // 40: com.openjproxy.grpc.XaRecoverRequest + (*XaRecoverResponse)(nil), // 41: com.openjproxy.grpc.XaRecoverResponse + (*XaForgetRequest)(nil), // 42: com.openjproxy.grpc.XaForgetRequest + (*XaSetTransactionTimeoutRequest)(nil), // 43: com.openjproxy.grpc.XaSetTransactionTimeoutRequest + (*XaSetTransactionTimeoutResponse)(nil), // 44: com.openjproxy.grpc.XaSetTransactionTimeoutResponse + (*XaGetTransactionTimeoutRequest)(nil), // 45: com.openjproxy.grpc.XaGetTransactionTimeoutRequest + (*XaGetTransactionTimeoutResponse)(nil), // 46: com.openjproxy.grpc.XaGetTransactionTimeoutResponse + (*XaIsSameRMRequest)(nil), // 47: com.openjproxy.grpc.XaIsSameRMRequest + (*XaIsSameRMResponse)(nil), // 48: com.openjproxy.grpc.XaIsSameRMResponse + (*XaResponse)(nil), // 49: com.openjproxy.grpc.XaResponse + (*timestamppb.Timestamp)(nil), // 50: google.protobuf.Timestamp + (*date.Date)(nil), // 51: google.type.Date + (*timeofday.TimeOfDay)(nil), // 52: google.type.TimeOfDay + (*wrapperspb.StringValue)(nil), // 53: google.protobuf.StringValue +} +var file_StatementService_proto_depIdxs = []int32{ + 17, // 0: com.openjproxy.grpc.ConnectionDetails.properties:type_name -> com.openjproxy.grpc.PropertyEntry + 50, // 1: com.openjproxy.grpc.TimestampWithZone.instant:type_name -> google.protobuf.Timestamp + 1, // 2: com.openjproxy.grpc.TimestampWithZone.original_type:type_name -> com.openjproxy.grpc.TemporalType + 13, // 3: com.openjproxy.grpc.ParameterValue.int_array_value:type_name -> com.openjproxy.grpc.IntArray + 14, // 4: com.openjproxy.grpc.ParameterValue.long_array_value:type_name -> com.openjproxy.grpc.LongArray + 11, // 5: com.openjproxy.grpc.ParameterValue.timestamp_value:type_name -> com.openjproxy.grpc.TimestampWithZone + 51, // 6: com.openjproxy.grpc.ParameterValue.date_value:type_name -> google.type.Date + 52, // 7: com.openjproxy.grpc.ParameterValue.time_value:type_name -> google.type.TimeOfDay + 53, // 8: com.openjproxy.grpc.ParameterValue.url_value:type_name -> google.protobuf.StringValue + 53, // 9: com.openjproxy.grpc.ParameterValue.rowid_value:type_name -> google.protobuf.StringValue + 53, // 10: com.openjproxy.grpc.ParameterValue.uuid_value:type_name -> google.protobuf.StringValue + 53, // 11: com.openjproxy.grpc.ParameterValue.biginteger_value:type_name -> google.protobuf.StringValue + 15, // 12: com.openjproxy.grpc.ParameterValue.string_array_value:type_name -> com.openjproxy.grpc.StringArray + 53, // 13: com.openjproxy.grpc.ParameterValue.rowidlifetime_value:type_name -> google.protobuf.StringValue + 0, // 14: com.openjproxy.grpc.ParameterProto.type:type_name -> com.openjproxy.grpc.ParameterTypeProto + 12, // 15: com.openjproxy.grpc.ParameterProto.values:type_name -> com.openjproxy.grpc.ParameterValue + 12, // 16: com.openjproxy.grpc.ResultRow.columns:type_name -> com.openjproxy.grpc.ParameterValue + 18, // 17: com.openjproxy.grpc.OpQueryResultProto.rows:type_name -> com.openjproxy.grpc.ResultRow + 4, // 18: com.openjproxy.grpc.TransactionInfo.transactionStatus:type_name -> com.openjproxy.grpc.TransactionStatus + 20, // 19: com.openjproxy.grpc.SessionInfo.transactionInfo:type_name -> com.openjproxy.grpc.TransactionInfo + 3, // 20: com.openjproxy.grpc.SessionInfo.sessionStatus:type_name -> com.openjproxy.grpc.SessionStatus + 21, // 21: com.openjproxy.grpc.OpResult.session:type_name -> com.openjproxy.grpc.SessionInfo + 5, // 22: com.openjproxy.grpc.OpResult.type:type_name -> com.openjproxy.grpc.ResultType + 19, // 23: com.openjproxy.grpc.OpResult.query_result:type_name -> com.openjproxy.grpc.OpQueryResultProto + 21, // 24: com.openjproxy.grpc.StatementRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 16, // 25: com.openjproxy.grpc.StatementRequest.parameters:type_name -> com.openjproxy.grpc.ParameterProto + 17, // 26: com.openjproxy.grpc.StatementRequest.properties:type_name -> com.openjproxy.grpc.PropertyEntry + 6, // 27: com.openjproxy.grpc.SqlErrorResponse.sqlErrorType:type_name -> com.openjproxy.grpc.SqlErrorType + 21, // 28: com.openjproxy.grpc.LobReference.session:type_name -> com.openjproxy.grpc.SessionInfo + 7, // 29: com.openjproxy.grpc.LobReference.lobType:type_name -> com.openjproxy.grpc.LobType + 25, // 30: com.openjproxy.grpc.ReadLobRequest.lobReference:type_name -> com.openjproxy.grpc.LobReference + 21, // 31: com.openjproxy.grpc.LobDataBlock.session:type_name -> com.openjproxy.grpc.SessionInfo + 7, // 32: com.openjproxy.grpc.LobDataBlock.lobType:type_name -> com.openjproxy.grpc.LobType + 17, // 33: com.openjproxy.grpc.LobDataBlock.metadata:type_name -> com.openjproxy.grpc.PropertyEntry + 9, // 34: com.openjproxy.grpc.TargetCall.callType:type_name -> com.openjproxy.grpc.CallType + 12, // 35: com.openjproxy.grpc.TargetCall.params:type_name -> com.openjproxy.grpc.ParameterValue + 29, // 36: com.openjproxy.grpc.TargetCall.nextCall:type_name -> com.openjproxy.grpc.TargetCall + 21, // 37: com.openjproxy.grpc.CallResourceRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 8, // 38: com.openjproxy.grpc.CallResourceRequest.resourceType:type_name -> com.openjproxy.grpc.ResourceType + 29, // 39: com.openjproxy.grpc.CallResourceRequest.target:type_name -> com.openjproxy.grpc.TargetCall + 17, // 40: com.openjproxy.grpc.CallResourceRequest.properties:type_name -> com.openjproxy.grpc.PropertyEntry + 21, // 41: com.openjproxy.grpc.CallResourceResponse.session:type_name -> com.openjproxy.grpc.SessionInfo + 12, // 42: com.openjproxy.grpc.CallResourceResponse.values:type_name -> com.openjproxy.grpc.ParameterValue + 21, // 43: com.openjproxy.grpc.ResultSetFetchRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 44: com.openjproxy.grpc.XaStartRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 33, // 45: com.openjproxy.grpc.XaStartRequest.xid:type_name -> com.openjproxy.grpc.XidProto + 21, // 46: com.openjproxy.grpc.XaEndRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 33, // 47: com.openjproxy.grpc.XaEndRequest.xid:type_name -> com.openjproxy.grpc.XidProto + 21, // 48: com.openjproxy.grpc.XaPrepareRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 33, // 49: com.openjproxy.grpc.XaPrepareRequest.xid:type_name -> com.openjproxy.grpc.XidProto + 21, // 50: com.openjproxy.grpc.XaPrepareResponse.session:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 51: com.openjproxy.grpc.XaCommitRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 33, // 52: com.openjproxy.grpc.XaCommitRequest.xid:type_name -> com.openjproxy.grpc.XidProto + 21, // 53: com.openjproxy.grpc.XaRollbackRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 33, // 54: com.openjproxy.grpc.XaRollbackRequest.xid:type_name -> com.openjproxy.grpc.XidProto + 21, // 55: com.openjproxy.grpc.XaRecoverRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 56: com.openjproxy.grpc.XaRecoverResponse.session:type_name -> com.openjproxy.grpc.SessionInfo + 33, // 57: com.openjproxy.grpc.XaRecoverResponse.xids:type_name -> com.openjproxy.grpc.XidProto + 21, // 58: com.openjproxy.grpc.XaForgetRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 33, // 59: com.openjproxy.grpc.XaForgetRequest.xid:type_name -> com.openjproxy.grpc.XidProto + 21, // 60: com.openjproxy.grpc.XaSetTransactionTimeoutRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 61: com.openjproxy.grpc.XaSetTransactionTimeoutResponse.session:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 62: com.openjproxy.grpc.XaGetTransactionTimeoutRequest.session:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 63: com.openjproxy.grpc.XaGetTransactionTimeoutResponse.session:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 64: com.openjproxy.grpc.XaIsSameRMRequest.session1:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 65: com.openjproxy.grpc.XaIsSameRMRequest.session2:type_name -> com.openjproxy.grpc.SessionInfo + 21, // 66: com.openjproxy.grpc.XaResponse.session:type_name -> com.openjproxy.grpc.SessionInfo + 10, // 67: com.openjproxy.grpc.StatementService.connect:input_type -> com.openjproxy.grpc.ConnectionDetails + 23, // 68: com.openjproxy.grpc.StatementService.executeUpdate:input_type -> com.openjproxy.grpc.StatementRequest + 23, // 69: com.openjproxy.grpc.StatementService.executeQuery:input_type -> com.openjproxy.grpc.StatementRequest + 32, // 70: com.openjproxy.grpc.StatementService.fetchNextRows:input_type -> com.openjproxy.grpc.ResultSetFetchRequest + 27, // 71: com.openjproxy.grpc.StatementService.createLob:input_type -> com.openjproxy.grpc.LobDataBlock + 26, // 72: com.openjproxy.grpc.StatementService.readLob:input_type -> com.openjproxy.grpc.ReadLobRequest + 21, // 73: com.openjproxy.grpc.StatementService.terminateSession:input_type -> com.openjproxy.grpc.SessionInfo + 21, // 74: com.openjproxy.grpc.StatementService.startTransaction:input_type -> com.openjproxy.grpc.SessionInfo + 21, // 75: com.openjproxy.grpc.StatementService.commitTransaction:input_type -> com.openjproxy.grpc.SessionInfo + 21, // 76: com.openjproxy.grpc.StatementService.rollbackTransaction:input_type -> com.openjproxy.grpc.SessionInfo + 30, // 77: com.openjproxy.grpc.StatementService.callResource:input_type -> com.openjproxy.grpc.CallResourceRequest + 34, // 78: com.openjproxy.grpc.StatementService.xaStart:input_type -> com.openjproxy.grpc.XaStartRequest + 35, // 79: com.openjproxy.grpc.StatementService.xaEnd:input_type -> com.openjproxy.grpc.XaEndRequest + 36, // 80: com.openjproxy.grpc.StatementService.xaPrepare:input_type -> com.openjproxy.grpc.XaPrepareRequest + 38, // 81: com.openjproxy.grpc.StatementService.xaCommit:input_type -> com.openjproxy.grpc.XaCommitRequest + 39, // 82: com.openjproxy.grpc.StatementService.xaRollback:input_type -> com.openjproxy.grpc.XaRollbackRequest + 40, // 83: com.openjproxy.grpc.StatementService.xaRecover:input_type -> com.openjproxy.grpc.XaRecoverRequest + 42, // 84: com.openjproxy.grpc.StatementService.xaForget:input_type -> com.openjproxy.grpc.XaForgetRequest + 43, // 85: com.openjproxy.grpc.StatementService.xaSetTransactionTimeout:input_type -> com.openjproxy.grpc.XaSetTransactionTimeoutRequest + 45, // 86: com.openjproxy.grpc.StatementService.xaGetTransactionTimeout:input_type -> com.openjproxy.grpc.XaGetTransactionTimeoutRequest + 47, // 87: com.openjproxy.grpc.StatementService.xaIsSameRM:input_type -> com.openjproxy.grpc.XaIsSameRMRequest + 21, // 88: com.openjproxy.grpc.StatementService.connect:output_type -> com.openjproxy.grpc.SessionInfo + 22, // 89: com.openjproxy.grpc.StatementService.executeUpdate:output_type -> com.openjproxy.grpc.OpResult + 22, // 90: com.openjproxy.grpc.StatementService.executeQuery:output_type -> com.openjproxy.grpc.OpResult + 22, // 91: com.openjproxy.grpc.StatementService.fetchNextRows:output_type -> com.openjproxy.grpc.OpResult + 25, // 92: com.openjproxy.grpc.StatementService.createLob:output_type -> com.openjproxy.grpc.LobReference + 27, // 93: com.openjproxy.grpc.StatementService.readLob:output_type -> com.openjproxy.grpc.LobDataBlock + 28, // 94: com.openjproxy.grpc.StatementService.terminateSession:output_type -> com.openjproxy.grpc.SessionTerminationStatus + 21, // 95: com.openjproxy.grpc.StatementService.startTransaction:output_type -> com.openjproxy.grpc.SessionInfo + 21, // 96: com.openjproxy.grpc.StatementService.commitTransaction:output_type -> com.openjproxy.grpc.SessionInfo + 21, // 97: com.openjproxy.grpc.StatementService.rollbackTransaction:output_type -> com.openjproxy.grpc.SessionInfo + 31, // 98: com.openjproxy.grpc.StatementService.callResource:output_type -> com.openjproxy.grpc.CallResourceResponse + 49, // 99: com.openjproxy.grpc.StatementService.xaStart:output_type -> com.openjproxy.grpc.XaResponse + 49, // 100: com.openjproxy.grpc.StatementService.xaEnd:output_type -> com.openjproxy.grpc.XaResponse + 37, // 101: com.openjproxy.grpc.StatementService.xaPrepare:output_type -> com.openjproxy.grpc.XaPrepareResponse + 49, // 102: com.openjproxy.grpc.StatementService.xaCommit:output_type -> com.openjproxy.grpc.XaResponse + 49, // 103: com.openjproxy.grpc.StatementService.xaRollback:output_type -> com.openjproxy.grpc.XaResponse + 41, // 104: com.openjproxy.grpc.StatementService.xaRecover:output_type -> com.openjproxy.grpc.XaRecoverResponse + 49, // 105: com.openjproxy.grpc.StatementService.xaForget:output_type -> com.openjproxy.grpc.XaResponse + 44, // 106: com.openjproxy.grpc.StatementService.xaSetTransactionTimeout:output_type -> com.openjproxy.grpc.XaSetTransactionTimeoutResponse + 46, // 107: com.openjproxy.grpc.StatementService.xaGetTransactionTimeout:output_type -> com.openjproxy.grpc.XaGetTransactionTimeoutResponse + 48, // 108: com.openjproxy.grpc.StatementService.xaIsSameRM:output_type -> com.openjproxy.grpc.XaIsSameRMResponse + 88, // [88:109] is the sub-list for method output_type + 67, // [67:88] is the sub-list for method input_type + 67, // [67:67] is the sub-list for extension type_name + 67, // [67:67] is the sub-list for extension extendee + 0, // [0:67] is the sub-list for field type_name +} + +func init() { file_StatementService_proto_init() } +func file_StatementService_proto_init() { + if File_StatementService_proto != nil { + return + } + file_StatementService_proto_msgTypes[2].OneofWrappers = []any{ + (*ParameterValue_BoolValue)(nil), + (*ParameterValue_IntValue)(nil), + (*ParameterValue_LongValue)(nil), + (*ParameterValue_FloatValue)(nil), + (*ParameterValue_DoubleValue)(nil), + (*ParameterValue_StringValue)(nil), + (*ParameterValue_BytesValue)(nil), + (*ParameterValue_IntArrayValue)(nil), + (*ParameterValue_LongArrayValue)(nil), + (*ParameterValue_IsNull)(nil), + (*ParameterValue_TimestampValue)(nil), + (*ParameterValue_DateValue)(nil), + (*ParameterValue_TimeValue)(nil), + (*ParameterValue_UrlValue)(nil), + (*ParameterValue_RowidValue)(nil), + (*ParameterValue_UuidValue)(nil), + (*ParameterValue_BigintegerValue)(nil), + (*ParameterValue_StringArrayValue)(nil), + (*ParameterValue_RowidlifetimeValue)(nil), + } + file_StatementService_proto_msgTypes[7].OneofWrappers = []any{ + (*PropertyEntry_BoolValue)(nil), + (*PropertyEntry_IntValue)(nil), + (*PropertyEntry_LongValue)(nil), + (*PropertyEntry_FloatValue)(nil), + (*PropertyEntry_DoubleValue)(nil), + (*PropertyEntry_StringValue)(nil), + (*PropertyEntry_BytesValue)(nil), + } + file_StatementService_proto_msgTypes[12].OneofWrappers = []any{ + (*OpResult_IntValue)(nil), + (*OpResult_QueryResult)(nil), + (*OpResult_UuidValue)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_StatementService_proto_rawDesc), len(file_StatementService_proto_rawDesc)), + NumEnums: 10, + NumMessages: 40, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_StatementService_proto_goTypes, + DependencyIndexes: file_StatementService_proto_depIdxs, + EnumInfos: file_StatementService_proto_enumTypes, + MessageInfos: file_StatementService_proto_msgTypes, + }.Build() + File_StatementService_proto = out.File + file_StatementService_proto_goTypes = nil + file_StatementService_proto_depIdxs = nil +} diff --git a/ojp-grpc-client-go/internal/gen/go/com/openjproxy/grpc/StatementService_grpc.pb.go b/ojp-grpc-client-go/internal/gen/go/com/openjproxy/grpc/StatementService_grpc.pb.go new file mode 100644 index 000000000..5f5c5c628 --- /dev/null +++ b/ojp-grpc-client-go/internal/gen/go/com/openjproxy/grpc/StatementService_grpc.pb.go @@ -0,0 +1,884 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.1 +// - protoc (unknown) +// source: StatementService.proto + +package grpc + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + StatementService_Connect_FullMethodName = "/com.openjproxy.grpc.StatementService/connect" + StatementService_ExecuteUpdate_FullMethodName = "/com.openjproxy.grpc.StatementService/executeUpdate" + StatementService_ExecuteQuery_FullMethodName = "/com.openjproxy.grpc.StatementService/executeQuery" + StatementService_FetchNextRows_FullMethodName = "/com.openjproxy.grpc.StatementService/fetchNextRows" + StatementService_CreateLob_FullMethodName = "/com.openjproxy.grpc.StatementService/createLob" + StatementService_ReadLob_FullMethodName = "/com.openjproxy.grpc.StatementService/readLob" + StatementService_TerminateSession_FullMethodName = "/com.openjproxy.grpc.StatementService/terminateSession" + StatementService_StartTransaction_FullMethodName = "/com.openjproxy.grpc.StatementService/startTransaction" + StatementService_CommitTransaction_FullMethodName = "/com.openjproxy.grpc.StatementService/commitTransaction" + StatementService_RollbackTransaction_FullMethodName = "/com.openjproxy.grpc.StatementService/rollbackTransaction" + StatementService_CallResource_FullMethodName = "/com.openjproxy.grpc.StatementService/callResource" + StatementService_XaStart_FullMethodName = "/com.openjproxy.grpc.StatementService/xaStart" + StatementService_XaEnd_FullMethodName = "/com.openjproxy.grpc.StatementService/xaEnd" + StatementService_XaPrepare_FullMethodName = "/com.openjproxy.grpc.StatementService/xaPrepare" + StatementService_XaCommit_FullMethodName = "/com.openjproxy.grpc.StatementService/xaCommit" + StatementService_XaRollback_FullMethodName = "/com.openjproxy.grpc.StatementService/xaRollback" + StatementService_XaRecover_FullMethodName = "/com.openjproxy.grpc.StatementService/xaRecover" + StatementService_XaForget_FullMethodName = "/com.openjproxy.grpc.StatementService/xaForget" + StatementService_XaSetTransactionTimeout_FullMethodName = "/com.openjproxy.grpc.StatementService/xaSetTransactionTimeout" + StatementService_XaGetTransactionTimeout_FullMethodName = "/com.openjproxy.grpc.StatementService/xaGetTransactionTimeout" + StatementService_XaIsSameRM_FullMethodName = "/com.openjproxy.grpc.StatementService/xaIsSameRM" +) + +// StatementServiceClient is the client API for StatementService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type StatementServiceClient interface { + Connect(ctx context.Context, in *ConnectionDetails, opts ...grpc.CallOption) (*SessionInfo, error) + ExecuteUpdate(ctx context.Context, in *StatementRequest, opts ...grpc.CallOption) (*OpResult, error) + ExecuteQuery(ctx context.Context, in *StatementRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[OpResult], error) + FetchNextRows(ctx context.Context, in *ResultSetFetchRequest, opts ...grpc.CallOption) (*OpResult, error) + CreateLob(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[LobDataBlock, LobReference], error) + ReadLob(ctx context.Context, in *ReadLobRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[LobDataBlock], error) + TerminateSession(ctx context.Context, in *SessionInfo, opts ...grpc.CallOption) (*SessionTerminationStatus, error) + StartTransaction(ctx context.Context, in *SessionInfo, opts ...grpc.CallOption) (*SessionInfo, error) + CommitTransaction(ctx context.Context, in *SessionInfo, opts ...grpc.CallOption) (*SessionInfo, error) + RollbackTransaction(ctx context.Context, in *SessionInfo, opts ...grpc.CallOption) (*SessionInfo, error) + CallResource(ctx context.Context, in *CallResourceRequest, opts ...grpc.CallOption) (*CallResourceResponse, error) + // XA Transaction Operations + XaStart(ctx context.Context, in *XaStartRequest, opts ...grpc.CallOption) (*XaResponse, error) + XaEnd(ctx context.Context, in *XaEndRequest, opts ...grpc.CallOption) (*XaResponse, error) + XaPrepare(ctx context.Context, in *XaPrepareRequest, opts ...grpc.CallOption) (*XaPrepareResponse, error) + XaCommit(ctx context.Context, in *XaCommitRequest, opts ...grpc.CallOption) (*XaResponse, error) + XaRollback(ctx context.Context, in *XaRollbackRequest, opts ...grpc.CallOption) (*XaResponse, error) + XaRecover(ctx context.Context, in *XaRecoverRequest, opts ...grpc.CallOption) (*XaRecoverResponse, error) + XaForget(ctx context.Context, in *XaForgetRequest, opts ...grpc.CallOption) (*XaResponse, error) + XaSetTransactionTimeout(ctx context.Context, in *XaSetTransactionTimeoutRequest, opts ...grpc.CallOption) (*XaSetTransactionTimeoutResponse, error) + XaGetTransactionTimeout(ctx context.Context, in *XaGetTransactionTimeoutRequest, opts ...grpc.CallOption) (*XaGetTransactionTimeoutResponse, error) + XaIsSameRM(ctx context.Context, in *XaIsSameRMRequest, opts ...grpc.CallOption) (*XaIsSameRMResponse, error) +} + +type statementServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewStatementServiceClient(cc grpc.ClientConnInterface) StatementServiceClient { + return &statementServiceClient{cc} +} + +func (c *statementServiceClient) Connect(ctx context.Context, in *ConnectionDetails, opts ...grpc.CallOption) (*SessionInfo, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SessionInfo) + err := c.cc.Invoke(ctx, StatementService_Connect_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) ExecuteUpdate(ctx context.Context, in *StatementRequest, opts ...grpc.CallOption) (*OpResult, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(OpResult) + err := c.cc.Invoke(ctx, StatementService_ExecuteUpdate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) ExecuteQuery(ctx context.Context, in *StatementRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[OpResult], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &StatementService_ServiceDesc.Streams[0], StatementService_ExecuteQuery_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[StatementRequest, OpResult]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StatementService_ExecuteQueryClient = grpc.ServerStreamingClient[OpResult] + +func (c *statementServiceClient) FetchNextRows(ctx context.Context, in *ResultSetFetchRequest, opts ...grpc.CallOption) (*OpResult, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(OpResult) + err := c.cc.Invoke(ctx, StatementService_FetchNextRows_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) CreateLob(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[LobDataBlock, LobReference], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &StatementService_ServiceDesc.Streams[1], StatementService_CreateLob_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[LobDataBlock, LobReference]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StatementService_CreateLobClient = grpc.BidiStreamingClient[LobDataBlock, LobReference] + +func (c *statementServiceClient) ReadLob(ctx context.Context, in *ReadLobRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[LobDataBlock], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &StatementService_ServiceDesc.Streams[2], StatementService_ReadLob_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[ReadLobRequest, LobDataBlock]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StatementService_ReadLobClient = grpc.ServerStreamingClient[LobDataBlock] + +func (c *statementServiceClient) TerminateSession(ctx context.Context, in *SessionInfo, opts ...grpc.CallOption) (*SessionTerminationStatus, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SessionTerminationStatus) + err := c.cc.Invoke(ctx, StatementService_TerminateSession_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) StartTransaction(ctx context.Context, in *SessionInfo, opts ...grpc.CallOption) (*SessionInfo, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SessionInfo) + err := c.cc.Invoke(ctx, StatementService_StartTransaction_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) CommitTransaction(ctx context.Context, in *SessionInfo, opts ...grpc.CallOption) (*SessionInfo, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SessionInfo) + err := c.cc.Invoke(ctx, StatementService_CommitTransaction_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) RollbackTransaction(ctx context.Context, in *SessionInfo, opts ...grpc.CallOption) (*SessionInfo, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SessionInfo) + err := c.cc.Invoke(ctx, StatementService_RollbackTransaction_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) CallResource(ctx context.Context, in *CallResourceRequest, opts ...grpc.CallOption) (*CallResourceResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CallResourceResponse) + err := c.cc.Invoke(ctx, StatementService_CallResource_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaStart(ctx context.Context, in *XaStartRequest, opts ...grpc.CallOption) (*XaResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaResponse) + err := c.cc.Invoke(ctx, StatementService_XaStart_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaEnd(ctx context.Context, in *XaEndRequest, opts ...grpc.CallOption) (*XaResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaResponse) + err := c.cc.Invoke(ctx, StatementService_XaEnd_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaPrepare(ctx context.Context, in *XaPrepareRequest, opts ...grpc.CallOption) (*XaPrepareResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaPrepareResponse) + err := c.cc.Invoke(ctx, StatementService_XaPrepare_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaCommit(ctx context.Context, in *XaCommitRequest, opts ...grpc.CallOption) (*XaResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaResponse) + err := c.cc.Invoke(ctx, StatementService_XaCommit_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaRollback(ctx context.Context, in *XaRollbackRequest, opts ...grpc.CallOption) (*XaResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaResponse) + err := c.cc.Invoke(ctx, StatementService_XaRollback_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaRecover(ctx context.Context, in *XaRecoverRequest, opts ...grpc.CallOption) (*XaRecoverResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaRecoverResponse) + err := c.cc.Invoke(ctx, StatementService_XaRecover_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaForget(ctx context.Context, in *XaForgetRequest, opts ...grpc.CallOption) (*XaResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaResponse) + err := c.cc.Invoke(ctx, StatementService_XaForget_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaSetTransactionTimeout(ctx context.Context, in *XaSetTransactionTimeoutRequest, opts ...grpc.CallOption) (*XaSetTransactionTimeoutResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaSetTransactionTimeoutResponse) + err := c.cc.Invoke(ctx, StatementService_XaSetTransactionTimeout_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaGetTransactionTimeout(ctx context.Context, in *XaGetTransactionTimeoutRequest, opts ...grpc.CallOption) (*XaGetTransactionTimeoutResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaGetTransactionTimeoutResponse) + err := c.cc.Invoke(ctx, StatementService_XaGetTransactionTimeout_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statementServiceClient) XaIsSameRM(ctx context.Context, in *XaIsSameRMRequest, opts ...grpc.CallOption) (*XaIsSameRMResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(XaIsSameRMResponse) + err := c.cc.Invoke(ctx, StatementService_XaIsSameRM_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// StatementServiceServer is the server API for StatementService service. +// All implementations must embed UnimplementedStatementServiceServer +// for forward compatibility. +type StatementServiceServer interface { + Connect(context.Context, *ConnectionDetails) (*SessionInfo, error) + ExecuteUpdate(context.Context, *StatementRequest) (*OpResult, error) + ExecuteQuery(*StatementRequest, grpc.ServerStreamingServer[OpResult]) error + FetchNextRows(context.Context, *ResultSetFetchRequest) (*OpResult, error) + CreateLob(grpc.BidiStreamingServer[LobDataBlock, LobReference]) error + ReadLob(*ReadLobRequest, grpc.ServerStreamingServer[LobDataBlock]) error + TerminateSession(context.Context, *SessionInfo) (*SessionTerminationStatus, error) + StartTransaction(context.Context, *SessionInfo) (*SessionInfo, error) + CommitTransaction(context.Context, *SessionInfo) (*SessionInfo, error) + RollbackTransaction(context.Context, *SessionInfo) (*SessionInfo, error) + CallResource(context.Context, *CallResourceRequest) (*CallResourceResponse, error) + // XA Transaction Operations + XaStart(context.Context, *XaStartRequest) (*XaResponse, error) + XaEnd(context.Context, *XaEndRequest) (*XaResponse, error) + XaPrepare(context.Context, *XaPrepareRequest) (*XaPrepareResponse, error) + XaCommit(context.Context, *XaCommitRequest) (*XaResponse, error) + XaRollback(context.Context, *XaRollbackRequest) (*XaResponse, error) + XaRecover(context.Context, *XaRecoverRequest) (*XaRecoverResponse, error) + XaForget(context.Context, *XaForgetRequest) (*XaResponse, error) + XaSetTransactionTimeout(context.Context, *XaSetTransactionTimeoutRequest) (*XaSetTransactionTimeoutResponse, error) + XaGetTransactionTimeout(context.Context, *XaGetTransactionTimeoutRequest) (*XaGetTransactionTimeoutResponse, error) + XaIsSameRM(context.Context, *XaIsSameRMRequest) (*XaIsSameRMResponse, error) + mustEmbedUnimplementedStatementServiceServer() +} + +// UnimplementedStatementServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedStatementServiceServer struct{} + +func (UnimplementedStatementServiceServer) Connect(context.Context, *ConnectionDetails) (*SessionInfo, error) { + return nil, status.Error(codes.Unimplemented, "method Connect not implemented") +} +func (UnimplementedStatementServiceServer) ExecuteUpdate(context.Context, *StatementRequest) (*OpResult, error) { + return nil, status.Error(codes.Unimplemented, "method ExecuteUpdate not implemented") +} +func (UnimplementedStatementServiceServer) ExecuteQuery(*StatementRequest, grpc.ServerStreamingServer[OpResult]) error { + return status.Error(codes.Unimplemented, "method ExecuteQuery not implemented") +} +func (UnimplementedStatementServiceServer) FetchNextRows(context.Context, *ResultSetFetchRequest) (*OpResult, error) { + return nil, status.Error(codes.Unimplemented, "method FetchNextRows not implemented") +} +func (UnimplementedStatementServiceServer) CreateLob(grpc.BidiStreamingServer[LobDataBlock, LobReference]) error { + return status.Error(codes.Unimplemented, "method CreateLob not implemented") +} +func (UnimplementedStatementServiceServer) ReadLob(*ReadLobRequest, grpc.ServerStreamingServer[LobDataBlock]) error { + return status.Error(codes.Unimplemented, "method ReadLob not implemented") +} +func (UnimplementedStatementServiceServer) TerminateSession(context.Context, *SessionInfo) (*SessionTerminationStatus, error) { + return nil, status.Error(codes.Unimplemented, "method TerminateSession not implemented") +} +func (UnimplementedStatementServiceServer) StartTransaction(context.Context, *SessionInfo) (*SessionInfo, error) { + return nil, status.Error(codes.Unimplemented, "method StartTransaction not implemented") +} +func (UnimplementedStatementServiceServer) CommitTransaction(context.Context, *SessionInfo) (*SessionInfo, error) { + return nil, status.Error(codes.Unimplemented, "method CommitTransaction not implemented") +} +func (UnimplementedStatementServiceServer) RollbackTransaction(context.Context, *SessionInfo) (*SessionInfo, error) { + return nil, status.Error(codes.Unimplemented, "method RollbackTransaction not implemented") +} +func (UnimplementedStatementServiceServer) CallResource(context.Context, *CallResourceRequest) (*CallResourceResponse, error) { + return nil, status.Error(codes.Unimplemented, "method CallResource not implemented") +} +func (UnimplementedStatementServiceServer) XaStart(context.Context, *XaStartRequest) (*XaResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaStart not implemented") +} +func (UnimplementedStatementServiceServer) XaEnd(context.Context, *XaEndRequest) (*XaResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaEnd not implemented") +} +func (UnimplementedStatementServiceServer) XaPrepare(context.Context, *XaPrepareRequest) (*XaPrepareResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaPrepare not implemented") +} +func (UnimplementedStatementServiceServer) XaCommit(context.Context, *XaCommitRequest) (*XaResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaCommit not implemented") +} +func (UnimplementedStatementServiceServer) XaRollback(context.Context, *XaRollbackRequest) (*XaResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaRollback not implemented") +} +func (UnimplementedStatementServiceServer) XaRecover(context.Context, *XaRecoverRequest) (*XaRecoverResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaRecover not implemented") +} +func (UnimplementedStatementServiceServer) XaForget(context.Context, *XaForgetRequest) (*XaResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaForget not implemented") +} +func (UnimplementedStatementServiceServer) XaSetTransactionTimeout(context.Context, *XaSetTransactionTimeoutRequest) (*XaSetTransactionTimeoutResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaSetTransactionTimeout not implemented") +} +func (UnimplementedStatementServiceServer) XaGetTransactionTimeout(context.Context, *XaGetTransactionTimeoutRequest) (*XaGetTransactionTimeoutResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaGetTransactionTimeout not implemented") +} +func (UnimplementedStatementServiceServer) XaIsSameRM(context.Context, *XaIsSameRMRequest) (*XaIsSameRMResponse, error) { + return nil, status.Error(codes.Unimplemented, "method XaIsSameRM not implemented") +} +func (UnimplementedStatementServiceServer) mustEmbedUnimplementedStatementServiceServer() {} +func (UnimplementedStatementServiceServer) testEmbeddedByValue() {} + +// UnsafeStatementServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StatementServiceServer will +// result in compilation errors. +type UnsafeStatementServiceServer interface { + mustEmbedUnimplementedStatementServiceServer() +} + +func RegisterStatementServiceServer(s grpc.ServiceRegistrar, srv StatementServiceServer) { + // If the following call panics, it indicates UnimplementedStatementServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&StatementService_ServiceDesc, srv) +} + +func _StatementService_Connect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ConnectionDetails) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).Connect(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_Connect_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).Connect(ctx, req.(*ConnectionDetails)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_ExecuteUpdate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StatementRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).ExecuteUpdate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_ExecuteUpdate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).ExecuteUpdate(ctx, req.(*StatementRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_ExecuteQuery_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(StatementRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StatementServiceServer).ExecuteQuery(m, &grpc.GenericServerStream[StatementRequest, OpResult]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StatementService_ExecuteQueryServer = grpc.ServerStreamingServer[OpResult] + +func _StatementService_FetchNextRows_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResultSetFetchRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).FetchNextRows(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_FetchNextRows_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).FetchNextRows(ctx, req.(*ResultSetFetchRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_CreateLob_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StatementServiceServer).CreateLob(&grpc.GenericServerStream[LobDataBlock, LobReference]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StatementService_CreateLobServer = grpc.BidiStreamingServer[LobDataBlock, LobReference] + +func _StatementService_ReadLob_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(ReadLobRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StatementServiceServer).ReadLob(m, &grpc.GenericServerStream[ReadLobRequest, LobDataBlock]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StatementService_ReadLobServer = grpc.ServerStreamingServer[LobDataBlock] + +func _StatementService_TerminateSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SessionInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).TerminateSession(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_TerminateSession_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).TerminateSession(ctx, req.(*SessionInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_StartTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SessionInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).StartTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_StartTransaction_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).StartTransaction(ctx, req.(*SessionInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_CommitTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SessionInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).CommitTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_CommitTransaction_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).CommitTransaction(ctx, req.(*SessionInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_RollbackTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SessionInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).RollbackTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_RollbackTransaction_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).RollbackTransaction(ctx, req.(*SessionInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_CallResource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CallResourceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).CallResource(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_CallResource_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).CallResource(ctx, req.(*CallResourceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaStart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaStartRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaStart(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaStart_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaStart(ctx, req.(*XaStartRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaEnd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaEndRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaEnd(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaEnd_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaEnd(ctx, req.(*XaEndRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaPrepare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaPrepareRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaPrepare(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaPrepare_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaPrepare(ctx, req.(*XaPrepareRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaCommit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaCommitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaCommit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaCommit_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaCommit(ctx, req.(*XaCommitRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaRollback_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaRollbackRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaRollback(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaRollback_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaRollback(ctx, req.(*XaRollbackRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaRecover_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaRecoverRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaRecover(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaRecover_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaRecover(ctx, req.(*XaRecoverRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaForget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaForgetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaForget(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaForget_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaForget(ctx, req.(*XaForgetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaSetTransactionTimeout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaSetTransactionTimeoutRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaSetTransactionTimeout(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaSetTransactionTimeout_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaSetTransactionTimeout(ctx, req.(*XaSetTransactionTimeoutRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaGetTransactionTimeout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaGetTransactionTimeoutRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaGetTransactionTimeout(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaGetTransactionTimeout_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaGetTransactionTimeout(ctx, req.(*XaGetTransactionTimeoutRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatementService_XaIsSameRM_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(XaIsSameRMRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatementServiceServer).XaIsSameRM(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StatementService_XaIsSameRM_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatementServiceServer).XaIsSameRM(ctx, req.(*XaIsSameRMRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// StatementService_ServiceDesc is the grpc.ServiceDesc for StatementService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var StatementService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.openjproxy.grpc.StatementService", + HandlerType: (*StatementServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "connect", + Handler: _StatementService_Connect_Handler, + }, + { + MethodName: "executeUpdate", + Handler: _StatementService_ExecuteUpdate_Handler, + }, + { + MethodName: "fetchNextRows", + Handler: _StatementService_FetchNextRows_Handler, + }, + { + MethodName: "terminateSession", + Handler: _StatementService_TerminateSession_Handler, + }, + { + MethodName: "startTransaction", + Handler: _StatementService_StartTransaction_Handler, + }, + { + MethodName: "commitTransaction", + Handler: _StatementService_CommitTransaction_Handler, + }, + { + MethodName: "rollbackTransaction", + Handler: _StatementService_RollbackTransaction_Handler, + }, + { + MethodName: "callResource", + Handler: _StatementService_CallResource_Handler, + }, + { + MethodName: "xaStart", + Handler: _StatementService_XaStart_Handler, + }, + { + MethodName: "xaEnd", + Handler: _StatementService_XaEnd_Handler, + }, + { + MethodName: "xaPrepare", + Handler: _StatementService_XaPrepare_Handler, + }, + { + MethodName: "xaCommit", + Handler: _StatementService_XaCommit_Handler, + }, + { + MethodName: "xaRollback", + Handler: _StatementService_XaRollback_Handler, + }, + { + MethodName: "xaRecover", + Handler: _StatementService_XaRecover_Handler, + }, + { + MethodName: "xaForget", + Handler: _StatementService_XaForget_Handler, + }, + { + MethodName: "xaSetTransactionTimeout", + Handler: _StatementService_XaSetTransactionTimeout_Handler, + }, + { + MethodName: "xaGetTransactionTimeout", + Handler: _StatementService_XaGetTransactionTimeout_Handler, + }, + { + MethodName: "xaIsSameRM", + Handler: _StatementService_XaIsSameRM_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "executeQuery", + Handler: _StatementService_ExecuteQuery_Handler, + ServerStreams: true, + }, + { + StreamName: "createLob", + Handler: _StatementService_CreateLob_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "readLob", + Handler: _StatementService_ReadLob_Handler, + ServerStreams: true, + }, + }, + Metadata: "StatementService.proto", +} diff --git a/ojp-grpc-client-go/internal/gen/go/ojp/transport/v1/containers.pb.go b/ojp-grpc-client-go/internal/gen/go/ojp/transport/v1/containers.pb.go new file mode 100644 index 000000000..b46a73784 --- /dev/null +++ b/ojp-grpc-client-go/internal/gen/go/ojp/transport/v1/containers.pb.go @@ -0,0 +1,542 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: containers.proto + +package v1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Container wraps any serializable value type to enable type-safe deserialization. +// This allows us to know which type was serialized without ambiguity. +type Container struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Content: + // + // *Container_Value + // *Container_Object + // *Container_Array + // *Container_Properties + Content isContainer_Content `protobuf_oneof:"content"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Container) Reset() { + *x = Container{} + mi := &file_containers_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Container) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Container) ProtoMessage() {} + +func (x *Container) ProtoReflect() protoreflect.Message { + mi := &file_containers_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Container.ProtoReflect.Descriptor instead. +func (*Container) Descriptor() ([]byte, []int) { + return file_containers_proto_rawDescGZIP(), []int{0} +} + +func (x *Container) GetContent() isContainer_Content { + if x != nil { + return x.Content + } + return nil +} + +func (x *Container) GetValue() *Value { + if x != nil { + if x, ok := x.Content.(*Container_Value); ok { + return x.Value + } + } + return nil +} + +func (x *Container) GetObject() *Object { + if x != nil { + if x, ok := x.Content.(*Container_Object); ok { + return x.Object + } + } + return nil +} + +func (x *Container) GetArray() *Array { + if x != nil { + if x, ok := x.Content.(*Container_Array); ok { + return x.Array + } + } + return nil +} + +func (x *Container) GetProperties() *Properties { + if x != nil { + if x, ok := x.Content.(*Container_Properties); ok { + return x.Properties + } + } + return nil +} + +type isContainer_Content interface { + isContainer_Content() +} + +type Container_Value struct { + Value *Value `protobuf:"bytes,1,opt,name=value,proto3,oneof"` // Primitive value or nested structure +} + +type Container_Object struct { + Object *Object `protobuf:"bytes,2,opt,name=object,proto3,oneof"` // Map/Object +} + +type Container_Array struct { + Array *Array `protobuf:"bytes,3,opt,name=array,proto3,oneof"` // List/Array +} + +type Container_Properties struct { + Properties *Properties `protobuf:"bytes,4,opt,name=properties,proto3,oneof"` // Properties (String -> String map) +} + +func (*Container_Value) isContainer_Content() {} + +func (*Container_Object) isContainer_Content() {} + +func (*Container_Array) isContainer_Content() {} + +func (*Container_Properties) isContainer_Content() {} + +// Value represents a single value that can be a primitive, object, array, or null. +// This is used to represent any JSON-like value structure in a type-safe manner. +type Value struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Kind: + // + // *Value_S + // *Value_N + // *Value_B + // *Value_O + // *Value_A + // *Value_NullValue + Kind isValue_Kind `protobuf_oneof:"kind"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Value) Reset() { + *x = Value{} + mi := &file_containers_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Value) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Value) ProtoMessage() {} + +func (x *Value) ProtoReflect() protoreflect.Message { + mi := &file_containers_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Value.ProtoReflect.Descriptor instead. +func (*Value) Descriptor() ([]byte, []int) { + return file_containers_proto_rawDescGZIP(), []int{1} +} + +func (x *Value) GetKind() isValue_Kind { + if x != nil { + return x.Kind + } + return nil +} + +func (x *Value) GetS() string { + if x != nil { + if x, ok := x.Kind.(*Value_S); ok { + return x.S + } + } + return "" +} + +func (x *Value) GetN() float64 { + if x != nil { + if x, ok := x.Kind.(*Value_N); ok { + return x.N + } + } + return 0 +} + +func (x *Value) GetB() bool { + if x != nil { + if x, ok := x.Kind.(*Value_B); ok { + return x.B + } + } + return false +} + +func (x *Value) GetO() *Object { + if x != nil { + if x, ok := x.Kind.(*Value_O); ok { + return x.O + } + } + return nil +} + +func (x *Value) GetA() *Array { + if x != nil { + if x, ok := x.Kind.(*Value_A); ok { + return x.A + } + } + return nil +} + +func (x *Value) GetNullValue() structpb.NullValue { + if x != nil { + if x, ok := x.Kind.(*Value_NullValue); ok { + return x.NullValue + } + } + return structpb.NullValue(0) +} + +type isValue_Kind interface { + isValue_Kind() +} + +type Value_S struct { + S string `protobuf:"bytes,1,opt,name=s,proto3,oneof"` // String value +} + +type Value_N struct { + N float64 `protobuf:"fixed64,2,opt,name=n,proto3,oneof"` // Numeric value (covers int, long, float, double) +} + +type Value_B struct { + B bool `protobuf:"varint,3,opt,name=b,proto3,oneof"` // Boolean value +} + +type Value_O struct { + O *Object `protobuf:"bytes,4,opt,name=o,proto3,oneof"` // Object/Map value +} + +type Value_A struct { + A *Array `protobuf:"bytes,5,opt,name=a,proto3,oneof"` // Array/List value +} + +type Value_NullValue struct { + NullValue structpb.NullValue `protobuf:"varint,6,opt,name=null_value,json=nullValue,proto3,enum=google.protobuf.NullValue,oneof"` // Explicit null marker +} + +func (*Value_S) isValue_Kind() {} + +func (*Value_N) isValue_Kind() {} + +func (*Value_B) isValue_Kind() {} + +func (*Value_O) isValue_Kind() {} + +func (*Value_A) isValue_Kind() {} + +func (*Value_NullValue) isValue_Kind() {} + +// Object represents a map/dictionary structure with string keys and arbitrary values. +// Uses map to preserve key-value pairs. +// Note: Iteration order is not guaranteed by protobuf maps, but implementations +// should use LinkedHashMap to preserve insertion order in Java. +type Object struct { + state protoimpl.MessageState `protogen:"open.v1"` + Entries map[string]*Value `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Object) Reset() { + *x = Object{} + mi := &file_containers_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Object) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Object) ProtoMessage() {} + +func (x *Object) ProtoReflect() protoreflect.Message { + mi := &file_containers_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Object.ProtoReflect.Descriptor instead. +func (*Object) Descriptor() ([]byte, []int) { + return file_containers_proto_rawDescGZIP(), []int{2} +} + +func (x *Object) GetEntries() map[string]*Value { + if x != nil { + return x.Entries + } + return nil +} + +// Array represents a list/array structure with ordered values. +type Array struct { + state protoimpl.MessageState `protogen:"open.v1"` + Values []*Value `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Array) Reset() { + *x = Array{} + mi := &file_containers_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Array) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Array) ProtoMessage() {} + +func (x *Array) ProtoReflect() protoreflect.Message { + mi := &file_containers_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Array.ProtoReflect.Descriptor instead. +func (*Array) Descriptor() ([]byte, []int) { + return file_containers_proto_rawDescGZIP(), []int{3} +} + +func (x *Array) GetValues() []*Value { + if x != nil { + return x.Values + } + return nil +} + +// Properties represents a simple map with string keys and string values. +// This is a special case for java.util.Properties where all values are strings. +type Properties struct { + state protoimpl.MessageState `protogen:"open.v1"` + Entries map[string]string `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Properties) Reset() { + *x = Properties{} + mi := &file_containers_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Properties) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Properties) ProtoMessage() {} + +func (x *Properties) ProtoReflect() protoreflect.Message { + mi := &file_containers_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Properties.ProtoReflect.Descriptor instead. +func (*Properties) Descriptor() ([]byte, []int) { + return file_containers_proto_rawDescGZIP(), []int{4} +} + +func (x *Properties) GetEntries() map[string]string { + if x != nil { + return x.Entries + } + return nil +} + +var File_containers_proto protoreflect.FileDescriptor + +const file_containers_proto_rawDesc = "" + + "\n" + + "\x10containers.proto\x12\x10ojp.transport.v1\x1a\x1cgoogle/protobuf/struct.proto\"\xec\x01\n" + + "\tContainer\x12/\n" + + "\x05value\x18\x01 \x01(\v2\x17.ojp.transport.v1.ValueH\x00R\x05value\x122\n" + + "\x06object\x18\x02 \x01(\v2\x18.ojp.transport.v1.ObjectH\x00R\x06object\x12/\n" + + "\x05array\x18\x03 \x01(\v2\x17.ojp.transport.v1.ArrayH\x00R\x05array\x12>\n" + + "\n" + + "properties\x18\x04 \x01(\v2\x1c.ojp.transport.v1.PropertiesH\x00R\n" + + "propertiesB\t\n" + + "\acontent\"\xcf\x01\n" + + "\x05Value\x12\x0e\n" + + "\x01s\x18\x01 \x01(\tH\x00R\x01s\x12\x0e\n" + + "\x01n\x18\x02 \x01(\x01H\x00R\x01n\x12\x0e\n" + + "\x01b\x18\x03 \x01(\bH\x00R\x01b\x12(\n" + + "\x01o\x18\x04 \x01(\v2\x18.ojp.transport.v1.ObjectH\x00R\x01o\x12'\n" + + "\x01a\x18\x05 \x01(\v2\x17.ojp.transport.v1.ArrayH\x00R\x01a\x12;\n" + + "\n" + + "null_value\x18\x06 \x01(\x0e2\x1a.google.protobuf.NullValueH\x00R\tnullValueB\x06\n" + + "\x04kind\"\x9e\x01\n" + + "\x06Object\x12?\n" + + "\aentries\x18\x01 \x03(\v2%.ojp.transport.v1.Object.EntriesEntryR\aentries\x1aS\n" + + "\fEntriesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12-\n" + + "\x05value\x18\x02 \x01(\v2\x17.ojp.transport.v1.ValueR\x05value:\x028\x01\"8\n" + + "\x05Array\x12/\n" + + "\x06values\x18\x01 \x03(\v2\x17.ojp.transport.v1.ValueR\x06values\"\x8d\x01\n" + + "\n" + + "Properties\x12C\n" + + "\aentries\x18\x01 \x03(\v2).ojp.transport.v1.Properties.EntriesEntryR\aentries\x1a:\n" + + "\fEntriesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x02P\x01b\x06proto3" + +var ( + file_containers_proto_rawDescOnce sync.Once + file_containers_proto_rawDescData []byte +) + +func file_containers_proto_rawDescGZIP() []byte { + file_containers_proto_rawDescOnce.Do(func() { + file_containers_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_containers_proto_rawDesc), len(file_containers_proto_rawDesc))) + }) + return file_containers_proto_rawDescData +} + +var file_containers_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_containers_proto_goTypes = []any{ + (*Container)(nil), // 0: ojp.transport.v1.Container + (*Value)(nil), // 1: ojp.transport.v1.Value + (*Object)(nil), // 2: ojp.transport.v1.Object + (*Array)(nil), // 3: ojp.transport.v1.Array + (*Properties)(nil), // 4: ojp.transport.v1.Properties + nil, // 5: ojp.transport.v1.Object.EntriesEntry + nil, // 6: ojp.transport.v1.Properties.EntriesEntry + (structpb.NullValue)(0), // 7: google.protobuf.NullValue +} +var file_containers_proto_depIdxs = []int32{ + 1, // 0: ojp.transport.v1.Container.value:type_name -> ojp.transport.v1.Value + 2, // 1: ojp.transport.v1.Container.object:type_name -> ojp.transport.v1.Object + 3, // 2: ojp.transport.v1.Container.array:type_name -> ojp.transport.v1.Array + 4, // 3: ojp.transport.v1.Container.properties:type_name -> ojp.transport.v1.Properties + 2, // 4: ojp.transport.v1.Value.o:type_name -> ojp.transport.v1.Object + 3, // 5: ojp.transport.v1.Value.a:type_name -> ojp.transport.v1.Array + 7, // 6: ojp.transport.v1.Value.null_value:type_name -> google.protobuf.NullValue + 5, // 7: ojp.transport.v1.Object.entries:type_name -> ojp.transport.v1.Object.EntriesEntry + 1, // 8: ojp.transport.v1.Array.values:type_name -> ojp.transport.v1.Value + 6, // 9: ojp.transport.v1.Properties.entries:type_name -> ojp.transport.v1.Properties.EntriesEntry + 1, // 10: ojp.transport.v1.Object.EntriesEntry.value:type_name -> ojp.transport.v1.Value + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name +} + +func init() { file_containers_proto_init() } +func file_containers_proto_init() { + if File_containers_proto != nil { + return + } + file_containers_proto_msgTypes[0].OneofWrappers = []any{ + (*Container_Value)(nil), + (*Container_Object)(nil), + (*Container_Array)(nil), + (*Container_Properties)(nil), + } + file_containers_proto_msgTypes[1].OneofWrappers = []any{ + (*Value_S)(nil), + (*Value_N)(nil), + (*Value_B)(nil), + (*Value_O)(nil), + (*Value_A)(nil), + (*Value_NullValue)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_containers_proto_rawDesc), len(file_containers_proto_rawDesc)), + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_containers_proto_goTypes, + DependencyIndexes: file_containers_proto_depIdxs, + MessageInfos: file_containers_proto_msgTypes, + }.Build() + File_containers_proto = out.File + file_containers_proto_goTypes = nil + file_containers_proto_depIdxs = nil +} diff --git a/ojp-grpc-client-go/internal/gen/go/org/openjproxy/grpc/echo.pb.go b/ojp-grpc-client-go/internal/gen/go/org/openjproxy/grpc/echo.pb.go new file mode 100644 index 000000000..acc4d0f50 --- /dev/null +++ b/ojp-grpc-client-go/internal/gen/go/org/openjproxy/grpc/echo.pb.go @@ -0,0 +1,174 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: echo.proto + +package grpc + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type EchoRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EchoRequest) Reset() { + *x = EchoRequest{} + mi := &file_echo_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EchoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EchoRequest) ProtoMessage() {} + +func (x *EchoRequest) ProtoReflect() protoreflect.Message { + mi := &file_echo_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EchoRequest.ProtoReflect.Descriptor instead. +func (*EchoRequest) Descriptor() ([]byte, []int) { + return file_echo_proto_rawDescGZIP(), []int{0} +} + +func (x *EchoRequest) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type EchoResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EchoResponse) Reset() { + *x = EchoResponse{} + mi := &file_echo_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EchoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EchoResponse) ProtoMessage() {} + +func (x *EchoResponse) ProtoReflect() protoreflect.Message { + mi := &file_echo_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EchoResponse.ProtoReflect.Descriptor instead. +func (*EchoResponse) Descriptor() ([]byte, []int) { + return file_echo_proto_rawDescGZIP(), []int{1} +} + +func (x *EchoResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_echo_proto protoreflect.FileDescriptor + +const file_echo_proto_rawDesc = "" + + "\n" + + "\n" + + "echo.proto\x12\x13org.openjproxy.grpc\"'\n" + + "\vEchoRequest\x12\x18\n" + + "\amessage\x18\x01 \x01(\tR\amessage\"(\n" + + "\fEchoResponse\x12\x18\n" + + "\amessage\x18\x01 \x01(\tR\amessage2Z\n" + + "\vEchoService\x12K\n" + + "\x04Echo\x12 .org.openjproxy.grpc.EchoRequest\x1a!.org.openjproxy.grpc.EchoResponseB\x14B\x10EchoServiceProtoP\x01b\x06proto3" + +var ( + file_echo_proto_rawDescOnce sync.Once + file_echo_proto_rawDescData []byte +) + +func file_echo_proto_rawDescGZIP() []byte { + file_echo_proto_rawDescOnce.Do(func() { + file_echo_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_echo_proto_rawDesc), len(file_echo_proto_rawDesc))) + }) + return file_echo_proto_rawDescData +} + +var file_echo_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_echo_proto_goTypes = []any{ + (*EchoRequest)(nil), // 0: org.openjproxy.grpc.EchoRequest + (*EchoResponse)(nil), // 1: org.openjproxy.grpc.EchoResponse +} +var file_echo_proto_depIdxs = []int32{ + 0, // 0: org.openjproxy.grpc.EchoService.Echo:input_type -> org.openjproxy.grpc.EchoRequest + 1, // 1: org.openjproxy.grpc.EchoService.Echo:output_type -> org.openjproxy.grpc.EchoResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_echo_proto_init() } +func file_echo_proto_init() { + if File_echo_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_echo_proto_rawDesc), len(file_echo_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_echo_proto_goTypes, + DependencyIndexes: file_echo_proto_depIdxs, + MessageInfos: file_echo_proto_msgTypes, + }.Build() + File_echo_proto = out.File + file_echo_proto_goTypes = nil + file_echo_proto_depIdxs = nil +} diff --git a/ojp-grpc-client-go/internal/gen/go/org/openjproxy/grpc/echo_grpc.pb.go b/ojp-grpc-client-go/internal/gen/go/org/openjproxy/grpc/echo_grpc.pb.go new file mode 100644 index 000000000..ad1ec41bf --- /dev/null +++ b/ojp-grpc-client-go/internal/gen/go/org/openjproxy/grpc/echo_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.1 +// - protoc (unknown) +// source: echo.proto + +package grpc + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + EchoService_Echo_FullMethodName = "/org.openjproxy.grpc.EchoService/Echo" +) + +// EchoServiceClient is the client API for EchoService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type EchoServiceClient interface { + Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) +} + +type echoServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient { + return &echoServiceClient{cc} +} + +func (c *echoServiceClient) Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(EchoResponse) + err := c.cc.Invoke(ctx, EchoService_Echo_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EchoServiceServer is the server API for EchoService service. +// All implementations must embed UnimplementedEchoServiceServer +// for forward compatibility. +type EchoServiceServer interface { + Echo(context.Context, *EchoRequest) (*EchoResponse, error) + mustEmbedUnimplementedEchoServiceServer() +} + +// UnimplementedEchoServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedEchoServiceServer struct{} + +func (UnimplementedEchoServiceServer) Echo(context.Context, *EchoRequest) (*EchoResponse, error) { + return nil, status.Error(codes.Unimplemented, "method Echo not implemented") +} +func (UnimplementedEchoServiceServer) mustEmbedUnimplementedEchoServiceServer() {} +func (UnimplementedEchoServiceServer) testEmbeddedByValue() {} + +// UnsafeEchoServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to EchoServiceServer will +// result in compilation errors. +type UnsafeEchoServiceServer interface { + mustEmbedUnimplementedEchoServiceServer() +} + +func RegisterEchoServiceServer(s grpc.ServiceRegistrar, srv EchoServiceServer) { + // If the following call panics, it indicates UnimplementedEchoServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&EchoService_ServiceDesc, srv) +} + +func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EchoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EchoServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: EchoService_Echo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EchoServiceServer).Echo(ctx, req.(*EchoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// EchoService_ServiceDesc is the grpc.ServiceDesc for EchoService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var EchoService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "org.openjproxy.grpc.EchoService", + HandlerType: (*EchoServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _EchoService_Echo_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "echo.proto", +} diff --git a/ojp-grpc-client-go/scripts/run-db2-crud-test.ps1 b/ojp-grpc-client-go/scripts/run-db2-crud-test.ps1 new file mode 100644 index 000000000..ac1416dba --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-db2-crud-test.ps1 @@ -0,0 +1,128 @@ +param( + [switch]$SkipBuild +) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$clientDir = Split-Path -Parent $scriptDir +$repoRoot = Split-Path -Parent $clientDir +$serverDir = Join-Path $repoRoot "ojp-server" +$composeFile = Join-Path $clientDir "docker-compose.db2.yml" +$runStamp = Get-Date -Format "yyyyMMdd-HHmmss" +$serverLogOut = Join-Path $clientDir ".ojp-server-db2.$runStamp.out.log" +$serverLogErr = Join-Path $clientDir ".ojp-server-db2.$runStamp.err.log" + +$dbUser = "db2inst1" +$dbPassword = "testpass" +$dbHost = "localhost" +$dbName = "testdb" + +function Get-FreeTcpPort { + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) + $listener.Start() + $port = ($listener.LocalEndpoint).Port + $listener.Stop() + return [string]$port +} + +$ojpPort = Get-FreeTcpPort +$ojpPrometheusPort = Get-FreeTcpPort +$dbPort = Get-FreeTcpPort + +$env:DB2_HOST_PORT = $dbPort + +function Wait-Db2Healthy { + param([int]$MaxAttempts = 120, [int]$SleepSeconds = 5) + for ($i = 1; $i -le $MaxAttempts; $i++) { + $status = docker inspect -f '{{.State.Health.Status}}' ojp-db2 2>$null + if ($status -eq "healthy") { return } + Start-Sleep -Seconds $SleepSeconds + } + throw "DB2 container did not become healthy in time." +} + +function Wait-OjpStarted { + param([int]$MaxAttempts = 120, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + if (Test-Path $serverLogOut) { + $tail = Get-Content $serverLogOut -Tail 120 -ErrorAction SilentlyContinue + if ($tail -match "OJP gRPC Server started successfully") { return } + } + Start-Sleep -Seconds $SleepSeconds + } + throw "OJP server did not start in time. Check $serverLogOut and $serverLogErr" +} + +Write-Host "[1/8] Starting DB2 via docker compose..." +docker compose -f $composeFile up -d | Out-Null + +Write-Host "[2/8] Waiting for DB2 health..." +Wait-Db2Healthy + +Write-Host "[3/8] Ensuring DB2 JDBC driver in ojp-server/ojp-libs..." +$libsDir = Join-Path $serverDir "ojp-libs" +New-Item -ItemType Directory -Force -Path $libsDir | Out-Null +$db2Driver = Get-ChildItem -Path $libsDir -Filter "jcc-*.jar" -ErrorAction SilentlyContinue | Select-Object -First 1 +if (-not $db2Driver) { + $driverTarget = Join-Path $libsDir "jcc-11.5.9.0.jar" + Invoke-WebRequest -Uri "https://repo1.maven.org/maven2/com/ibm/db2/jcc/11.5.9.0/jcc-11.5.9.0.jar" -OutFile $driverTarget +} + +if (-not $SkipBuild) { + Write-Host "[4/8] Building OJP modules needed by server..." + Push-Location $repoRoot + try { + mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" + } + finally { + Pop-Location + } +} else { + Write-Host "[4/8] Skipping build (-SkipBuild)." +} + +Write-Host "[5/8] Starting OJP server..." +$jarPath = Join-Path $serverDir "target\ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if (-not (Test-Path $jarPath)) { + throw "Missing server jar: $jarPath" +} +$serverProcess = Start-Process -FilePath "java" ` + -ArgumentList @( + "-Duser.timezone=UTC", + "-Dojp.server.port=$ojpPort", + "-Dojp.prometheus.port=$ojpPrometheusPort", + "-Dojp.libs.path=$libsDir", + "-jar", + $jarPath + ) ` + -WorkingDirectory $serverDir ` + -WindowStyle Hidden ` + -RedirectStandardOutput $serverLogOut ` + -RedirectStandardError $serverLogErr ` + -PassThru + +try { + Write-Host "[6/8] Waiting for OJP gRPC server on :$ojpPort..." + Wait-OjpStarted + + Write-Host "[7/8] Running Go CRUD app against DB2..." + Push-Location $clientDir + try { + $env:OJP_JDBC_LINE = "jdbc:ojp[localhost:$ojpPort]_db2://${dbHost}:${dbPort}/${dbName},${dbUser},${dbPassword}" + go run ./cmd/ojp-grpc-client + } + finally { + Pop-Location + Remove-Item Env:OJP_JDBC_LINE -ErrorAction SilentlyContinue + } + + Write-Host "[8/8] DB2 + OJP CRUD run completed successfully. Bringing compose down..." + docker compose -f $composeFile down | Out-Null +} +finally { + Remove-Item Env:DB2_HOST_PORT -ErrorAction SilentlyContinue + if ($serverProcess -and -not $serverProcess.HasExited) { + Stop-Process -Id $serverProcess.Id -Force + } +} diff --git a/ojp-grpc-client-go/scripts/run-db2-crud-test.sh b/ojp-grpc-client-go/scripts/run-db2-crud-test.sh new file mode 100644 index 000000000..4f9dd8519 --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-db2-crud-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PS1_SCRIPT="${SCRIPT_DIR}/run-db2-crud-test.ps1" + +if ! command -v powershell.exe >/dev/null 2>&1; then + echo "powershell.exe is required for this wrapper script." + exit 1 +fi + +if command -v wslpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" +elif command -v cygpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" +else + PS1_SCRIPT_WIN="${PS1_SCRIPT}" +fi + +powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-mariadb-crud-test.ps1 b/ojp-grpc-client-go/scripts/run-mariadb-crud-test.ps1 new file mode 100644 index 000000000..473009714 --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mariadb-crud-test.ps1 @@ -0,0 +1,125 @@ +param( + [switch]$SkipBuild +) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$clientDir = Split-Path -Parent $scriptDir +$repoRoot = Split-Path -Parent $clientDir +$serverDir = Join-Path $repoRoot "ojp-server" +$composeFile = Join-Path $clientDir "docker-compose.mariadb.yml" +$runStamp = Get-Date -Format "yyyyMMdd-HHmmss" +$serverLogOut = Join-Path $clientDir ".ojp-server-mariadb.$runStamp.out.log" +$serverLogErr = Join-Path $clientDir ".ojp-server-mariadb.$runStamp.err.log" + +$dbUser = "testuser" +$dbPassword = "testpassword" +$dbName = "testdb" +$dbHost = "localhost" +$dbPort = "3307" + +function Get-FreeTcpPort { + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) + $listener.Start() + $port = ($listener.LocalEndpoint).Port + $listener.Stop() + return [string]$port +} + +$ojpPort = Get-FreeTcpPort +$ojpPrometheusPort = Get-FreeTcpPort + +function Wait-MariaDbHealthy { + param([int]$MaxAttempts = 60, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + $status = docker inspect -f '{{.State.Health.Status}}' ojp-mariadb 2>$null + if ($status -eq "healthy") { return } + Start-Sleep -Seconds $SleepSeconds + } + throw "MariaDB container did not become healthy in time." +} + +function Wait-OjpStarted { + param([int]$MaxAttempts = 120, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + if (Test-Path $serverLogOut) { + $tail = Get-Content $serverLogOut -Tail 120 -ErrorAction SilentlyContinue + if ($tail -match "OJP gRPC Server started successfully") { return } + } + Start-Sleep -Seconds $SleepSeconds + } + throw "OJP server did not start in time. Check $serverLogOut and $serverLogErr" +} + +Write-Host "[1/8] Starting MariaDB via docker compose..." +docker compose -f $composeFile up -d | Out-Null + +Write-Host "[2/8] Waiting for MariaDB health..." +Wait-MariaDbHealthy + +Write-Host "[3/8] Ensuring MariaDB JDBC driver in ojp-server/ojp-libs..." +$libsDir = Join-Path $serverDir "ojp-libs" +New-Item -ItemType Directory -Force -Path $libsDir | Out-Null +$mariaDriver = Get-ChildItem -Path $libsDir -Filter "mariadb-java-client-*.jar" -ErrorAction SilentlyContinue | Select-Object -First 1 +if (-not $mariaDriver) { + $driverTarget = Join-Path $libsDir "mariadb-java-client-3.5.3.jar" + Invoke-WebRequest -Uri "https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/3.5.3/mariadb-java-client-3.5.3.jar" -OutFile $driverTarget +} + +if (-not $SkipBuild) { + Write-Host "[4/8] Building OJP modules needed by server..." + Push-Location $repoRoot + try { + mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" + } + finally { + Pop-Location + } +} else { + Write-Host "[4/8] Skipping build (-SkipBuild)." +} + +Write-Host "[5/8] Starting OJP server..." +$jarPath = Join-Path $serverDir "target\ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if (-not (Test-Path $jarPath)) { + throw "Missing server jar: $jarPath" +} +$serverProcess = Start-Process -FilePath "java" ` + -ArgumentList @( + "-Duser.timezone=UTC", + "-Dojp.server.port=$ojpPort", + "-Dojp.prometheus.port=$ojpPrometheusPort", + "-Dojp.libs.path=$libsDir", + "-jar", + $jarPath + ) ` + -WorkingDirectory $serverDir ` + -WindowStyle Hidden ` + -RedirectStandardOutput $serverLogOut ` + -RedirectStandardError $serverLogErr ` + -PassThru + +try { + Write-Host "[6/8] Waiting for OJP gRPC server on :$ojpPort..." + Wait-OjpStarted + + Write-Host "[7/8] Running Go CRUD app against MariaDB testdb..." + Push-Location $clientDir + try { + $env:OJP_JDBC_LINE = "jdbc:ojp[localhost:$ojpPort]_mariadb://${dbHost}:${dbPort}/${dbName},${dbUser},${dbPassword}" + go run ./cmd/ojp-grpc-client + } + finally { + Pop-Location + Remove-Item Env:OJP_JDBC_LINE -ErrorAction SilentlyContinue + } + + Write-Host "[8/8] MariaDB + OJP CRUD run completed successfully. Bringing compose down..." + docker compose -f $composeFile down | Out-Null +} +finally { + if ($serverProcess -and -not $serverProcess.HasExited) { + Stop-Process -Id $serverProcess.Id -Force + } +} diff --git a/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh b/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh new file mode 100644 index 000000000..98da92a77 --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PS1_SCRIPT="${SCRIPT_DIR}/run-mariadb-crud-test.ps1" + +if ! command -v powershell.exe >/dev/null 2>&1; then + echo "powershell.exe is required for this wrapper script." + exit 1 +fi + +if command -v wslpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" +elif command -v cygpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" +else + PS1_SCRIPT_WIN="${PS1_SCRIPT}" +fi + +powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-mssql-crud-test.ps1 b/ojp-grpc-client-go/scripts/run-mssql-crud-test.ps1 new file mode 100644 index 000000000..e488b877d --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mssql-crud-test.ps1 @@ -0,0 +1,128 @@ +param( + [switch]$SkipBuild +) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$clientDir = Split-Path -Parent $scriptDir +$repoRoot = Split-Path -Parent $clientDir +$serverDir = Join-Path $repoRoot "ojp-server" +$composeFile = Join-Path $clientDir "docker-compose.mssql.yml" +$runStamp = Get-Date -Format "yyyyMMdd-HHmmss" +$serverLogOut = Join-Path $clientDir ".ojp-server-mssql.$runStamp.out.log" +$serverLogErr = Join-Path $clientDir ".ojp-server-mssql.$runStamp.err.log" + +$dbUser = "sa" +$dbPassword = "TestPassword123!" +$dbHost = "localhost" +$dbName = "tempdb" + +function Get-FreeTcpPort { + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) + $listener.Start() + $port = ($listener.LocalEndpoint).Port + $listener.Stop() + return [string]$port +} + +$ojpPort = Get-FreeTcpPort +$ojpPrometheusPort = Get-FreeTcpPort +$dbPort = Get-FreeTcpPort + +$env:MSSQL_HOST_PORT = $dbPort + +function Wait-MsSqlHealthy { + param([int]$MaxAttempts = 80, [int]$SleepSeconds = 3) + for ($i = 1; $i -le $MaxAttempts; $i++) { + $status = docker inspect -f '{{.State.Health.Status}}' ojp-mssql 2>$null + if ($status -eq "healthy") { return } + Start-Sleep -Seconds $SleepSeconds + } + throw "MSSQL container did not become healthy in time." +} + +function Wait-OjpStarted { + param([int]$MaxAttempts = 120, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + if (Test-Path $serverLogOut) { + $tail = Get-Content $serverLogOut -Tail 120 -ErrorAction SilentlyContinue + if ($tail -match "OJP gRPC Server started successfully") { return } + } + Start-Sleep -Seconds $SleepSeconds + } + throw "OJP server did not start in time. Check $serverLogOut and $serverLogErr" +} + +Write-Host "[1/8] Starting MSSQL via docker compose..." +docker compose -f $composeFile up -d | Out-Null + +Write-Host "[2/8] Waiting for MSSQL health..." +Wait-MsSqlHealthy + +Write-Host "[3/8] Ensuring MSSQL JDBC driver in ojp-server/ojp-libs..." +$libsDir = Join-Path $serverDir "ojp-libs" +New-Item -ItemType Directory -Force -Path $libsDir | Out-Null +$mssqlDriver = Get-ChildItem -Path $libsDir -Filter "mssql-jdbc-*.jar" -ErrorAction SilentlyContinue | Select-Object -First 1 +if (-not $mssqlDriver) { + $driverTarget = Join-Path $libsDir "mssql-jdbc-12.10.0.jre11.jar" + Invoke-WebRequest -Uri "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.10.0.jre11/mssql-jdbc-12.10.0.jre11.jar" -OutFile $driverTarget +} + +if (-not $SkipBuild) { + Write-Host "[4/8] Building OJP modules needed by server..." + Push-Location $repoRoot + try { + mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" + } + finally { + Pop-Location + } +} else { + Write-Host "[4/8] Skipping build (-SkipBuild)." +} + +Write-Host "[5/8] Starting OJP server..." +$jarPath = Join-Path $serverDir "target\ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if (-not (Test-Path $jarPath)) { + throw "Missing server jar: $jarPath" +} +$serverProcess = Start-Process -FilePath "java" ` + -ArgumentList @( + "-Duser.timezone=UTC", + "-Dojp.server.port=$ojpPort", + "-Dojp.prometheus.port=$ojpPrometheusPort", + "-Dojp.libs.path=$libsDir", + "-jar", + $jarPath + ) ` + -WorkingDirectory $serverDir ` + -WindowStyle Hidden ` + -RedirectStandardOutput $serverLogOut ` + -RedirectStandardError $serverLogErr ` + -PassThru + +try { + Write-Host "[6/8] Waiting for OJP gRPC server on :$ojpPort..." + Wait-OjpStarted + + Write-Host "[7/8] Running Go CRUD app against MSSQL..." + Push-Location $clientDir + try { + $env:OJP_JDBC_LINE = "jdbc:ojp[localhost:$ojpPort]_sqlserver://${dbHost}:${dbPort};databaseName=${dbName};encrypt=false;trustServerCertificate=true,${dbUser},${dbPassword}" + go run ./cmd/ojp-grpc-client + } + finally { + Pop-Location + Remove-Item Env:OJP_JDBC_LINE -ErrorAction SilentlyContinue + } + + Write-Host "[8/8] MSSQL + OJP CRUD run completed successfully. Bringing compose down..." + docker compose -f $composeFile down | Out-Null +} +finally { + Remove-Item Env:MSSQL_HOST_PORT -ErrorAction SilentlyContinue + if ($serverProcess -and -not $serverProcess.HasExited) { + Stop-Process -Id $serverProcess.Id -Force + } +} diff --git a/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh b/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh new file mode 100644 index 000000000..059442bec --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PS1_SCRIPT="${SCRIPT_DIR}/run-mssql-crud-test.ps1" + +if ! command -v powershell.exe >/dev/null 2>&1; then + echo "powershell.exe is required for this wrapper script." + exit 1 +fi + +if command -v wslpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" +elif command -v cygpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" +else + PS1_SCRIPT_WIN="${PS1_SCRIPT}" +fi + +powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-mysql-crud-test.ps1 b/ojp-grpc-client-go/scripts/run-mysql-crud-test.ps1 new file mode 100644 index 000000000..37b0402aa --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mysql-crud-test.ps1 @@ -0,0 +1,125 @@ +param( + [switch]$SkipBuild +) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$clientDir = Split-Path -Parent $scriptDir +$repoRoot = Split-Path -Parent $clientDir +$serverDir = Join-Path $repoRoot "ojp-server" +$composeFile = Join-Path $clientDir "docker-compose.mysql.yml" +$runStamp = Get-Date -Format "yyyyMMdd-HHmmss" +$serverLogOut = Join-Path $clientDir ".ojp-server-mysql.$runStamp.out.log" +$serverLogErr = Join-Path $clientDir ".ojp-server-mysql.$runStamp.err.log" + +$dbUser = "testuser" +$dbPassword = "testpassword" +$dbName = "testdb" +$dbHost = "localhost" +$dbPort = "3306" + +function Get-FreeTcpPort { + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) + $listener.Start() + $port = ($listener.LocalEndpoint).Port + $listener.Stop() + return [string]$port +} + +$ojpPort = Get-FreeTcpPort +$ojpPrometheusPort = Get-FreeTcpPort + +function Wait-MySqlHealthy { + param([int]$MaxAttempts = 60, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + $status = docker inspect -f '{{.State.Health.Status}}' ojp-mysql 2>$null + if ($status -eq "healthy") { return } + Start-Sleep -Seconds $SleepSeconds + } + throw "MySQL container did not become healthy in time." +} + +function Wait-OjpStarted { + param([int]$MaxAttempts = 120, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + if (Test-Path $serverLogOut) { + $tail = Get-Content $serverLogOut -Tail 120 -ErrorAction SilentlyContinue + if ($tail -match "OJP gRPC Server started successfully") { return } + } + Start-Sleep -Seconds $SleepSeconds + } + throw "OJP server did not start in time. Check $serverLogOut and $serverLogErr" +} + +Write-Host "[1/8] Starting MySQL via docker compose..." +docker compose -f $composeFile up -d | Out-Null + +Write-Host "[2/8] Waiting for MySQL health..." +Wait-MySqlHealthy + +Write-Host "[3/8] Ensuring MySQL JDBC driver in ojp-server/ojp-libs..." +$libsDir = Join-Path $serverDir "ojp-libs" +New-Item -ItemType Directory -Force -Path $libsDir | Out-Null +$mysqlDriver = Get-ChildItem -Path $libsDir -Filter "mysql-connector-j-*.jar" -ErrorAction SilentlyContinue | Select-Object -First 1 +if (-not $mysqlDriver) { + $driverTarget = Join-Path $libsDir "mysql-connector-j-9.3.0.jar" + Invoke-WebRequest -Uri "https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/9.3.0/mysql-connector-j-9.3.0.jar" -OutFile $driverTarget +} + +if (-not $SkipBuild) { + Write-Host "[4/8] Building OJP modules needed by server..." + Push-Location $repoRoot + try { + mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" + } + finally { + Pop-Location + } +} else { + Write-Host "[4/8] Skipping build (-SkipBuild)." +} + +Write-Host "[5/8] Starting OJP server..." +$jarPath = Join-Path $serverDir "target\ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if (-not (Test-Path $jarPath)) { + throw "Missing server jar: $jarPath" +} +$serverProcess = Start-Process -FilePath "java" ` + -ArgumentList @( + "-Duser.timezone=UTC", + "-Dojp.server.port=$ojpPort", + "-Dojp.prometheus.port=$ojpPrometheusPort", + "-Dojp.libs.path=$libsDir", + "-jar", + $jarPath + ) ` + -WorkingDirectory $serverDir ` + -WindowStyle Hidden ` + -RedirectStandardOutput $serverLogOut ` + -RedirectStandardError $serverLogErr ` + -PassThru + +try { + Write-Host "[6/8] Waiting for OJP gRPC server on :$ojpPort..." + Wait-OjpStarted + + Write-Host "[7/8] Running Go CRUD app against MySQL testdb..." + Push-Location $clientDir + try { + $env:OJP_JDBC_LINE = "jdbc:ojp[localhost:$ojpPort]_mysql://${dbHost}:${dbPort}/${dbName},${dbUser},${dbPassword}" + go run ./cmd/ojp-grpc-client + } + finally { + Pop-Location + Remove-Item Env:OJP_JDBC_LINE -ErrorAction SilentlyContinue + } + + Write-Host "[8/8] MySQL + OJP CRUD run completed successfully. Bringing compose down..." + docker compose -f $composeFile down | Out-Null +} +finally { + if ($serverProcess -and -not $serverProcess.HasExited) { + Stop-Process -Id $serverProcess.Id -Force + } +} diff --git a/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh b/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh new file mode 100644 index 000000000..783287017 --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PS1_SCRIPT="${SCRIPT_DIR}/run-mysql-crud-test.ps1" + +if ! command -v powershell.exe >/dev/null 2>&1; then + echo "powershell.exe is required for this wrapper script." + exit 1 +fi + +if command -v wslpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" +elif command -v cygpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" +else + PS1_SCRIPT_WIN="${PS1_SCRIPT}" +fi + +powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-oracle-crud-test.ps1 b/ojp-grpc-client-go/scripts/run-oracle-crud-test.ps1 new file mode 100644 index 000000000..87cfccfda --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-oracle-crud-test.ps1 @@ -0,0 +1,128 @@ +param( + [switch]$SkipBuild +) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$clientDir = Split-Path -Parent $scriptDir +$repoRoot = Split-Path -Parent $clientDir +$serverDir = Join-Path $repoRoot "ojp-server" +$composeFile = Join-Path $clientDir "docker-compose.oracle.yml" +$runStamp = Get-Date -Format "yyyyMMdd-HHmmss" +$serverLogOut = Join-Path $clientDir ".ojp-server-oracle.$runStamp.out.log" +$serverLogErr = Join-Path $clientDir ".ojp-server-oracle.$runStamp.err.log" + +$dbUser = "testuser" +$dbPassword = "testpassword" +$dbHost = "localhost" +$dbService = "XEPDB1" + +function Get-FreeTcpPort { + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) + $listener.Start() + $port = ($listener.LocalEndpoint).Port + $listener.Stop() + return [string]$port +} + +$ojpPort = Get-FreeTcpPort +$ojpPrometheusPort = Get-FreeTcpPort +$dbPort = Get-FreeTcpPort + +$env:ORACLE_HOST_PORT = $dbPort + +function Wait-OracleHealthy { + param([int]$MaxAttempts = 90, [int]$SleepSeconds = 4) + for ($i = 1; $i -le $MaxAttempts; $i++) { + $status = docker inspect -f '{{.State.Health.Status}}' ojp-oracle 2>$null + if ($status -eq "healthy") { return } + Start-Sleep -Seconds $SleepSeconds + } + throw "Oracle container did not become healthy in time." +} + +function Wait-OjpStarted { + param([int]$MaxAttempts = 120, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + if (Test-Path $serverLogOut) { + $tail = Get-Content $serverLogOut -Tail 120 -ErrorAction SilentlyContinue + if ($tail -match "OJP gRPC Server started successfully") { return } + } + Start-Sleep -Seconds $SleepSeconds + } + throw "OJP server did not start in time. Check $serverLogOut and $serverLogErr" +} + +Write-Host "[1/8] Starting Oracle XE via docker compose..." +docker compose -f $composeFile up -d | Out-Null + +Write-Host "[2/8] Waiting for Oracle health..." +Wait-OracleHealthy + +Write-Host "[3/8] Ensuring Oracle JDBC driver in ojp-server/ojp-libs..." +$libsDir = Join-Path $serverDir "ojp-libs" +New-Item -ItemType Directory -Force -Path $libsDir | Out-Null +$oracleDriver = Get-ChildItem -Path $libsDir -Filter "ojdbc*.jar" -ErrorAction SilentlyContinue | Select-Object -First 1 +if (-not $oracleDriver) { + $driverTarget = Join-Path $libsDir "ojdbc11-23.8.0.25.04.jar" + Invoke-WebRequest -Uri "https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc11/23.8.0.25.04/ojdbc11-23.8.0.25.04.jar" -OutFile $driverTarget +} + +if (-not $SkipBuild) { + Write-Host "[4/8] Building OJP modules needed by server..." + Push-Location $repoRoot + try { + mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" + } + finally { + Pop-Location + } +} else { + Write-Host "[4/8] Skipping build (-SkipBuild)." +} + +Write-Host "[5/8] Starting OJP server..." +$jarPath = Join-Path $serverDir "target\ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if (-not (Test-Path $jarPath)) { + throw "Missing server jar: $jarPath" +} +$serverProcess = Start-Process -FilePath "java" ` + -ArgumentList @( + "-Duser.timezone=UTC", + "-Dojp.server.port=$ojpPort", + "-Dojp.prometheus.port=$ojpPrometheusPort", + "-Dojp.libs.path=$libsDir", + "-jar", + $jarPath + ) ` + -WorkingDirectory $serverDir ` + -WindowStyle Hidden ` + -RedirectStandardOutput $serverLogOut ` + -RedirectStandardError $serverLogErr ` + -PassThru + +try { + Write-Host "[6/8] Waiting for OJP gRPC server on :$ojpPort..." + Wait-OjpStarted + + Write-Host "[7/8] Running Go CRUD app against Oracle..." + Push-Location $clientDir + try { + $env:OJP_JDBC_LINE = "jdbc:ojp[localhost:$ojpPort]_oracle:thin:@${dbHost}:${dbPort}/${dbService},${dbUser},${dbPassword}" + go run ./cmd/ojp-grpc-client + } + finally { + Pop-Location + Remove-Item Env:OJP_JDBC_LINE -ErrorAction SilentlyContinue + } + + Write-Host "[8/8] Oracle + OJP CRUD run completed successfully. Bringing compose down..." + docker compose -f $composeFile down | Out-Null +} +finally { + Remove-Item Env:ORACLE_HOST_PORT -ErrorAction SilentlyContinue + if ($serverProcess -and -not $serverProcess.HasExited) { + Stop-Process -Id $serverProcess.Id -Force + } +} diff --git a/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh b/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh new file mode 100644 index 000000000..bc9fc309f --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PS1_SCRIPT="${SCRIPT_DIR}/run-oracle-crud-test.ps1" + +if ! command -v powershell.exe >/dev/null 2>&1; then + echo "powershell.exe is required for this wrapper script." + exit 1 +fi + +if command -v wslpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" +elif command -v cygpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" +else + PS1_SCRIPT_WIN="${PS1_SCRIPT}" +fi + +powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-postgres18-crud-test.ps1 b/ojp-grpc-client-go/scripts/run-postgres18-crud-test.ps1 new file mode 100644 index 000000000..047e1885f --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-postgres18-crud-test.ps1 @@ -0,0 +1,124 @@ +param( + [switch]$SkipBuild +) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$clientDir = Split-Path -Parent $scriptDir +$repoRoot = Split-Path -Parent $clientDir +$serverDir = Join-Path $repoRoot "ojp-server" +$composeFile = Join-Path $clientDir "docker-compose.postgres18.yml" +$runStamp = Get-Date -Format "yyyyMMdd-HHmmss" +$serverLogOut = Join-Path $clientDir ".ojp-server-postgres18.$runStamp.out.log" +$serverLogErr = Join-Path $clientDir ".ojp-server-postgres18.$runStamp.err.log" + +$postgresUser = "testuser" +$postgresPassword = "testpassword" +$postgresDb = "testdb" +$postgresHost = "localhost" +$postgresPort = "5432" +function Get-FreeTcpPort { + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) + $listener.Start() + $port = ($listener.LocalEndpoint).Port + $listener.Stop() + return [string]$port +} + +$ojpPort = Get-FreeTcpPort +$ojpPrometheusPort = Get-FreeTcpPort + +function Wait-PostgresHealthy { + param([int]$MaxAttempts = 60, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + $status = docker inspect -f '{{.State.Health.Status}}' ojp-postgres18 2>$null + if ($status -eq "healthy") { return } + Start-Sleep -Seconds $SleepSeconds + } + throw "PostgreSQL container did not become healthy in time." +} + +function Wait-OjpStarted { + param([int]$MaxAttempts = 120, [int]$SleepSeconds = 2) + for ($i = 1; $i -le $MaxAttempts; $i++) { + if (Test-Path $serverLogOut) { + $tail = Get-Content $serverLogOut -Tail 120 -ErrorAction SilentlyContinue + if ($tail -match "OJP gRPC Server started successfully") { return } + } + Start-Sleep -Seconds $SleepSeconds + } + throw "OJP server did not start in time. Check $serverLogOut and $serverLogErr" +} + +Write-Host "[1/8] Starting PostgreSQL 18 via docker compose..." +docker compose -f $composeFile up -d | Out-Null + +Write-Host "[2/8] Waiting for PostgreSQL health..." +Wait-PostgresHealthy + +Write-Host "[3/8] Ensuring PostgreSQL JDBC driver in ojp-server/ojp-libs..." +$libsDir = Join-Path $serverDir "ojp-libs" +New-Item -ItemType Directory -Force -Path $libsDir | Out-Null +$pgDriver = Get-ChildItem -Path $libsDir -Filter "postgresql-*.jar" -ErrorAction SilentlyContinue | Select-Object -First 1 +if (-not $pgDriver) { + $driverTarget = Join-Path $libsDir "postgresql-42.7.8.jar" + Invoke-WebRequest -Uri "https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.8/postgresql-42.7.8.jar" -OutFile $driverTarget +} + +if (-not $SkipBuild) { + Write-Host "[4/8] Building OJP modules needed by server..." + Push-Location $repoRoot + try { + mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" + } + finally { + Pop-Location + } +} else { + Write-Host "[4/8] Skipping build (-SkipBuild)." +} + +Write-Host "[5/8] Starting OJP server..." +$jarPath = Join-Path $serverDir "target\ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if (-not (Test-Path $jarPath)) { + throw "Missing server jar: $jarPath" +} +$serverProcess = Start-Process -FilePath "java" ` + -ArgumentList @( + "-Duser.timezone=UTC", + "-Dojp.server.port=$ojpPort", + "-Dojp.prometheus.port=$ojpPrometheusPort", + "-Dojp.libs.path=$libsDir", + "-jar", + $jarPath + ) ` + -WorkingDirectory $serverDir ` + -WindowStyle Hidden ` + -RedirectStandardOutput $serverLogOut ` + -RedirectStandardError $serverLogErr ` + -PassThru + +try { + Write-Host "[6/8] Waiting for OJP gRPC server on :$ojpPort..." + Wait-OjpStarted + + Write-Host "[7/8] Running Go CRUD app against PostgreSQL testdb..." + Push-Location $clientDir + try { + $env:OJP_JDBC_LINE = "jdbc:ojp[localhost:$ojpPort]_postgresql://${postgresHost}:${postgresPort}/${postgresDb},${postgresUser},${postgresPassword}" + go run ./cmd/ojp-grpc-client + } + finally { + Pop-Location + Remove-Item Env:OJP_JDBC_LINE -ErrorAction SilentlyContinue + } + + Write-Host "[8/8] PostgreSQL 18 + OJP CRUD run completed successfully. Bringing compose down..." + docker compose -f $composeFile down | Out-Null +} +finally { + if ($serverProcess -and -not $serverProcess.HasExited) { + Stop-Process -Id $serverProcess.Id -Force + } +} diff --git a/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh b/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh new file mode 100644 index 000000000..6d17928cd --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PS1_SCRIPT="${SCRIPT_DIR}/run-postgres18-crud-test.ps1" + +if ! command -v powershell.exe >/dev/null 2>&1; then + echo "powershell.exe is required for this wrapper script." + exit 1 +fi + +if command -v wslpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" +elif command -v cygpath >/dev/null 2>&1; then + PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" +else + PS1_SCRIPT_WIN="${PS1_SCRIPT}" +fi + +powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" + diff --git a/ojp-grpc-client-go/testdata/connection.csv b/ojp-grpc-client-go/testdata/connection.csv new file mode 100644 index 000000000..4ef695f10 --- /dev/null +++ b/ojp-grpc-client-go/testdata/connection.csv @@ -0,0 +1,10 @@ +jdbc:ojp[localhost:1059]_h2:~/test,sa, +jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword +jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword +jdbc:ojp[localhost:1059]_mysql://localhost:3306/defaultdb,testuser,testpassword +jdbc:ojp[localhost:1059]_mariadb://localhost:3307/defaultdb,testuser,testpassword +jdbc:ojp[localhost:1059]_oracle:thin:@localhost:1521/XEPDB1,testuser,testpassword +jdbc:ojp[localhost:1059]_sqlserver://localhost:1433;databaseName=defaultdb;encrypt=false;trustServerCertificate=true,testuser,TestPassword123! +jdbc:ojp[localhost:1059]_sqlserver://localhost:1433;databaseName=defaultdb;encrypt=false;trustServerCertificate=true,testuser,TestPassword123! +jdbc:ojp[localhost:1059]_db2://localhost:50000/testdb,db2inst1,testpass +jdbc:ojp[localhost:1059]_postgresql://localhost:26257/defaultdb?sslmode=disable,root, \ No newline at end of file diff --git a/ojp-grpc-client-go/testdata/mariadb/init/01-init.sql b/ojp-grpc-client-go/testdata/mariadb/init/01-init.sql new file mode 100644 index 000000000..98bcac497 --- /dev/null +++ b/ojp-grpc-client-go/testdata/mariadb/init/01-init.sql @@ -0,0 +1 @@ +CREATE DATABASE IF NOT EXISTS testdb; diff --git a/ojp-grpc-client-go/testdata/mysql/init/01-init.sql b/ojp-grpc-client-go/testdata/mysql/init/01-init.sql new file mode 100644 index 000000000..98bcac497 --- /dev/null +++ b/ojp-grpc-client-go/testdata/mysql/init/01-init.sql @@ -0,0 +1 @@ +CREATE DATABASE IF NOT EXISTS testdb; diff --git a/ojp-grpc-client-go/testdata/postgres/init/01-init.sql b/ojp-grpc-client-go/testdata/postgres/init/01-init.sql new file mode 100644 index 000000000..b3f9e5e48 --- /dev/null +++ b/ojp-grpc-client-go/testdata/postgres/init/01-init.sql @@ -0,0 +1,11 @@ +-- Database is created by POSTGRES_DB=testdb. +-- Keep this script idempotent and lightweight for local integration tests. +CREATE TABLE IF NOT EXISTS compose_bootstrap_marker ( + id INT PRIMARY KEY, + note VARCHAR(64) NOT NULL +); + +INSERT INTO compose_bootstrap_marker (id, note) +VALUES (1, 'postgres18-ready') +ON CONFLICT (id) DO NOTHING; + diff --git a/tools/client-generation/example/go/go.mod b/tools/client-generation/example/go/go.mod deleted file mode 100644 index cc1b3f775..000000000 --- a/tools/client-generation/example/go/go.mod +++ /dev/null @@ -1,18 +0,0 @@ -module github.com/ojp-client - -go 1.22 - -require ( - google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 - google.golang.org/grpc v1.64.0 - google.golang.org/protobuf v1.33.0 -) - -require ( - golang.org/x/net v0.22.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect -) - -replace github.com/open-j-proxy/ojp-client => ../ diff --git a/tools/client-generation/example/go/go.sum b/tools/client-generation/example/go/go.sum deleted file mode 100644 index 2e0adb7be..000000000 --- a/tools/client-generation/example/go/go.sum +++ /dev/null @@ -1,16 +0,0 @@ -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237 h1:PgNlNSx2Nq2/j4juYzQBG0/Zdr+WP4z5N01Vk4VYBCY= -google.golang.org/genproto v0.0.0-20240318140521-94a12d6c2237/go.mod h1:9sVD8c25Af3p0rGs7S7LLsxWKFiJt/65LdSyqXBkX/Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/tools/client-generation/example/go/main.go b/tools/client-generation/example/go/main.go deleted file mode 100644 index e848e16ec..000000000 --- a/tools/client-generation/example/go/main.go +++ /dev/null @@ -1,498 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - "os" - "sync" - "time" - - "github.com/ojp-client/gen/go/com/openjproxy/grpc" - "github.com/ojp-client/pkg/client" -) - -func main() { - log.SetFlags(log.LstdFlags | log.Lshortfile) - - log.Println("=== Test 1: Round-robin load balancing ===") - testRoundRobin() - - log.Println("\n=== Test 2: Session stickiness ===") - testSessionStickiness() - - log.Println("\n=== Test 3: Health check failure detection ===") - testHealthCheck() - - log.Println("\n=== Test 4: Concurrent connections ===") - testConcurrentConnections() - - log.Println("\n=== Test 5: Transaction support ===") - testTransactions() - - log.Println("\n=== Test 6: XA Transaction support ===") - testXA() - - log.Println("\n=== Test 7: Load metric tracking ===") - testLoadMetrics() - - log.Println("\n=== All tests passed! ===") -} - -func env(name, fallback string) string { - if v := os.Getenv(name); v != "" { - return v - } - return fallback -} - -func testRoundRobin() { - healthConfig := client.DefaultHealthCheckConfig() - - connManager, err := client.NewMultinodeConnectionManager([]string{ - "127.0.0.1:1059", - "127.0.0.1:1060", - }, healthConfig) - if err != nil { - log.Fatalf("Failed to create connection manager: %v", err) - } - defer connManager.Shutdown() - - service := client.NewMultinodeStatementService(connManager) - defer service.Shutdown() - - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") - details := &grpc.ConnectionDetails{ - Url: backendURL, - User: env("OJP_DB_USER", "ojp"), - Password: env("OJP_DB_PASSWORD", "ojp"), - ClientUUID: "test-roundrobin", - } - - session, err := service.Connect(context.Background(), details) - if err != nil { - log.Fatalf("Connect failed: %v", err) - } - log.Printf("Connected! Session: %s", session.GetSessionUUID()) - - _, err = service.ExecuteUpdate(context.Background(), session, "CREATE TABLE IF NOT EXISTS test_rr(id INT PRIMARY KEY, server VARCHAR(100))") - if err != nil { - log.Fatalf("Create table failed: %v", err) - } - - for i := 0; i < 4; i++ { - sql := fmt.Sprintf("INSERT INTO test_rr(id, server) VALUES (%d, 'server-%d') ON CONFLICT (id) DO UPDATE SET server = EXCLUDED.server", i, i%2) - _, err = service.ExecuteUpdate(context.Background(), session, sql) - if err != nil { - log.Printf("Insert %d failed: %v", i, err) - } - } - - results, err := service.ExecuteQuery(context.Background(), session, "SELECT id, server FROM test_rr ORDER BY id") - if err != nil { - log.Fatalf("Query failed: %v", err) - } - log.Printf("Got %d results from round-robin inserts", len(results)) - - service.TerminateSession(context.Background(), session) - log.Printf("Round-robin test completed") -} - -func testSessionStickiness() { - healthConfig := client.DefaultHealthCheckConfig() - - connManager, err := client.NewMultinodeConnectionManager([]string{ - "127.0.0.1:1059", - "127.0.0.1:1060", - }, healthConfig) - if err != nil { - log.Fatalf("Failed to create connection manager: %v", err) - } - defer connManager.Shutdown() - - service := client.NewMultinodeStatementService(connManager) - defer service.Shutdown() - - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") - details := &grpc.ConnectionDetails{ - Url: backendURL, - User: env("OJP_DB_USER", "ojp"), - Password: env("OJP_DB_PASSWORD", "ojp"), - ClientUUID: "test-sticky", - } - - session, err := service.Connect(context.Background(), details) - if err != nil { - log.Fatalf("Connect failed: %v", err) - } - log.Printf("Connected! Session: %s", session.GetSessionUUID()) - - _, err = service.ExecuteUpdate(context.Background(), session, "CREATE TABLE IF NOT EXISTS test_sticky(id INT PRIMARY KEY, data VARCHAR(100))") - if err != nil { - log.Fatalf("Create table failed: %v", err) - } - - for i := 0; i < 5; i++ { - sql := fmt.Sprintf("INSERT INTO test_sticky(id, data) VALUES (%d, 'sticky-%d') ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data", i, i) - _, err = service.ExecuteUpdate(context.Background(), session, sql) - if err != nil { - log.Printf("Insert %d failed: %v", i, err) - } - } - - endpoints := connManager.GetServerEndpoints() - log.Printf("Server endpoints: %v", endpoints) - - for _, ep := range endpoints { - log.Printf(" Endpoint %s: healthy=%v, connCount=%d", ep.Address(), ep.IsHealthy(), ep.ConnectionCount()) - } - - service.TerminateSession(context.Background(), session) - log.Printf("Session stickiness test completed") -} - -func testHealthCheck() { - healthConfig := client.LoadHealthCheckConfig(map[string]string{ - "ojp.health.check.interval": "3000", - "ojp.health.check.timeout": "2000", - }) - - connManager, err := client.NewMultinodeConnectionManager([]string{ - "127.0.0.1:1059", - "127.0.0.1:1060", - }, healthConfig) - if err != nil { - log.Fatalf("Failed to create connection manager: %v", err) - } - defer connManager.Shutdown() - - connManager.StartHealthChecks() - log.Printf("Health checks started") - - time.Sleep(1 * time.Second) - - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") - details := &grpc.ConnectionDetails{ - Url: backendURL, - User: env("OJP_DB_USER", "ojp"), - Password: env("OJP_DB_PASSWORD", "ojp"), - ClientUUID: "test-health", - } - - service := client.NewMultinodeStatementService(connManager) - defer service.Shutdown() - - session, err := service.Connect(context.Background(), details) - if err != nil { - log.Fatalf("Connect failed: %v", err) - } - log.Printf("Connected! Session: %s", session.GetSessionUUID()) - - time.Sleep(2 * time.Second) - - clusterHealth := connManager.GenerateClusterHealth() - log.Printf("Cluster health: %s", clusterHealth) - - for _, ep := range connManager.GetServerEndpoints() { - log.Printf(" Endpoint %s: healthy=%v", ep.Address(), ep.IsHealthy()) - } - - service.TerminateSession(context.Background(), session) - log.Printf("Health check test completed") -} - -func testConcurrentConnections() { - healthConfig := client.DefaultHealthCheckConfig() - - connManager, err := client.NewMultinodeConnectionManager([]string{ - "127.0.0.1:1059", - "127.0.0.1:1060", - }, healthConfig) - if err != nil { - log.Fatalf("Failed to create connection manager: %v", err) - } - defer connManager.Shutdown() - - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") - - var wg sync.WaitGroup - results := make(chan string, 10) - - for i := 0; i < 5; i++ { - wg.Add(1) - go func(idx int) { - defer wg.Done() - - service := client.NewMultinodeStatementService(connManager) - details := &grpc.ConnectionDetails{ - Url: backendURL, - User: env("OJP_DB_USER", "ojp"), - Password: env("OJP_DB_PASSWORD", "ojp"), - ClientUUID: fmt.Sprintf("test-concurrent-%d", idx), - } - - var session *grpc.SessionInfo - var err error - for attempt := 0; attempt < 3; attempt++ { - session, err = service.Connect(context.Background(), details) - if err == nil { - break - } - log.Printf("Connect attempt %d failed: %v, retrying...", attempt+1, err) - time.Sleep(500 * time.Millisecond) - } - if err != nil { - results <- fmt.Sprintf("goroutine %d: connect failed after retries: %v", idx, err) - return - } - - sql := fmt.Sprintf("SELECT %d as result", idx*100) - qResults, err := service.ExecuteQuery(context.Background(), session, sql) - if err != nil { - results <- fmt.Sprintf("goroutine %d: query failed: %v", idx, err) - } else { - results <- fmt.Sprintf("goroutine %d: got %d results", idx, len(qResults)) - } - - service.TerminateSession(context.Background(), session) - }(i) - } - - wg.Wait() - close(results) - - log.Printf("Concurrent connection results:") - for r := range results { - log.Printf(" %s", r) - } - - log.Printf("Concurrent test completed") -} - -func testTransactions() { - healthConfig := client.DefaultHealthCheckConfig() - - connManager, err := client.NewMultinodeConnectionManager([]string{ - "127.0.0.1:1059", - }, healthConfig) - if err != nil { - log.Fatalf("Failed to create connection manager: %v", err) - } - defer connManager.Shutdown() - - service := client.NewMultinodeStatementService(connManager) - defer service.Shutdown() - - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") - details := &grpc.ConnectionDetails{ - Url: backendURL, - User: env("OJP_DB_USER", "ojp"), - Password: env("OJP_DB_PASSWORD", "ojp"), - ClientUUID: "test-transaction", - } - - session, err := service.Connect(context.Background(), details) - if err != nil { - log.Fatalf("Connect failed: %v", err) - } - log.Printf("Connected! Session: %s", session.GetSessionUUID()) - - _, err = service.ExecuteUpdate(context.Background(), session, "CREATE TABLE IF NOT EXISTS test_txn(id INT PRIMARY KEY, value VARCHAR(100))") - if err != nil { - log.Fatalf("Create table failed: %v", err) - } - - sessionWithTXN, err := service.StartTransaction(context.Background(), session) - if err != nil { - log.Printf("StartTransaction not supported (OK): %v", err) - } else { - log.Printf("Transaction started! Session: %s", sessionWithTXN.GetSessionUUID()) - - _, err = service.ExecuteUpdate(context.Background(), sessionWithTXN, "INSERT INTO test_txn(id, value) VALUES (1, 'transactional')") - if err != nil { - log.Printf("Insert in transaction failed: %v", err) - } - - _, err = service.CommitTransaction(context.Background(), sessionWithTXN) - if err != nil { - log.Printf("Commit failed: %v", err) - } else { - log.Printf("Transaction committed!") - } - } - - results, err := service.ExecuteQuery(context.Background(), session, "SELECT id, value FROM test_txn WHERE id = 1") - if err != nil { - log.Printf("Query failed: %v", err) - } else if len(results) > 0 { - res := results[0] - if res.GetQueryResult() != nil && len(res.GetQueryResult().GetRows()) > 0 { - log.Printf("Verified committed data exists") - } - } - - service.TerminateSession(context.Background(), session) - log.Printf("Transaction test completed") -} - -func testXA() { - healthConfig := client.DefaultHealthCheckConfig() - - connManager, err := client.NewMultinodeConnectionManager([]string{ - "127.0.0.1:1059", - }, healthConfig) - if err != nil { - log.Fatalf("Failed to create connection manager: %v", err) - } - defer connManager.Shutdown() - - service := client.NewMultinodeStatementService(connManager) - defer service.Shutdown() - - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") - details := &grpc.ConnectionDetails{ - Url: backendURL, - User: env("OJP_DB_USER", "ojp"), - Password: env("OJP_DB_PASSWORD", "ojp"), - ClientUUID: "test-xa", - } - - session, err := service.Connect(context.Background(), details) - if err != nil { - log.Fatalf("Connect failed: %v", err) - } - log.Printf("Connected! Session: %s", session.GetSessionUUID()) - - xid := &grpc.XidProto{ - FormatId: 1, - GlobalTransactionId: []byte("test-xa-global"), - BranchQualifier: []byte("test-xa-branch"), - } - - resp, err := service.XAStart(context.Background(), xid, 0) - if err != nil { - log.Printf("XAStart failed (may not be supported): %v", err) - } else { - log.Printf("XAStart: success=%v", resp.GetSuccess()) - } - - _, err = service.ExecuteUpdate(context.Background(), session, "CREATE TABLE IF NOT EXISTS test_xa(id INT PRIMARY KEY, value VARCHAR(100))") - if err != nil { - log.Printf("Create table failed: %v", err) - } - - _, err = service.ExecuteUpdate(context.Background(), session, "INSERT INTO test_xa(id, value) VALUES (1, 'xa-test')") - if err != nil { - log.Printf("Insert failed: %v", err) - } - - resp, err = service.XAEnd(context.Background(), xid, 0) - if err != nil { - log.Printf("XAEnd failed: %v", err) - } else { - log.Printf("XAEnd: success=%v", resp.GetSuccess()) - } - - prepResp, err := service.XAPrepare(context.Background(), xid) - if err != nil { - log.Printf("XAPrepare failed: %v", err) - } else { - log.Printf("XAPrepare: result=%d", prepResp.GetResult()) - } - - commitResp, err := service.XACommit(context.Background(), xid, false) - if err != nil { - log.Printf("XACommit failed: %v", err) - } else { - log.Printf("XACommit: success=%v", commitResp.GetSuccess()) - } - - results, err := service.ExecuteQuery(context.Background(), session, "SELECT id, value FROM test_xa WHERE id = 1") - if err != nil { - log.Printf("Query after XA failed: %v", err) - } else if len(results) > 0 && results[0].GetQueryResult() != nil { - log.Printf("XA data persisted correctly") - } - - recoverResp, err := service.XARecover(context.Background(), 0) - if err != nil { - log.Printf("XARecover failed: %v", err) - } else { - log.Printf("XARecover: %d xids", len(recoverResp.GetXids())) - } - - forgetResp, err := service.XAForget(context.Background(), xid) - if err != nil { - log.Printf("XAForget failed: %v", err) - } else { - log.Printf("XAForget: success=%v", forgetResp.GetSuccess()) - } - - timeoutResp, err := service.XASetTransactionTimeout(context.Background(), 30) - if err != nil { - log.Printf("XASetTransactionTimeout failed: %v", err) - } else { - log.Printf("XASetTransactionTimeout: success=%v", timeoutResp.GetSuccess()) - } - - getTimeoutResp, err := service.XAGetTransactionTimeout(context.Background()) - if err != nil { - log.Printf("XAGetTransactionTimeout failed: %v", err) - } else { - log.Printf("XAGetTransactionTimeout: seconds=%d", getTimeoutResp.GetSeconds()) - } - - service.TerminateSession(context.Background(), session) - log.Printf("XA test completed") -} - -func testLoadMetrics() { - healthConfig := client.LoadHealthCheckConfig(map[string]string{ - "ojp.loadaware.selection.enabled": "true", - }) - - connManager, err := client.NewMultinodeConnectionManager([]string{ - "127.0.0.1:1059", - "127.0.0.1:1060", - }, healthConfig) - if err != nil { - log.Fatalf("Failed to create connection manager: %v", err) - } - defer connManager.Shutdown() - - service := client.NewMultinodeStatementService(connManager) - defer service.Shutdown() - - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://ojp-postgres:5432/ojp") - details := &grpc.ConnectionDetails{ - Url: backendURL, - User: env("OJP_DB_USER", "ojp"), - Password: env("OJP_DB_PASSWORD", "ojp"), - ClientUUID: "test-load", - } - - session, err := service.Connect(context.Background(), details) - if err != nil { - log.Fatalf("Connect failed: %v", err) - } - log.Printf("Connected! Session: %s", session.GetSessionUUID()) - - for i := 0; i < 3; i++ { - sql := fmt.Sprintf("SELECT * FROM generate_series(1, %d)", i*10) - results, err := service.ExecuteQuery(context.Background(), session, sql) - if err != nil { - log.Printf("Query %d failed: %v", i, err) - } else { - log.Printf("Query %d: %d results", i, len(results)) - } - } - - endpoints := connManager.GetServerEndpoints() - log.Printf("Load metrics after queries:") - for _, ep := range endpoints { - log.Printf(" %s: load_metric=%d", ep.Address(), ep.LoadMetric()) - } - - service.TerminateSession(context.Background(), session) - log.Printf("Load metrics test completed") -} \ No newline at end of file From b7f1e7341d7545c2166c33b7440044e2d7a2e080 Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Tue, 19 May 2026 18:37:45 +0200 Subject: [PATCH 07/12] remove old sh scripts --- .../scripts/run-db2-crud-test.sh | 20 ------------------ .../scripts/run-mariadb-crud-test.sh | 20 ------------------ .../scripts/run-mssql-crud-test.sh | 20 ------------------ .../scripts/run-mysql-crud-test.sh | 20 ------------------ .../scripts/run-oracle-crud-test.sh | 20 ------------------ .../scripts/run-postgres18-crud-test.sh | 21 ------------------- 6 files changed, 121 deletions(-) delete mode 100644 ojp-grpc-client-go/scripts/run-db2-crud-test.sh delete mode 100644 ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh delete mode 100644 ojp-grpc-client-go/scripts/run-mssql-crud-test.sh delete mode 100644 ojp-grpc-client-go/scripts/run-mysql-crud-test.sh delete mode 100644 ojp-grpc-client-go/scripts/run-oracle-crud-test.sh delete mode 100644 ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh diff --git a/ojp-grpc-client-go/scripts/run-db2-crud-test.sh b/ojp-grpc-client-go/scripts/run-db2-crud-test.sh deleted file mode 100644 index 4f9dd8519..000000000 --- a/ojp-grpc-client-go/scripts/run-db2-crud-test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PS1_SCRIPT="${SCRIPT_DIR}/run-db2-crud-test.ps1" - -if ! command -v powershell.exe >/dev/null 2>&1; then - echo "powershell.exe is required for this wrapper script." - exit 1 -fi - -if command -v wslpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" -elif command -v cygpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" -else - PS1_SCRIPT_WIN="${PS1_SCRIPT}" -fi - -powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh b/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh deleted file mode 100644 index 98da92a77..000000000 --- a/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PS1_SCRIPT="${SCRIPT_DIR}/run-mariadb-crud-test.ps1" - -if ! command -v powershell.exe >/dev/null 2>&1; then - echo "powershell.exe is required for this wrapper script." - exit 1 -fi - -if command -v wslpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" -elif command -v cygpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" -else - PS1_SCRIPT_WIN="${PS1_SCRIPT}" -fi - -powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh b/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh deleted file mode 100644 index 059442bec..000000000 --- a/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PS1_SCRIPT="${SCRIPT_DIR}/run-mssql-crud-test.ps1" - -if ! command -v powershell.exe >/dev/null 2>&1; then - echo "powershell.exe is required for this wrapper script." - exit 1 -fi - -if command -v wslpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" -elif command -v cygpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" -else - PS1_SCRIPT_WIN="${PS1_SCRIPT}" -fi - -powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh b/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh deleted file mode 100644 index 783287017..000000000 --- a/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PS1_SCRIPT="${SCRIPT_DIR}/run-mysql-crud-test.ps1" - -if ! command -v powershell.exe >/dev/null 2>&1; then - echo "powershell.exe is required for this wrapper script." - exit 1 -fi - -if command -v wslpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" -elif command -v cygpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" -else - PS1_SCRIPT_WIN="${PS1_SCRIPT}" -fi - -powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh b/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh deleted file mode 100644 index bc9fc309f..000000000 --- a/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PS1_SCRIPT="${SCRIPT_DIR}/run-oracle-crud-test.ps1" - -if ! command -v powershell.exe >/dev/null 2>&1; then - echo "powershell.exe is required for this wrapper script." - exit 1 -fi - -if command -v wslpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" -elif command -v cygpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" -else - PS1_SCRIPT_WIN="${PS1_SCRIPT}" -fi - -powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" diff --git a/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh b/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh deleted file mode 100644 index 6d17928cd..000000000 --- a/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PS1_SCRIPT="${SCRIPT_DIR}/run-postgres18-crud-test.ps1" - -if ! command -v powershell.exe >/dev/null 2>&1; then - echo "powershell.exe is required for this wrapper script." - exit 1 -fi - -if command -v wslpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(wslpath -w "${PS1_SCRIPT}")" -elif command -v cygpath >/dev/null 2>&1; then - PS1_SCRIPT_WIN="$(cygpath -w "${PS1_SCRIPT}")" -else - PS1_SCRIPT_WIN="${PS1_SCRIPT}" -fi - -powershell.exe -ExecutionPolicy Bypass -File "${PS1_SCRIPT_WIN}" "$@" - From 87a751b48c637795642a8d4388798ee9c92f6f2a Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Tue, 19 May 2026 20:01:19 +0200 Subject: [PATCH 08/12] adding new bash scripts --- .../cmd/ojp-grpc-client/main.go | 2 +- .../scripts/run-db2-crud-test.sh | 116 ++++++++++++++++++ .../scripts/run-mariadb-crud-test.sh | 113 +++++++++++++++++ .../scripts/run-mssql-crud-test.sh | 116 ++++++++++++++++++ .../scripts/run-mysql-crud-test.sh | 113 +++++++++++++++++ .../scripts/run-oracle-crud-test.sh | 116 ++++++++++++++++++ .../scripts/run-postgres18-crud-test.sh | 113 +++++++++++++++++ 7 files changed, 688 insertions(+), 1 deletion(-) create mode 100755 ojp-grpc-client-go/scripts/run-db2-crud-test.sh create mode 100755 ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh create mode 100755 ojp-grpc-client-go/scripts/run-mssql-crud-test.sh create mode 100755 ojp-grpc-client-go/scripts/run-mysql-crud-test.sh create mode 100755 ojp-grpc-client-go/scripts/run-oracle-crud-test.sh create mode 100755 ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh diff --git a/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go b/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go index eca24f74d..14159e825 100644 --- a/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go +++ b/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go @@ -98,7 +98,7 @@ func main() { // CREATE updateReq := &pb.StatementRequest{ Session: connectResp, - Sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", + Sql: "CREATE TABLE IF NOT EXISTS demo(id INT NOT NULL PRIMARY KEY, name VARCHAR(100))", } if _, err = client.ExecuteUpdate(ctx, updateReq); err != nil { log.Fatalf("create table failed: %v", err) diff --git a/ojp-grpc-client-go/scripts/run-db2-crud-test.sh b/ojp-grpc-client-go/scripts/run-db2-crud-test.sh new file mode 100755 index 000000000..fd6e0c8b6 --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-db2-crud-test.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +set -euo pipefail + +SKIP_BUILD=false +if [[ "${1:-}" == "-SkipBuild" ]]; then + SKIP_BUILD=true +fi + +scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +clientDir="$(dirname "$scriptDir")" +repoRoot="$(dirname "$clientDir")" +serverDir="$repoRoot/ojp-server" +composeFile="$clientDir/docker-compose.db2.yml" +runStamp="$(date +%Y%m%d-%H%M%S)" +serverLogOut="$clientDir/.ojp-server-db2.${runStamp}.out.log" +serverLogErr="$clientDir/.ojp-server-db2.${runStamp}.err.log" + +dbUser="db2inst1" +dbPassword="testpass" +dbName="testdb" +dbHost="localhost" + +get_free_port() { + python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()" +} + +ojpPort=$(get_free_port) +ojpPrometheusPort=$(get_free_port) +dbPort=$(get_free_port) + +export DB2_HOST_PORT="$dbPort" + +wait_db2_healthy() { + local maxAttempts=${1:-120} sleepSeconds=${2:-5} + for ((i = 1; i <= maxAttempts; i++)); do + status="$(docker inspect --format '{{.State.Health.Status}}' ojp-db2 2>/dev/null || true)" + if [[ "$status" == "healthy" ]]; then + return 0 + fi + sleep "$sleepSeconds" + done + echo "ERROR: DB2 container did not become healthy in time." + exit 1 +} + +wait_ojp_started() { + local maxAttempts=${1:-120} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + if [[ -f "$serverLogOut" ]]; then + if grep -q "OJP gRPC Server started successfully" "$serverLogOut" 2>/dev/null; then + return 0 + fi + fi + sleep "$sleepSeconds" + done + echo "ERROR: OJP server did not start in time. Check $serverLogOut and $serverLogErr" + exit 1 +} + +cleanup() { + local exit_code=$? + docker compose -f "$composeFile" down 2>/dev/null || true + unset DB2_HOST_PORT + if [[ -n "${serverPid:-}" ]]; then + kill "$serverPid" 2>/dev/null || true + fi + exit "$exit_code" +} +trap cleanup EXIT + +echo "[1/8] Starting DB2 via docker compose..." +docker compose -f "$composeFile" up -d + +echo "[2/8] Waiting for DB2 health..." +wait_db2_healthy + +echo "[3/8] Ensuring DB2 JDBC driver in ojp-server/ojp-libs..." +libsDir="$serverDir/ojp-libs" +mkdir -p "$libsDir" +if ! ls "$libsDir"/jcc-*.jar 1>/dev/null 2>&1; then + driverTarget="$libsDir/jcc-11.5.9.0.jar" + curl -sLo "$driverTarget" "https://repo1.maven.org/maven2/com/ibm/db2/jcc/11.5.9.0/jcc-11.5.9.0.jar" +fi + +if [[ "$SKIP_BUILD" == false ]]; then + echo "[4/8] Building OJP modules needed by server..." + (cd "$repoRoot" && mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true") +else + echo "[4/8] Skipping build (-SkipBuild)." +fi + +echo "[5/8] Starting OJP server..." +jarPath="$serverDir/target/ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if [[ ! -f "$jarPath" ]]; then + echo "ERROR: Missing server jar: $jarPath" + exit 1 +fi + +java \ + -Duser.timezone=UTC \ + -Dojp.server.port="$ojpPort" \ + -Dojp.prometheus.port="$ojpPrometheusPort" \ + -Dojp.libs.path="$libsDir" \ + -jar "$jarPath" \ + >"$serverLogOut" 2>"$serverLogErr" & +serverPid=$! + +echo "[6/8] Waiting for OJP gRPC server on :$ojpPort..." +wait_ojp_started + +echo "[7/8] Running Go CRUD app against DB2..." +export OJP_JDBC_LINE="jdbc:ojp[localhost:${ojpPort}]_db2://${dbHost}:${dbPort}/${dbName},${dbUser},${dbPassword}" +(cd "$clientDir" && go run ./cmd/ojp-grpc-client) +unset OJP_JDBC_LINE + +echo "[8/8] DB2 + OJP CRUD run completed successfully. Bringing compose down..." diff --git a/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh b/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh new file mode 100755 index 000000000..9ea84a23a --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mariadb-crud-test.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +set -euo pipefail + +SKIP_BUILD=false +if [[ "${1:-}" == "-SkipBuild" ]]; then + SKIP_BUILD=true +fi + +scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +clientDir="$(dirname "$scriptDir")" +repoRoot="$(dirname "$clientDir")" +serverDir="$repoRoot/ojp-server" +composeFile="$clientDir/docker-compose.mariadb.yml" +runStamp="$(date +%Y%m%d-%H%M%S)" +serverLogOut="$clientDir/.ojp-server-mariadb.${runStamp}.out.log" +serverLogErr="$clientDir/.ojp-server-mariadb.${runStamp}.err.log" + +dbUser="testuser" +dbPassword="testpassword" +dbName="testdb" +dbHost="localhost" +dbPort="3307" + +get_free_port() { + python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()" +} + +ojpPort=$(get_free_port) +ojpPrometheusPort=$(get_free_port) + +wait_mariadb_healthy() { + local maxAttempts=${1:-60} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + status="$(docker inspect --format '{{.State.Health.Status}}' ojp-mariadb 2>/dev/null || true)" + if [[ "$status" == "healthy" ]]; then + return 0 + fi + sleep "$sleepSeconds" + done + echo "ERROR: MariaDB container did not become healthy in time." + exit 1 +} + +wait_ojp_started() { + local maxAttempts=${1:-120} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + if [[ -f "$serverLogOut" ]]; then + if grep -q "OJP gRPC Server started successfully" "$serverLogOut" 2>/dev/null; then + return 0 + fi + fi + sleep "$sleepSeconds" + done + echo "ERROR: OJP server did not start in time. Check $serverLogOut and $serverLogErr" + exit 1 +} + +cleanup() { + local exit_code=$? + docker compose -f "$composeFile" down 2>/dev/null || true + if [[ -n "${serverPid:-}" ]]; then + kill "$serverPid" 2>/dev/null || true + fi + exit "$exit_code" +} +trap cleanup EXIT + +echo "[1/8] Starting MariaDB via docker compose..." +docker compose -f "$composeFile" up -d + +echo "[2/8] Waiting for MariaDB health..." +wait_mariadb_healthy + +echo "[3/8] Ensuring MariaDB JDBC driver in ojp-server/ojp-libs..." +libsDir="$serverDir/ojp-libs" +mkdir -p "$libsDir" +if ! ls "$libsDir"/mariadb-java-client-*.jar 1>/dev/null 2>&1; then + driverTarget="$libsDir/mariadb-java-client-3.5.3.jar" + curl -sLo "$driverTarget" "https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/3.5.3/mariadb-java-client-3.5.3.jar" +fi + +if [[ "$SKIP_BUILD" == false ]]; then + echo "[4/8] Building OJP modules needed by server..." + (cd "$repoRoot" && mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true") +else + echo "[4/8] Skipping build (-SkipBuild)." +fi + +echo "[5/8] Starting OJP server..." +jarPath="$serverDir/target/ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if [[ ! -f "$jarPath" ]]; then + echo "ERROR: Missing server jar: $jarPath" + exit 1 +fi + +java \ + -Duser.timezone=UTC \ + -Dojp.server.port="$ojpPort" \ + -Dojp.prometheus.port="$ojpPrometheusPort" \ + -Dojp.libs.path="$libsDir" \ + -jar "$jarPath" \ + >"$serverLogOut" 2>"$serverLogErr" & +serverPid=$! + +echo "[6/8] Waiting for OJP gRPC server on :$ojpPort..." +wait_ojp_started + +echo "[7/8] Running Go CRUD app against MariaDB testdb..." +export OJP_JDBC_LINE="jdbc:ojp[localhost:${ojpPort}]_mariadb://${dbHost}:${dbPort}/${dbName},${dbUser},${dbPassword}" +(cd "$clientDir" && go run ./cmd/ojp-grpc-client) +unset OJP_JDBC_LINE + +echo "[8/8] MariaDB + OJP CRUD run completed successfully. Bringing compose down..." diff --git a/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh b/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh new file mode 100755 index 000000000..ec31613ad --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mssql-crud-test.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +set -euo pipefail + +SKIP_BUILD=false +if [[ "${1:-}" == "-SkipBuild" ]]; then + SKIP_BUILD=true +fi + +scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +clientDir="$(dirname "$scriptDir")" +repoRoot="$(dirname "$clientDir")" +serverDir="$repoRoot/ojp-server" +composeFile="$clientDir/docker-compose.mssql.yml" +runStamp="$(date +%Y%m%d-%H%M%S)" +serverLogOut="$clientDir/.ojp-server-mssql.${runStamp}.out.log" +serverLogErr="$clientDir/.ojp-server-mssql.${runStamp}.err.log" + +dbUser="sa" +dbPassword="TestPassword123!" +dbName="tempdb" +dbHost="localhost" + +get_free_port() { + python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()" +} + +ojpPort=$(get_free_port) +ojpPrometheusPort=$(get_free_port) +dbPort=$(get_free_port) + +export MSSQL_HOST_PORT="$dbPort" + +wait_mssql_healthy() { + local maxAttempts=${1:-80} sleepSeconds=${2:-3} + for ((i = 1; i <= maxAttempts; i++)); do + status="$(docker inspect --format '{{.State.Health.Status}}' ojp-mssql 2>/dev/null || true)" + if [[ "$status" == "healthy" ]]; then + return 0 + fi + sleep "$sleepSeconds" + done + echo "ERROR: MSSQL container did not become healthy in time." + exit 1 +} + +wait_ojp_started() { + local maxAttempts=${1:-120} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + if [[ -f "$serverLogOut" ]]; then + if grep -q "OJP gRPC Server started successfully" "$serverLogOut" 2>/dev/null; then + return 0 + fi + fi + sleep "$sleepSeconds" + done + echo "ERROR: OJP server did not start in time. Check $serverLogOut and $serverLogErr" + exit 1 +} + +cleanup() { + local exit_code=$? + docker compose -f "$composeFile" down 2>/dev/null || true + unset MSSQL_HOST_PORT + if [[ -n "${serverPid:-}" ]]; then + kill "$serverPid" 2>/dev/null || true + fi + exit "$exit_code" +} +trap cleanup EXIT + +echo "[1/8] Starting MSSQL via docker compose..." +docker compose -f "$composeFile" up -d + +echo "[2/8] Waiting for MSSQL health..." +wait_mssql_healthy + +echo "[3/8] Ensuring MSSQL JDBC driver in ojp-server/ojp-libs..." +libsDir="$serverDir/ojp-libs" +mkdir -p "$libsDir" +if ! ls "$libsDir"/mssql-jdbc-*.jar 1>/dev/null 2>&1; then + driverTarget="$libsDir/mssql-jdbc-12.10.0.jre11.jar" + curl -sLo "$driverTarget" "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.10.0.jre11/mssql-jdbc-12.10.0.jre11.jar" +fi + +if [[ "$SKIP_BUILD" == false ]]; then + echo "[4/8] Building OJP modules needed by server..." + (cd "$repoRoot" && mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true") +else + echo "[4/8] Skipping build (-SkipBuild)." +fi + +echo "[5/8] Starting OJP server..." +jarPath="$serverDir/target/ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if [[ ! -f "$jarPath" ]]; then + echo "ERROR: Missing server jar: $jarPath" + exit 1 +fi + +java \ + -Duser.timezone=UTC \ + -Dojp.server.port="$ojpPort" \ + -Dojp.prometheus.port="$ojpPrometheusPort" \ + -Dojp.libs.path="$libsDir" \ + -jar "$jarPath" \ + >"$serverLogOut" 2>"$serverLogErr" & +serverPid=$! + +echo "[6/8] Waiting for OJP gRPC server on :$ojpPort..." +wait_ojp_started + +echo "[7/8] Running Go CRUD app against MSSQL..." +export OJP_JDBC_LINE="jdbc:ojp[localhost:${ojpPort}]_sqlserver://${dbHost}:${dbPort};databaseName=${dbName};encrypt=false;trustServerCertificate=true,${dbUser},${dbPassword}" +(cd "$clientDir" && go run ./cmd/ojp-grpc-client) +unset OJP_JDBC_LINE + +echo "[8/8] MSSQL + OJP CRUD run completed successfully. Bringing compose down..." diff --git a/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh b/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh new file mode 100755 index 000000000..18bcd1481 --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-mysql-crud-test.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +set -euo pipefail + +SKIP_BUILD=false +if [[ "${1:-}" == "-SkipBuild" ]]; then + SKIP_BUILD=true +fi + +scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +clientDir="$(dirname "$scriptDir")" +repoRoot="$(dirname "$clientDir")" +serverDir="$repoRoot/ojp-server" +composeFile="$clientDir/docker-compose.mysql.yml" +runStamp="$(date +%Y%m%d-%H%M%S)" +serverLogOut="$clientDir/.ojp-server-mysql.${runStamp}.out.log" +serverLogErr="$clientDir/.ojp-server-mysql.${runStamp}.err.log" + +dbUser="testuser" +dbPassword="testpassword" +dbName="testdb" +dbHost="localhost" +dbPort="3306" + +get_free_port() { + python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()" +} + +ojpPort=$(get_free_port) +ojpPrometheusPort=$(get_free_port) + +wait_mysql_healthy() { + local maxAttempts=${1:-60} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + status="$(docker inspect --format '{{.State.Health.Status}}' ojp-mysql 2>/dev/null || true)" + if [[ "$status" == "healthy" ]]; then + return 0 + fi + sleep "$sleepSeconds" + done + echo "ERROR: MySQL container did not become healthy in time." + exit 1 +} + +wait_ojp_started() { + local maxAttempts=${1:-120} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + if [[ -f "$serverLogOut" ]]; then + if grep -q "OJP gRPC Server started successfully" "$serverLogOut" 2>/dev/null; then + return 0 + fi + fi + sleep "$sleepSeconds" + done + echo "ERROR: OJP server did not start in time. Check $serverLogOut and $serverLogErr" + exit 1 +} + +cleanup() { + local exit_code=$? + docker compose -f "$composeFile" down 2>/dev/null || true + if [[ -n "${serverPid:-}" ]]; then + kill "$serverPid" 2>/dev/null || true + fi + exit "$exit_code" +} +trap cleanup EXIT + +echo "[1/8] Starting MySQL via docker compose..." +docker compose -f "$composeFile" up -d + +echo "[2/8] Waiting for MySQL health..." +wait_mysql_healthy + +echo "[3/8] Ensuring MySQL JDBC driver in ojp-server/ojp-libs..." +libsDir="$serverDir/ojp-libs" +mkdir -p "$libsDir" +if ! ls "$libsDir"/mysql-connector-j-*.jar 1>/dev/null 2>&1; then + driverTarget="$libsDir/mysql-connector-j-9.3.0.jar" + curl -sLo "$driverTarget" "https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/9.3.0/mysql-connector-j-9.3.0.jar" +fi + +if [[ "$SKIP_BUILD" == false ]]; then + echo "[4/8] Building OJP modules needed by server..." + (cd "$repoRoot" && mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true") +else + echo "[4/8] Skipping build (-SkipBuild)." +fi + +echo "[5/8] Starting OJP server..." +jarPath="$serverDir/target/ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if [[ ! -f "$jarPath" ]]; then + echo "ERROR: Missing server jar: $jarPath" + exit 1 +fi + +java \ + -Duser.timezone=UTC \ + -Dojp.server.port="$ojpPort" \ + -Dojp.prometheus.port="$ojpPrometheusPort" \ + -Dojp.libs.path="$libsDir" \ + -jar "$jarPath" \ + >"$serverLogOut" 2>"$serverLogErr" & +serverPid=$! + +echo "[6/8] Waiting for OJP gRPC server on :$ojpPort..." +wait_ojp_started + +echo "[7/8] Running Go CRUD app against MySQL testdb..." +export OJP_JDBC_LINE="jdbc:ojp[localhost:${ojpPort}]_mysql://${dbHost}:${dbPort}/${dbName},${dbUser},${dbPassword}" +(cd "$clientDir" && go run ./cmd/ojp-grpc-client) +unset OJP_JDBC_LINE + +echo "[8/8] MySQL + OJP CRUD run completed successfully. Bringing compose down..." diff --git a/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh b/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh new file mode 100755 index 000000000..cb63579b9 --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-oracle-crud-test.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +set -euo pipefail + +SKIP_BUILD=false +if [[ "${1:-}" == "-SkipBuild" ]]; then + SKIP_BUILD=true +fi + +scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +clientDir="$(dirname "$scriptDir")" +repoRoot="$(dirname "$clientDir")" +serverDir="$repoRoot/ojp-server" +composeFile="$clientDir/docker-compose.oracle.yml" +runStamp="$(date +%Y%m%d-%H%M%S)" +serverLogOut="$clientDir/.ojp-server-oracle.${runStamp}.out.log" +serverLogErr="$clientDir/.ojp-server-oracle.${runStamp}.err.log" + +dbUser="testuser" +dbPassword="testpassword" +dbService="XEPDB1" +dbHost="localhost" + +get_free_port() { + python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()" +} + +ojpPort=$(get_free_port) +ojpPrometheusPort=$(get_free_port) +dbPort=$(get_free_port) + +export ORACLE_HOST_PORT="$dbPort" + +wait_oracle_healthy() { + local maxAttempts=${1:-90} sleepSeconds=${2:-4} + for ((i = 1; i <= maxAttempts; i++)); do + status="$(docker inspect --format '{{.State.Health.Status}}' ojp-oracle 2>/dev/null || true)" + if [[ "$status" == "healthy" ]]; then + return 0 + fi + sleep "$sleepSeconds" + done + echo "ERROR: Oracle container did not become healthy in time." + exit 1 +} + +wait_ojp_started() { + local maxAttempts=${1:-120} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + if [[ -f "$serverLogOut" ]]; then + if grep -q "OJP gRPC Server started successfully" "$serverLogOut" 2>/dev/null; then + return 0 + fi + fi + sleep "$sleepSeconds" + done + echo "ERROR: OJP server did not start in time. Check $serverLogOut and $serverLogErr" + exit 1 +} + +cleanup() { + local exit_code=$? + docker compose -f "$composeFile" down 2>/dev/null || true + unset ORACLE_HOST_PORT + if [[ -n "${serverPid:-}" ]]; then + kill "$serverPid" 2>/dev/null || true + fi + exit "$exit_code" +} +trap cleanup EXIT + +echo "[1/8] Starting Oracle XE via docker compose..." +docker compose -f "$composeFile" up -d + +echo "[2/8] Waiting for Oracle health..." +wait_oracle_healthy + +echo "[3/8] Ensuring Oracle JDBC driver in ojp-server/ojp-libs..." +libsDir="$serverDir/ojp-libs" +mkdir -p "$libsDir" +if ! ls "$libsDir"/ojdbc*.jar 1>/dev/null 2>&1; then + driverTarget="$libsDir/ojdbc11-23.8.0.25.04.jar" + curl -sLo "$driverTarget" "https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc11/23.8.0.25.04/ojdbc11-23.8.0.25.04.jar" +fi + +if [[ "$SKIP_BUILD" == false ]]; then + echo "[4/8] Building OJP modules needed by server..." + (cd "$repoRoot" && mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true") +else + echo "[4/8] Skipping build (-SkipBuild)." +fi + +echo "[5/8] Starting OJP server..." +jarPath="$serverDir/target/ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if [[ ! -f "$jarPath" ]]; then + echo "ERROR: Missing server jar: $jarPath" + exit 1 +fi + +java \ + -Duser.timezone=UTC \ + -Dojp.server.port="$ojpPort" \ + -Dojp.prometheus.port="$ojpPrometheusPort" \ + -Dojp.libs.path="$libsDir" \ + -jar "$jarPath" \ + >"$serverLogOut" 2>"$serverLogErr" & +serverPid=$! + +echo "[6/8] Waiting for OJP gRPC server on :$ojpPort..." +wait_ojp_started + +echo "[7/8] Running Go CRUD app against Oracle..." +export OJP_JDBC_LINE="jdbc:ojp[localhost:${ojpPort}]_oracle:thin:@${dbHost}:${dbPort}/${dbService},${dbUser},${dbPassword}" +(cd "$clientDir" && go run ./cmd/ojp-grpc-client) +unset OJP_JDBC_LINE + +echo "[8/8] Oracle + OJP CRUD run completed successfully. Bringing compose down..." diff --git a/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh b/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh new file mode 100755 index 000000000..3c1f77d5a --- /dev/null +++ b/ojp-grpc-client-go/scripts/run-postgres18-crud-test.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +set -euo pipefail + +SKIP_BUILD=false +if [[ "${1:-}" == "-SkipBuild" ]]; then + SKIP_BUILD=true +fi + +scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +clientDir="$(dirname "$scriptDir")" +repoRoot="$(dirname "$clientDir")" +serverDir="$repoRoot/ojp-server" +composeFile="$clientDir/docker-compose.postgres18.yml" +runStamp="$(date +%Y%m%d-%H%M%S)" +serverLogOut="$clientDir/.ojp-server-postgres18.${runStamp}.out.log" +serverLogErr="$clientDir/.ojp-server-postgres18.${runStamp}.err.log" + +dbUser="testuser" +dbPassword="testpassword" +dbName="testdb" +dbHost="localhost" +dbPort="5432" + +get_free_port() { + python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()" +} + +ojpPort=$(get_free_port) +ojpPrometheusPort=$(get_free_port) + +wait_postgres_healthy() { + local maxAttempts=${1:-60} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + status="$(docker inspect --format '{{.State.Health.Status}}' ojp-postgres18 2>/dev/null || true)" + if [[ "$status" == "healthy" ]]; then + return 0 + fi + sleep "$sleepSeconds" + done + echo "ERROR: PostgreSQL container did not become healthy in time." + exit 1 +} + +wait_ojp_started() { + local maxAttempts=${1:-120} sleepSeconds=${2:-2} + for ((i = 1; i <= maxAttempts; i++)); do + if [[ -f "$serverLogOut" ]]; then + if grep -q "OJP gRPC Server started successfully" "$serverLogOut" 2>/dev/null; then + return 0 + fi + fi + sleep "$sleepSeconds" + done + echo "ERROR: OJP server did not start in time. Check $serverLogOut and $serverLogErr" + exit 1 +} + +cleanup() { + local exit_code=$? + docker compose -f "$composeFile" down 2>/dev/null || true + if [[ -n "${serverPid:-}" ]]; then + kill "$serverPid" 2>/dev/null || true + fi + exit "$exit_code" +} +trap cleanup EXIT + +echo "[1/8] Starting PostgreSQL 18 via docker compose..." +docker compose -f "$composeFile" up -d + +echo "[2/8] Waiting for PostgreSQL health..." +wait_postgres_healthy + +echo "[3/8] Ensuring PostgreSQL JDBC driver in ojp-server/ojp-libs..." +libsDir="$serverDir/ojp-libs" +mkdir -p "$libsDir" +if ! ls "$libsDir"/postgresql-*.jar 1>/dev/null 2>&1; then + driverTarget="$libsDir/postgresql-42.7.8.jar" + curl -sLo "$driverTarget" "https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.8/postgresql-42.7.8.jar" +fi + +if [[ "$SKIP_BUILD" == false ]]; then + echo "[4/8] Building OJP modules needed by server..." + (cd "$repoRoot" && mvn install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true") +else + echo "[4/8] Skipping build (-SkipBuild)." +fi + +echo "[5/8] Starting OJP server..." +jarPath="$serverDir/target/ojp-server-0.4.17-SNAPSHOT-shaded.jar" +if [[ ! -f "$jarPath" ]]; then + echo "ERROR: Missing server jar: $jarPath" + exit 1 +fi + +java \ + -Duser.timezone=UTC \ + -Dojp.server.port="$ojpPort" \ + -Dojp.prometheus.port="$ojpPrometheusPort" \ + -Dojp.libs.path="$libsDir" \ + -jar "$jarPath" \ + >"$serverLogOut" 2>"$serverLogErr" & +serverPid=$! + +echo "[6/8] Waiting for OJP gRPC server on :$ojpPort..." +wait_ojp_started + +echo "[7/8] Running Go CRUD app against PostgreSQL testdb..." +export OJP_JDBC_LINE="jdbc:ojp[localhost:${ojpPort}]_postgresql://${dbHost}:${dbPort}/${dbName},${dbUser},${dbPassword}" +(cd "$clientDir" && go run ./cmd/ojp-grpc-client) +unset OJP_JDBC_LINE + +echo "[8/8] PostgreSQL 18 + OJP CRUD run completed successfully. Bringing compose down..." From bf2a2ce4366589212bbecbaad49f8b476218ff7d Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Tue, 19 May 2026 20:01:30 +0200 Subject: [PATCH 09/12] clean up --- ojp-grpc-client-go/main.go | 89 -------------------------------------- 1 file changed, 89 deletions(-) delete mode 100644 ojp-grpc-client-go/main.go diff --git a/ojp-grpc-client-go/main.go b/ojp-grpc-client-go/main.go deleted file mode 100644 index 3d0f807d8..000000000 --- a/ojp-grpc-client-go/main.go +++ /dev/null @@ -1,89 +0,0 @@ -package main - -import ( - "context" - "fmt" - "io" - "log" - "os" - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - - pb "github.com/open-j-proxy/ojp-client/gen/go/com/openjproxy/grpc" -) - -func main() { - addr := env("OJP_ADDR", "127.0.0.1:1059") - backendURL := env("OJP_BACKEND_URL", "jdbc:postgresql://postgres:5432/ojp") - dbUser := env("OJP_DB_USER", "ojp") - dbPassword := env("OJP_DB_PASSWORD", "ojp") - - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - conn, err := grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - log.Fatalf("dial failed: %v", err) - } - defer conn.Close() - - client := pb.NewStatementServiceClient(conn) - - connectResp, err := client.Connect(ctx, &pb.ConnectionDetails{ - Url: backendURL, - User: dbUser, - Password: dbPassword, - ClientUUID: "go-example-client", - }) - if err != nil { - log.Fatalf("connect failed: %v", err) - } - - updateReq := &pb.StatementRequest{ - Session: connectResp, - Sql: "CREATE TABLE IF NOT EXISTS demo(id INT PRIMARY KEY, name VARCHAR(100))", - } - if _, err = client.ExecuteUpdate(ctx, updateReq); err != nil { - log.Fatalf("create table failed: %v", err) - } - - insertReq := &pb.StatementRequest{ - Session: connectResp, - Sql: "INSERT INTO demo(id, name) VALUES (1, 'hello from go') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name", - } - if _, err = client.ExecuteUpdate(ctx, insertReq); err != nil { - log.Fatalf("insert failed: %v", err) - } - - queryReq := &pb.StatementRequest{ - Session: connectResp, - Sql: "SELECT id, name FROM demo ORDER BY id", - } - stream, err := client.ExecuteQuery(ctx, queryReq) - if err != nil { - log.Fatalf("executeQuery failed: %v", err) - } - - for { - msg, recvErr := stream.Recv() - if recvErr == io.EOF { - break - } - if recvErr != nil { - log.Fatalf("stream recv failed: %v", recvErr) - } - fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) - } - - _, _ = client.TerminateSession(context.Background(), connectResp) -} - -func env(name, fallback string) string { - v := os.Getenv(name) - if v == "" { - return fallback - } - return v -} From 28ef8a93a3d9e779ef7765b6d44a981c39443c91 Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Tue, 19 May 2026 20:07:40 +0200 Subject: [PATCH 10/12] adding test setup to the readme.md --- ojp-grpc-client-go/README.md | 105 +++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 24 deletions(-) diff --git a/ojp-grpc-client-go/README.md b/ojp-grpc-client-go/README.md index 02931e021..ef3b0cc39 100644 --- a/ojp-grpc-client-go/README.md +++ b/ojp-grpc-client-go/README.md @@ -40,13 +40,6 @@ Example: jdbc:ojp[localhost:1059]_postgresql://localhost:5432/defaultdb,testuser,testpassword ``` -Fallback (test helper only): - -- `OJP_JDBC_CSV` (multi-line CSV content for testing only) -- `OJP_JDBC_CSV_INDEX` (0-based line index, default `0`) - -If `OJP_JDBC_LINE` is set, it is used first. - ## What `main` Does 1. Parses connection values from env (`addr`, backend JDBC URL, user, password). @@ -60,23 +53,16 @@ If `OJP_JDBC_LINE` is set, it is used first. - delete - read -Notes: - -- Assertions are executed after each read: - - after insert: exactly 1 row - - after update: exactly 1 row - - after delete: 0 rows - ## Run the Client From `ojp-grpc-client-go`: -```powershell +```bash $env:OJP_JDBC_LINE='jdbc:ojp[localhost:1059]_h2:~/test,sa,' go run ./cmd/ojp-grpc-client ``` -Expected output shape: +Expected output: ```text READ after CREATE/INSERT: @@ -101,7 +87,7 @@ Covered functions: Run: -```powershell +```bash go test ./cmd/ojp-grpc-client ``` @@ -109,7 +95,7 @@ go test ./cmd/ojp-grpc-client ### 1) Prepare OJP server drivers -```powershell +```bash cd ..\ojp-server bash -lc "tr -d '\r' < download-drivers.sh | bash" ``` @@ -120,7 +106,7 @@ This creates `ojp-server/ojp-libs/` and downloads H2 + other open-source JDBC dr From repository root (`ojp/`): -```powershell +```bash mvn clean install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" ``` @@ -128,7 +114,7 @@ mvn clean install "-DskipTests=true" "-Dgpg.skip=true" "-Dcheckstyle.skip=true" From `ojp-server`: -```powershell +```bash java -Duser.timezone=UTC -Dojp.libs.path=.\ojp-libs -jar .\target\ojp-server-0.4.17-SNAPSHOT-shaded.jar ``` @@ -136,14 +122,14 @@ java -Duser.timezone=UTC -Dojp.libs.path=.\ojp-libs -jar .\target\ojp-server-0.4 From `ojp-grpc-client-go`: -```powershell +```bash $env:OJP_JDBC_LINE='jdbc:ojp[localhost:1059]_h2:~/test,sa,' go run ./cmd/ojp-grpc-client ``` If you want to test using CSV test data: -```powershell +```bash $env:OJP_JDBC_CSV = Get-Content -Raw -Path .\testdata\connection.csv $env:OJP_JDBC_CSV_INDEX='0' Remove-Item Env:OJP_JDBC_LINE -ErrorAction SilentlyContinue @@ -175,7 +161,7 @@ What this script does: 5. Starts OJP server on dynamically selected free ports 6. Runs `go run ./cmd/ojp-grpc-client` with `OJP_JDBC_LINE` targeting `testdb` -### Bash wrapper +### Bash From `ojp-grpc-client-go`: @@ -183,7 +169,7 @@ From `ojp-grpc-client-go`: bash scripts/run-postgres18-crud-test.sh -SkipBuild ``` -The bash script is a wrapper that calls the PowerShell script. +The bash script is a standalone implementation that follows the same steps as the PowerShell version. ## End-to-End Test (MySQL via Docker Compose) @@ -230,3 +216,74 @@ This follows the same steps as the PostgreSQL script: 4. (Optional) builds OJP modules 5. Starts OJP server on dynamically selected free ports 6. Runs `go run ./cmd/ojp-grpc-client` with MariaDB `OJP_JDBC_LINE` + +## End-to-End Test (DB2 via Docker Compose) + +From `ojp-grpc-client-go`: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\run-db2-crud-test.ps1 -SkipBuild +``` + +Or: + +```bash +bash scripts/run-db2-crud-test.sh -SkipBuild +``` + +This follows the same steps as the PostgreSQL script: + +1. Starts `icr.io/db2_community/db2` using `docker-compose.db2.yml` with a dynamically assigned host port +2. Waits for healthy DB2 (up to 10 min, 5s intervals) +3. Ensures DB2 JDBC driver (`jcc-*.jar`) exists in `ojp-server/ojp-libs` +4. (Optional) builds OJP modules +5. Starts OJP server on dynamically selected free ports +6. Runs `go run ./cmd/ojp-grpc-client` with DB2 `OJP_JDBC_LINE` + +> **Note:** DB2 uses a stricter SQL dialect. The `demo` table creation requires `NOT NULL` on primary key columns — this is already handled in the Go client's CREATE TABLE statement. + +## End-to-End Test (SQL Server via Docker Compose) + +From `ojp-grpc-client-go`: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\run-mssql-crud-test.ps1 -SkipBuild +``` + +Or: + +```bash +bash scripts/run-mssql-crud-test.sh -SkipBuild +``` + +This follows the same steps as the PostgreSQL script: + +1. Starts `mcr.microsoft.com/mssql/server:2022-latest` using `docker-compose.mssql.yml` with a dynamically assigned host port +2. Waits for healthy MSSQL (up to 4 min, 3s intervals) +3. Ensures MSSQL JDBC driver (`mssql-jdbc-*.jar`) exists in `ojp-server/ojp-libs` +4. (Optional) builds OJP modules +5. Starts OJP server on dynamically selected free ports +6. Runs `go run ./cmd/ojp-grpc-client` with SQL Server `OJP_JDBC_LINE` + +## End-to-End Test (Oracle XE via Docker Compose) + +From `ojp-grpc-client-go`: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\run-oracle-crud-test.ps1 -SkipBuild +``` + +Or: + +```bash +bash scripts/run-oracle-crud-test.sh -SkipBuild +``` + +This follows the same steps as the PostgreSQL script: + +1. Starts `gvenzl/oracle-xe` using `docker-compose.oracle.yml` with a dynamically assigned host port +2. Waits for healthy Oracle (up to 6 min, 4s intervals) +3. Ensures Oracle JDBC driver (`ojdbc*.jar`) exists in `ojp-server/ojp-libs` +4. (Optional) builds OJP modules +5. Starts OJP server on dynamically selected free ports +6. Runs `go run ./cmd/ojp-grpc-client` with Oracle `OJP_JDBC_LINE` From 0c2e5ae418cfa420abec691b690f55440e16f115 Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Tue, 19 May 2026 20:46:15 +0200 Subject: [PATCH 11/12] linter for go --- ojp-grpc-client-go/README.md | 3 +- .../cmd/ojp-grpc-client/main.go | 7 +--- .../internal/client/endpoint.go | 2 - ojp-grpc-client-go/internal/client/health.go | 6 +-- .../internal/client/multinode.go | 19 +++------- ojp-grpc-client-go/internal/client/service.go | 37 ++++++++++--------- 6 files changed, 31 insertions(+), 43 deletions(-) diff --git a/ojp-grpc-client-go/README.md b/ojp-grpc-client-go/README.md index ef3b0cc39..1e5aa8248 100644 --- a/ojp-grpc-client-go/README.md +++ b/ojp-grpc-client-go/README.md @@ -240,7 +240,8 @@ This follows the same steps as the PostgreSQL script: 5. Starts OJP server on dynamically selected free ports 6. Runs `go run ./cmd/ojp-grpc-client` with DB2 `OJP_JDBC_LINE` -> **Note:** DB2 uses a stricter SQL dialect. The `demo` table creation requires `NOT NULL` on primary key columns — this is already handled in the Go client's CREATE TABLE statement. +> **Note:** DB2 uses a stricter SQL dialect. The `demo` table creation requires `NOT NULL` on primary key columns — +> this is already handled in the Go clients CREATE TABLE statement. ## End-to-End Test (SQL Server via Docker Compose) diff --git a/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go b/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go index 14159e825..64d5e943a 100644 --- a/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go +++ b/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go @@ -64,12 +64,7 @@ func main() { if err != nil { log.Fatalf("dial failed: %v", err) } - defer func(conn *grpc.ClientConn) { - err := conn.Close() - if err != nil { - - } - }(conn) + defer conn.Close() client := pb.NewStatementServiceClient(conn) diff --git a/ojp-grpc-client-go/internal/client/endpoint.go b/ojp-grpc-client-go/internal/client/endpoint.go index b574cbd9b..e3106f6ca 100644 --- a/ojp-grpc-client-go/internal/client/endpoint.go +++ b/ojp-grpc-client-go/internal/client/endpoint.go @@ -2,7 +2,6 @@ package client import ( "fmt" - "sync" "sync/atomic" "time" ) @@ -16,7 +15,6 @@ type ServerEndpoint struct { lastFailureTime atomic.Int64 connCount atomic.Int64 // Number of active connections loadMetric atomic.Int64 // Load metric for load-aware selection - mu sync.RWMutex } // NewServerEndpoint creates a new server endpoint. diff --git a/ojp-grpc-client-go/internal/client/health.go b/ojp-grpc-client-go/internal/client/health.go index 83a2f0b63..7def90e06 100644 --- a/ojp-grpc-client-go/internal/client/health.go +++ b/ojp-grpc-client-go/internal/client/health.go @@ -9,7 +9,7 @@ import ( type HealthCheckConfig struct { healthCheckIntervalMs int64 healthCheckThresholdMs int64 - healthCheckTimeoutMs int64 + healthCheckTimeoutMs int64 redistributionEnabled bool idleRebalanceFraction float64 maxClosePerRecovery int @@ -32,7 +32,7 @@ func LoadHealthCheckConfig(props map[string]string) *HealthCheckConfig { } interval := getInt64(props, "ojp.health.check.interval", DefaultHealthCheckIntervalMs) threshold := getInt64(props, "ojp.health.check.threshold", DefaultHealthCheckThresholdMs) - timeout := getInt(props, "ojp.health.check.timeout", DefaultHealthCheckTimeoutMs) + timeout := getInt64(props, "ojp.health.check.timeout", DefaultHealthCheckTimeoutMs) enabled := getBool(props, "ojp.redistribution.enabled", DefaultRedistributionEnabled) idleFraction := getFloat(props, "ojp.redistribution.idleRebalanceFraction", DefaultIdleRebalanceFraction) maxClose := getInt(props, "ojp.redistribution.maxClosePerRecovery", DefaultMaxClosePerRecovery) @@ -41,7 +41,7 @@ func LoadHealthCheckConfig(props map[string]string) *HealthCheckConfig { return &HealthCheckConfig{ healthCheckIntervalMs: interval, healthCheckThresholdMs: threshold, - healthCheckTimeoutMs: int64(timeout), + healthCheckTimeoutMs: timeout, redistributionEnabled: enabled, idleRebalanceFraction: idleFraction, maxClosePerRecovery: maxClose, diff --git a/ojp-grpc-client-go/internal/client/multinode.go b/ojp-grpc-client-go/internal/client/multinode.go index a4cab3066..6776c39e0 100644 --- a/ojp-grpc-client-go/internal/client/multinode.go +++ b/ojp-grpc-client-go/internal/client/multinode.go @@ -15,9 +15,7 @@ import ( ) type ChannelAndStub struct { - channel *grpc.ClientConn - blockingStub ojpgrpc.StatementServiceClient - asyncStub ojpgrpc.StatementServiceClient + channel *grpc.ClientConn } type MultinodeConnectionManager struct { @@ -161,11 +159,11 @@ func (m *MultinodeConnectionManager) roundRobinServer() *ServerEndpoint { m.mu.RLock() defer m.mu.RUnlock() - if len(m.endpoints) == 0 { + count := len(m.endpoints) + if count == 0 { return nil } - count := len(m.endpoints) idx := int(m.roundRobinIdx.Add(1)) % count for i := 0; i < count; i++ { @@ -175,12 +173,7 @@ func (m *MultinodeConnectionManager) roundRobinServer() *ServerEndpoint { } } - for _, ep := range m.endpoints { - if ep.IsHealthy() { - return ep - } - } - + // No healthy endpoint found; return the first as a last resort. return m.endpoints[0] } @@ -226,9 +219,7 @@ func (m *MultinodeConnectionManager) getChannel(server *ServerEndpoint) (*grpc.C } m.channelMap[server] = &ChannelAndStub{ - channel: conn, - blockingStub: ojpgrpc.NewStatementServiceClient(conn), - asyncStub: ojpgrpc.NewStatementServiceClient(conn), + channel: conn, } return conn, nil diff --git a/ojp-grpc-client-go/internal/client/service.go b/ojp-grpc-client-go/internal/client/service.go index d8a5a00b9..5dfbdc7d5 100644 --- a/ojp-grpc-client-go/internal/client/service.go +++ b/ojp-grpc-client-go/internal/client/service.go @@ -331,14 +331,17 @@ type GrpcStatementServiceClient struct { address string client ojpgrpc.StatementServiceClient conn *grpc.ClientConn + connMu sync.Mutex } func NewGrpcStatementServiceClient(address string) *GrpcStatementServiceClient { return &GrpcStatementServiceClient{address: address} } -func (c *GrpcStatementServiceClient) EnsureConnected(ctx context.Context) error { - _ = ctx +func (c *GrpcStatementServiceClient) EnsureConnected() error { + c.connMu.Lock() + defer c.connMu.Unlock() + if c.conn != nil { return nil } @@ -368,7 +371,7 @@ func (c *GrpcStatementServiceClient) EnsureConnected(ctx context.Context) error func (c *GrpcStatementServiceClient) Connect(ctx context.Context, details *ojpgrpc.ConnectionDetails) (*ojpgrpc.SessionInfo, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -377,7 +380,7 @@ func (c *GrpcStatementServiceClient) Connect(ctx context.Context, details *ojpgr func (c *GrpcStatementServiceClient) ExecuteUpdate(ctx context.Context, session *ojpgrpc.SessionInfo, sql string) (*ojpgrpc.OpResult, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -391,7 +394,7 @@ func (c *GrpcStatementServiceClient) ExecuteUpdate(ctx context.Context, session func (c *GrpcStatementServiceClient) ExecuteQuery(ctx context.Context, session *ojpgrpc.SessionInfo, sql string) ([]*ojpgrpc.OpResult, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -429,7 +432,7 @@ func (c *GrpcStatementServiceClient) TerminateSession(ctx context.Context, sessi func (c *GrpcStatementServiceClient) StartTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -438,21 +441,21 @@ func (c *GrpcStatementServiceClient) StartTransaction(ctx context.Context, sessi func (c *GrpcStatementServiceClient) CommitTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { if c.client == nil { - return nil, nil + return nil, fmt.Errorf("client not connected") } return c.client.CommitTransaction(ctx, session) } func (c *GrpcStatementServiceClient) RollbackTransaction(ctx context.Context, session *ojpgrpc.SessionInfo) (*ojpgrpc.SessionInfo, error) { if c.client == nil { - return nil, nil + return nil, fmt.Errorf("client not connected") } return c.client.RollbackTransaction(ctx, session) } func (c *GrpcStatementServiceClient) XAStart(ctx context.Context, xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -465,7 +468,7 @@ func (c *GrpcStatementServiceClient) XAStart(ctx context.Context, xid *ojpgrpc.X func (c *GrpcStatementServiceClient) XAEnd(ctx context.Context, xid *ojpgrpc.XidProto, flags int) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -478,7 +481,7 @@ func (c *GrpcStatementServiceClient) XAEnd(ctx context.Context, xid *ojpgrpc.Xid func (c *GrpcStatementServiceClient) XAPrepare(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaPrepareResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -488,7 +491,7 @@ func (c *GrpcStatementServiceClient) XAPrepare(ctx context.Context, xid *ojpgrpc func (c *GrpcStatementServiceClient) XACommit(ctx context.Context, xid *ojpgrpc.XidProto, onePhase bool) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -501,7 +504,7 @@ func (c *GrpcStatementServiceClient) XACommit(ctx context.Context, xid *ojpgrpc. func (c *GrpcStatementServiceClient) XARollback(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -511,7 +514,7 @@ func (c *GrpcStatementServiceClient) XARollback(ctx context.Context, xid *ojpgrp func (c *GrpcStatementServiceClient) XARecover(ctx context.Context, flag int) (*ojpgrpc.XaRecoverResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -521,7 +524,7 @@ func (c *GrpcStatementServiceClient) XARecover(ctx context.Context, flag int) (* func (c *GrpcStatementServiceClient) XAForget(ctx context.Context, xid *ojpgrpc.XidProto) (*ojpgrpc.XaResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -531,7 +534,7 @@ func (c *GrpcStatementServiceClient) XAForget(ctx context.Context, xid *ojpgrpc. func (c *GrpcStatementServiceClient) XASetTransactionTimeout(ctx context.Context, seconds int) (*ojpgrpc.XaSetTransactionTimeoutResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } @@ -541,7 +544,7 @@ func (c *GrpcStatementServiceClient) XASetTransactionTimeout(ctx context.Context func (c *GrpcStatementServiceClient) XAGetTransactionTimeout(ctx context.Context) (*ojpgrpc.XaGetTransactionTimeoutResponse, error) { if c.client == nil { - if err := c.EnsureConnected(ctx); err != nil { + if err := c.EnsureConnected(); err != nil { return nil, err } } From 30e115908b703fe79254936a1c9567eb034d8908 Mon Sep 17 00:00:00 2001 From: Jens Papenhagen Date: Wed, 20 May 2026 18:04:22 +0200 Subject: [PATCH 12/12] adding transaction roundtrip with rollback --- .../cmd/ojp-grpc-client/main.go | 62 +++--- .../ojp-grpc-client/transaction_rollback.go | 191 ++++++++++++++++++ 2 files changed, 221 insertions(+), 32 deletions(-) create mode 100644 ojp-grpc-client-go/cmd/ojp-grpc-client/transaction_rollback.go diff --git a/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go b/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go index 64d5e943a..288802ce8 100644 --- a/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go +++ b/ojp-grpc-client-go/cmd/ojp-grpc-client/main.go @@ -12,9 +12,7 @@ import ( "strings" "time" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - + ojpclient "github.com/open-j-proxy/ojp-client/internal/client" pb "github.com/open-j-proxy/ojp-client/internal/gen/go/com/openjproxy/grpc" ) @@ -59,14 +57,7 @@ func main() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - // Open gRPC connection to OJP. - conn, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - log.Fatalf("dial failed: %v", err) - } - defer conn.Close() - - client := pb.NewStatementServiceClient(conn) + client := ojpclient.NewGrpcStatementServiceClient(addr) connectResp, err := client.Connect(ctx, &pb.ConnectionDetails{ Url: backendURL, @@ -85,7 +76,7 @@ func main() { Session: connectResp, Sql: "SET SCHEMA DB2INST1", } - if _, err = client.ExecuteUpdate(ctx, setSchemaReq); err != nil { + if _, err = client.ExecuteUpdate(ctx, connectResp, setSchemaReq.Sql); err != nil { log.Fatalf("set schema failed: %v", err) } } @@ -95,7 +86,7 @@ func main() { Session: connectResp, Sql: "CREATE TABLE IF NOT EXISTS demo(id INT NOT NULL PRIMARY KEY, name VARCHAR(100))", } - if _, err = client.ExecuteUpdate(ctx, updateReq); err != nil { + if _, err = client.ExecuteUpdate(ctx, connectResp, updateReq.Sql); err != nil { log.Fatalf("create table failed: %v", err) } @@ -106,7 +97,7 @@ func main() { Session: connectResp, Sql: insertSQL, } - if _, err = client.ExecuteUpdate(ctx, insertReq); err != nil { + if _, err = client.ExecuteUpdate(ctx, connectResp, insertReq.Sql); err != nil { log.Fatalf("insert failed: %v", err) } @@ -115,15 +106,14 @@ func main() { Session: connectResp, Sql: "SELECT id, name FROM demo ORDER BY id", } - stream, err := client.ExecuteQuery(ctx, queryReq) + results, err := client.ExecuteQuery(ctx, connectResp, queryReq.Sql) if err != nil { log.Fatalf("executeQuery failed: %v", err) } - fmt.Println("READ after CREATE/INSERT:") - results, err := drainQueryStream(stream) - if err != nil { - log.Fatalf("read after insert failed: %v", err) + for _, msg := range results { + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) } + fmt.Println("READ after CREATE/INSERT:") var insertedRows []*pb.ResultRow for _, r := range results { if qr := r.GetQueryResult(); qr != nil { @@ -143,18 +133,17 @@ func main() { Session: connectResp, Sql: "UPDATE demo SET name = 'updated from go' WHERE id = 1", } - if _, err = client.ExecuteUpdate(ctx, updateReq2); err != nil { + if _, err = client.ExecuteUpdate(ctx, connectResp, updateReq2.Sql); err != nil { log.Fatalf("update failed: %v", err) } - stream, err = client.ExecuteQuery(ctx, queryReq) + results, err = client.ExecuteQuery(ctx, connectResp, queryReq.Sql) if err != nil { log.Fatalf("executeQuery after update failed: %v", err) } - fmt.Println("READ after UPDATE:") - results, err = drainQueryStream(stream) - if err != nil { - log.Fatalf("read after update failed: %v", err) + for _, msg := range results { + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) } + fmt.Println("READ after UPDATE:") var updatedRows []*pb.ResultRow for _, r := range results { if qr := r.GetQueryResult(); qr != nil { @@ -174,18 +163,17 @@ func main() { Session: connectResp, Sql: "DELETE FROM demo WHERE id = 1", } - if _, err = client.ExecuteUpdate(ctx, deleteReq); err != nil { + if _, err = client.ExecuteUpdate(ctx, connectResp, deleteReq.Sql); err != nil { log.Fatalf("delete failed: %v", err) } - stream, err = client.ExecuteQuery(ctx, queryReq) + results, err = client.ExecuteQuery(ctx, connectResp, queryReq.Sql) if err != nil { log.Fatalf("executeQuery after delete failed: %v", err) } - fmt.Println("READ after DELETE:") - results, err = drainQueryStream(stream) - if err != nil { - log.Fatalf("read after delete failed: %v", err) + for _, msg := range results { + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) } + fmt.Println("READ after DELETE:") var deletedRows int for _, r := range results { if qr := r.GetQueryResult(); qr != nil { @@ -195,8 +183,18 @@ func main() { if deletedRows != 0 { log.Fatalf("assert after delete failed: expected 0 rows, got %d", deletedRows) } + //close the simple round trip + _ = client.TerminateSession(context.Background(), connectResp) + + //staring with transcational database connections + if err = runTransactionRollbackRoundTrip(addr, backendURL, dbUser, dbPassword); err != nil { + log.Fatalf("transaction rollback round trip failed: %v", err) + } + if err = runTransactionCommitRoundTrip(addr, backendURL, dbUser, dbPassword); err != nil { + log.Fatalf("transaction commit round trip failed: %v", err) + } - _, _ = client.TerminateSession(context.Background(), connectResp) + client.Shutdown() } // drainQueryStream consumes the full ExecuteQuery stream, prints each OpResult, diff --git a/ojp-grpc-client-go/cmd/ojp-grpc-client/transaction_rollback.go b/ojp-grpc-client-go/cmd/ojp-grpc-client/transaction_rollback.go new file mode 100644 index 000000000..329ec5c8c --- /dev/null +++ b/ojp-grpc-client-go/cmd/ojp-grpc-client/transaction_rollback.go @@ -0,0 +1,191 @@ +package main + +import ( + "context" + "fmt" + "strings" + "time" + + ojpclient "github.com/open-j-proxy/ojp-client/internal/client" + pb "github.com/open-j-proxy/ojp-client/internal/gen/go/com/openjproxy/grpc" +) + +// runTransactionRollbackRoundTrip verifies local transaction rollback behavior. +// It inserts a row inside a transaction and asserts that the row disappears +// after calling RollbackTransaction. +func runTransactionRollbackRoundTrip(addr, backendURL, dbUser, dbPassword string) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + client := ojpclient.NewGrpcStatementServiceClient(addr) + defer client.Shutdown() + + session, err := client.Connect(ctx, &pb.ConnectionDetails{ + Url: backendURL, + User: dbUser, + Password: dbPassword, + ClientUUID: "go-example-client-tx-rollback", + }) + if err != nil { + return fmt.Errorf("connect failed: %w", err) + } + defer func() { + _ = client.TerminateSession(context.Background(), session) + }() + + if strings.HasPrefix(strings.ToLower(backendURL), "jdbc:db2:") { + if _, err = client.ExecuteUpdate(ctx, session, "SET SCHEMA DB2INST1"); err != nil { + return fmt.Errorf("set schema failed: %w", err) + } + } + + // CREATE + if _, err = client.ExecuteUpdate(ctx, session, "CREATE TABLE IF NOT EXISTS demo(id INT NOT NULL PRIMARY KEY, name VARCHAR(100))"); err != nil { + return fmt.Errorf("create table failed: %w", err) + } + + // DELETE + if _, err = client.ExecuteUpdate(ctx, session, "DELETE FROM demo WHERE id = 2"); err != nil { + return fmt.Errorf("cleanup delete failed: %w", err) + } + + txSession, err := client.StartTransaction(ctx, session) + if err != nil { + return fmt.Errorf("start transaction failed: %w", err) + } + fmt.Println("TRANSACTION started") + + // INSERT + if _, err = client.ExecuteUpdate(ctx, txSession, "INSERT INTO demo(id, name) VALUES (2, 'hello in tx')"); err != nil { + return fmt.Errorf("insert in transaction failed: %w", err) + } + + // READ + beforeRollbackResults, err := client.ExecuteQuery(ctx, txSession, "SELECT id, name FROM demo WHERE id = 2") + if err != nil { + return fmt.Errorf("execute query before rollback failed: %w", err) + } + for _, msg := range beforeRollbackResults { + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) + } + fmt.Println("READ inside TRANSACTION before ROLLBACK:") + var rowsBeforeRollback int + for _, r := range beforeRollbackResults { + if qr := r.GetQueryResult(); qr != nil { + rowsBeforeRollback += len(qr.GetRows()) + } + } + if rowsBeforeRollback != 1 { + return fmt.Errorf("assert before rollback failed: expected 1 row, got %d", rowsBeforeRollback) + } + + sessionAfterRollback, err := client.RollbackTransaction(ctx, txSession) + if err != nil { + return fmt.Errorf("rollback transaction failed: %w", err) + } + fmt.Println("TRANSACTION rolled back") + + // READ + afterRollbackResults, err := client.ExecuteQuery(ctx, sessionAfterRollback, "SELECT id, name FROM demo WHERE id = 2") + if err != nil { + return fmt.Errorf("execute query after rollback failed: %w", err) + } + for _, msg := range afterRollbackResults { + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) + } + fmt.Println("READ after ROLLBACK:") + var rowsAfterRollback int + for _, r := range afterRollbackResults { + if qr := r.GetQueryResult(); qr != nil { + rowsAfterRollback += len(qr.GetRows()) + } + } + if rowsAfterRollback != 0 { + return fmt.Errorf("assert after rollback failed: expected 0 rows, got %d", rowsAfterRollback) + } + + return nil +} + +// runTransactionCommitRoundTrip verifies local transaction commit behavior. +// It inserts a row inside a transaction and asserts that the row remains +// visible after calling CommitTransaction. +func runTransactionCommitRoundTrip(addr, backendURL, dbUser, dbPassword string) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + client := ojpclient.NewGrpcStatementServiceClient(addr) + defer client.Shutdown() + + session, err := client.Connect(ctx, &pb.ConnectionDetails{ + Url: backendURL, + User: dbUser, + Password: dbPassword, + ClientUUID: "go-example-client-tx-commit", + }) + if err != nil { + return fmt.Errorf("connect failed: %w", err) + } + defer func() { + _ = client.TerminateSession(context.Background(), session) + }() + + if strings.HasPrefix(strings.ToLower(backendURL), "jdbc:db2:") { + if _, err = client.ExecuteUpdate(ctx, session, "SET SCHEMA DB2INST1"); err != nil { + return fmt.Errorf("set schema failed: %w", err) + } + } + + // CREATE + if _, err = client.ExecuteUpdate(ctx, session, "CREATE TABLE IF NOT EXISTS demo(id INT NOT NULL PRIMARY KEY, name VARCHAR(100))"); err != nil { + return fmt.Errorf("create table failed: %w", err) + } + + // DELETE + if _, err = client.ExecuteUpdate(ctx, session, "DELETE FROM demo WHERE id = 3"); err != nil { + return fmt.Errorf("cleanup delete failed: %w", err) + } + + txSession, err := client.StartTransaction(ctx, session) + if err != nil { + return fmt.Errorf("start transaction failed: %w", err) + } + fmt.Println("TRANSACTION started for COMMIT test") + + // INSERT + if _, err = client.ExecuteUpdate(ctx, txSession, "INSERT INTO demo(id, name) VALUES (3, 'hello commit tx')"); err != nil { + return fmt.Errorf("insert in transaction failed: %w", err) + } + + sessionAfterCommit, err := client.CommitTransaction(ctx, txSession) + if err != nil { + return fmt.Errorf("commit transaction failed: %w", err) + } + fmt.Println("TRANSACTION committed") + + // READ + afterCommitResults, err := client.ExecuteQuery(ctx, sessionAfterCommit, "SELECT id, name FROM demo WHERE id = 3") + if err != nil { + return fmt.Errorf("execute query after commit failed: %w", err) + } + for _, msg := range afterCommitResults { + fmt.Printf("opResult: type=%v uuid=%s\n", msg.GetType(), msg.GetUuid()) + } + fmt.Println("READ after COMMIT:") + var rowsAfterCommit int + for _, r := range afterCommitResults { + if qr := r.GetQueryResult(); qr != nil { + rowsAfterCommit += len(qr.GetRows()) + } + } + if rowsAfterCommit != 1 { + return fmt.Errorf("assert after commit failed: expected 1 row, got %d", rowsAfterCommit) + } + + // DELETE + if _, err = client.ExecuteUpdate(ctx, sessionAfterCommit, "DELETE FROM demo WHERE id = 3"); err != nil { + return fmt.Errorf("post-commit cleanup delete failed: %w", err) + } + + return nil +}