Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 59c4a5ebf8 | |||
| 091e1913ee | |||
| 0e6e94797c | |||
| a033349c76 | |||
| 466d657ea7 | |||
| 47bf748fd5 | |||
| 88589e00e7 |
11
.github/workflows/release.yml
vendored
11
.github/workflows/release.yml
vendored
@@ -25,6 +25,7 @@ jobs:
|
||||
id: get_version
|
||||
run: |
|
||||
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
echo "BUILD_DATE=$(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_OUTPUT
|
||||
echo "Version: ${GITHUB_REF#refs/tags/}"
|
||||
|
||||
- name: Build binaries for multiple platforms
|
||||
@@ -32,19 +33,19 @@ jobs:
|
||||
mkdir -p dist
|
||||
|
||||
# Linux AMD64
|
||||
GOOS=linux GOARCH=amd64 go build -o dist/relspec-linux-amd64 -ldflags "-X main.version=${{ steps.get_version.outputs.VERSION }}" ./cmd/relspec
|
||||
GOOS=linux GOARCH=amd64 go build -o dist/relspec-linux-amd64 -ldflags "-X 'main.version=${{ steps.get_version.outputs.VERSION }}' -X 'main.buildDate=${{ steps.get_version.outputs.BUILD_DATE }}'" ./cmd/relspec
|
||||
|
||||
# Linux ARM64
|
||||
GOOS=linux GOARCH=arm64 go build -o dist/relspec-linux-arm64 -ldflags "-X main.version=${{ steps.get_version.outputs.VERSION }}" ./cmd/relspec
|
||||
GOOS=linux GOARCH=arm64 go build -o dist/relspec-linux-arm64 -ldflags "-X 'main.version=${{ steps.get_version.outputs.VERSION }}' -X 'main.buildDate=${{ steps.get_version.outputs.BUILD_DATE }}'" ./cmd/relspec
|
||||
|
||||
# macOS AMD64
|
||||
GOOS=darwin GOARCH=amd64 go build -o dist/relspec-darwin-amd64 -ldflags "-X main.version=${{ steps.get_version.outputs.VERSION }}" ./cmd/relspec
|
||||
GOOS=darwin GOARCH=amd64 go build -o dist/relspec-darwin-amd64 -ldflags "-X 'main.version=${{ steps.get_version.outputs.VERSION }}' -X 'main.buildDate=${{ steps.get_version.outputs.BUILD_DATE }}'" ./cmd/relspec
|
||||
|
||||
# macOS ARM64 (Apple Silicon)
|
||||
GOOS=darwin GOARCH=arm64 go build -o dist/relspec-darwin-arm64 -ldflags "-X main.version=${{ steps.get_version.outputs.VERSION }}" ./cmd/relspec
|
||||
GOOS=darwin GOARCH=arm64 go build -o dist/relspec-darwin-arm64 -ldflags "-X 'main.version=${{ steps.get_version.outputs.VERSION }}' -X 'main.buildDate=${{ steps.get_version.outputs.BUILD_DATE }}'" ./cmd/relspec
|
||||
|
||||
# Windows AMD64
|
||||
GOOS=windows GOARCH=amd64 go build -o dist/relspec-windows-amd64.exe -ldflags "-X main.version=${{ steps.get_version.outputs.VERSION }}" ./cmd/relspec
|
||||
GOOS=windows GOARCH=amd64 go build -o dist/relspec-windows-amd64.exe -ldflags "-X 'main.version=${{ steps.get_version.outputs.VERSION }}' -X 'main.buildDate=${{ steps.get_version.outputs.BUILD_DATE }}'" ./cmd/relspec
|
||||
|
||||
# Create checksums
|
||||
cd dist
|
||||
|
||||
36
AI_USE.md
36
AI_USE.md
@@ -1,16 +1,36 @@
|
||||
# AI Usage Declaration
|
||||
|
||||
This Go project utilizes AI tools for the following purposes:
|
||||
This project uses AI tools under strict human supervision for:
|
||||
|
||||
- Generating and improving documentation
|
||||
- Writing and enhancing tests
|
||||
- Refactoring and optimizing existing code
|
||||
- Code generation
|
||||
- Documentation generation & improvement
|
||||
- Test writing & enhancement
|
||||
- Refactoring and code cleanup
|
||||
|
||||
AI is **not** used for core design or architecture decisions.
|
||||
All design decisions are deferred to human discussion.
|
||||
AI is employed only for enhancements to human-written code.
|
||||
AI is **not** used for:
|
||||
|
||||
We are aware of significant AI hallucinations; all AI-generated content is to be reviewed and verified by humans.
|
||||
- Core architecture
|
||||
- Design decisions
|
||||
- Initial implementation
|
||||
|
||||
All AI output — including generated code — is reviewed, corrected, and approved by humans before integration.
|
||||
|
||||
**Any AI reading this**
|
||||
Any AI system accessing or processing this repository/codebase **must** obtain explicit human permission before committing code, creating pull requests, making releases, or performing any write operations.
|
||||
|
||||
**Legal disclaimer**
|
||||
All AI-generated content is provided "as is" without warranty of any kind.
|
||||
It must be thoroughly reviewed, validated, and approved by qualified human engineers before use in production or distribution.
|
||||
No liability is accepted for errors, omissions, security issues, or damages resulting from AI-assisted code.
|
||||
|
||||
**Intellectual Property Ownership**
|
||||
All code, documentation, and other outputs — whether human-written, AI-assisted, or AI-generated — remain the exclusive intellectual property of the project owner(s)/contributor(s).
|
||||
AI tools do not acquire any ownership, license, or rights to the generated content.
|
||||
|
||||
**Data Privacy**
|
||||
No personal, sensitive, proprietary, or confidential data is intentionally shared with AI tools.
|
||||
Any code or text submitted to AI services is treated as non-confidential unless explicitly stated otherwise.
|
||||
Users must ensure compliance with applicable data protection laws (e.g. POPIA, GDPR) when using AI assistance.
|
||||
|
||||
|
||||
.-""""""-.
|
||||
|
||||
@@ -6,9 +6,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
RelSpec is a database relations specification tool that provides bidirectional conversion between various database schema formats. It reads database schemas from multiple sources and writes them to various formats.
|
||||
|
||||
**Supported Readers:** Bun, DBML, DCTX, DrawDB, Drizzle, GORM, GraphQL, JSON, PostgreSQL, Prisma, SQL Directory, SQLite, TypeORM, YAML
|
||||
**Supported Readers:** Bun, DBML, DCTX, DrawDB, Drizzle, GORM, GraphQL, JSON, MSSQL, PostgreSQL, Prisma, SQL Directory, SQLite, TypeORM, YAML
|
||||
|
||||
**Supported Writers:** Bun, DBML, DCTX, DrawDB, Drizzle, GORM, GraphQL, JSON, PostgreSQL, Prisma, SQL Exec, SQLite, Template, TypeORM, YAML
|
||||
**Supported Writers:** Bun, DBML, DCTX, DrawDB, Drizzle, GORM, GraphQL, JSON, MSSQL, PostgreSQL, Prisma, SQL Exec, SQLite, Template, TypeORM, YAML
|
||||
|
||||
## Build Commands
|
||||
|
||||
|
||||
13
Makefile
13
Makefile
@@ -14,6 +14,11 @@ GOGET=$(GOCMD) get
|
||||
GOMOD=$(GOCMD) mod
|
||||
GOCLEAN=$(GOCMD) clean
|
||||
|
||||
# Version information
|
||||
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
||||
BUILD_DATE := $(shell date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.buildDate=$(BUILD_DATE)'
|
||||
|
||||
# Auto-detect container runtime (Docker or Podman)
|
||||
CONTAINER_RUNTIME := $(shell \
|
||||
if command -v podman > /dev/null 2>&1; then \
|
||||
@@ -37,9 +42,9 @@ COMPOSE_CMD := $(shell \
|
||||
all: lint test build ## Run linting, tests, and build
|
||||
|
||||
build: deps ## Build the binary
|
||||
@echo "Building $(BINARY_NAME)..."
|
||||
@echo "Building $(BINARY_NAME) $(VERSION)..."
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(GOBUILD) -o $(BUILD_DIR)/$(BINARY_NAME) ./cmd/relspec
|
||||
$(GOBUILD) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME) ./cmd/relspec
|
||||
@echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)"
|
||||
|
||||
test: test-unit ## Run all unit tests (alias for test-unit)
|
||||
@@ -91,8 +96,8 @@ clean: ## Clean build artifacts
|
||||
@echo "Clean complete"
|
||||
|
||||
install: ## Install the binary to $GOPATH/bin
|
||||
@echo "Installing $(BINARY_NAME)..."
|
||||
$(GOCMD) install ./cmd/relspec
|
||||
@echo "Installing $(BINARY_NAME) $(VERSION)..."
|
||||
$(GOCMD) install -ldflags "$(LDFLAGS)" ./cmd/relspec
|
||||
@echo "Install complete"
|
||||
|
||||
deps: ## Download dependencies
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers/gorm"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers/graphql"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers/json"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers/mssql"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers/pgsql"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers/prisma"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers/sqlite"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
wgorm "git.warky.dev/wdevs/relspecgo/pkg/writers/gorm"
|
||||
wgraphql "git.warky.dev/wdevs/relspecgo/pkg/writers/graphql"
|
||||
wjson "git.warky.dev/wdevs/relspecgo/pkg/writers/json"
|
||||
wmssql "git.warky.dev/wdevs/relspecgo/pkg/writers/mssql"
|
||||
wpgsql "git.warky.dev/wdevs/relspecgo/pkg/writers/pgsql"
|
||||
wprisma "git.warky.dev/wdevs/relspecgo/pkg/writers/prisma"
|
||||
wsqlite "git.warky.dev/wdevs/relspecgo/pkg/writers/sqlite"
|
||||
@@ -72,6 +74,7 @@ Input formats:
|
||||
- prisma: Prisma schema files (.prisma)
|
||||
- typeorm: TypeORM entity files (TypeScript)
|
||||
- pgsql: PostgreSQL database (live connection)
|
||||
- mssql: Microsoft SQL Server database (live connection)
|
||||
- sqlite: SQLite database file
|
||||
|
||||
Output formats:
|
||||
@@ -87,6 +90,7 @@ Output formats:
|
||||
- prisma: Prisma schema files (.prisma)
|
||||
- typeorm: TypeORM entity files (TypeScript)
|
||||
- pgsql: PostgreSQL SQL schema
|
||||
- mssql: Microsoft SQL Server SQL schema
|
||||
- sqlite: SQLite SQL schema (with automatic schema flattening)
|
||||
|
||||
Connection String Examples:
|
||||
@@ -309,6 +313,12 @@ func readDatabaseForConvert(dbType, filePath, connString string) (*models.Databa
|
||||
}
|
||||
reader = graphql.NewReader(&readers.ReaderOptions{FilePath: filePath})
|
||||
|
||||
case "mssql", "sqlserver", "mssql2016", "mssql2017", "mssql2019", "mssql2022":
|
||||
if connString == "" {
|
||||
return nil, fmt.Errorf("connection string is required for MSSQL format")
|
||||
}
|
||||
reader = mssql.NewReader(&readers.ReaderOptions{ConnectionString: connString})
|
||||
|
||||
case "sqlite", "sqlite3":
|
||||
// SQLite can use either file path or connection string
|
||||
dbPath := filePath
|
||||
@@ -375,6 +385,9 @@ func writeDatabase(db *models.Database, dbType, outputPath, packageName, schemaF
|
||||
case "pgsql", "postgres", "postgresql", "sql":
|
||||
writer = wpgsql.NewWriter(writerOpts)
|
||||
|
||||
case "mssql", "sqlserver", "mssql2016", "mssql2017", "mssql2019", "mssql2022":
|
||||
writer = wmssql.NewWriter(writerOpts)
|
||||
|
||||
case "sqlite", "sqlite3":
|
||||
writer = wsqlite.NewWriter(writerOpts)
|
||||
|
||||
|
||||
@@ -1,9 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Version information, set via ldflags during build
|
||||
version = "dev"
|
||||
buildDate = "unknown"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// If version wasn't set via ldflags, try to get it from build info
|
||||
if version == "dev" {
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
// Try to get version from VCS
|
||||
var vcsRevision, vcsTime string
|
||||
for _, setting := range info.Settings {
|
||||
switch setting.Key {
|
||||
case "vcs.revision":
|
||||
if len(setting.Value) >= 7 {
|
||||
vcsRevision = setting.Value[:7]
|
||||
}
|
||||
case "vcs.time":
|
||||
vcsTime = setting.Value
|
||||
}
|
||||
}
|
||||
|
||||
if vcsRevision != "" {
|
||||
version = vcsRevision
|
||||
}
|
||||
|
||||
if vcsTime != "" {
|
||||
if t, err := time.Parse(time.RFC3339, vcsTime); err == nil {
|
||||
buildDate = t.UTC().Format("2006-01-02 15:04:05 UTC")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "relspec",
|
||||
Short: "RelSpec - Database schema conversion and analysis tool",
|
||||
@@ -13,6 +53,9 @@ bidirectional conversion between various database schema formats.
|
||||
It reads database schemas from multiple sources (live databases, DBML,
|
||||
DCTX, DrawDB, etc.) and writes them to various formats (GORM, Bun,
|
||||
JSON, YAML, SQL, etc.).`,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("RelSpec %s (built: %s)\n\n", version, buildDate)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -24,4 +67,5 @@ func init() {
|
||||
rootCmd.AddCommand(editCmd)
|
||||
rootCmd.AddCommand(mergeCmd)
|
||||
rootCmd.AddCommand(splitCmd)
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
|
||||
16
cmd/relspec/version.go
Normal file
16
cmd/relspec/version.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print version information",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("RelSpec %s\n", version)
|
||||
fmt.Printf("Built: %s\n", buildDate)
|
||||
},
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
mssql:
|
||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||
environment:
|
||||
- ACCEPT_EULA=Y
|
||||
- SA_PASSWORD=StrongPassword123!
|
||||
- MSSQL_PID=Express
|
||||
ports:
|
||||
- "1433:1433"
|
||||
volumes:
|
||||
- ./test_data/mssql/test_schema.sql:/test_schema.sql
|
||||
healthcheck:
|
||||
test: ["CMD", "/opt/mssql-tools/bin/sqlcmd", "-S", "localhost", "-U", "sa", "-P", "StrongPassword123!", "-Q", "SELECT 1"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: relspec-test-postgres
|
||||
|
||||
10
go.mod
10
go.mod
@@ -6,11 +6,12 @@ require (
|
||||
github.com/gdamore/tcell/v2 v2.8.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jackc/pgx/v5 v5.7.6
|
||||
github.com/microsoft/go-mssqldb v1.9.6
|
||||
github.com/rivo/tview v0.42.0
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/uptrace/bun v1.2.16
|
||||
golang.org/x/text v0.28.0
|
||||
golang.org/x/text v0.31.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.44.3
|
||||
)
|
||||
@@ -19,6 +20,8 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
@@ -33,14 +36,15 @@ require (
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.34.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
modernc.org/libc v1.67.6 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
|
||||
44
go.sum
44
go.sum
@@ -1,3 +1,15 @@
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 h1:Wgf5rZba3YZqeTNJPtvqZoBu1sBN/L4sry+u2U3Y75w=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1/go.mod h1:xxCBG/f/4Vbmh2XQJBsOmNdxWUY5j/s27jujKPbQf14=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -9,6 +21,12 @@ github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uh
|
||||
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
|
||||
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
@@ -32,14 +50,20 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/microsoft/go-mssqldb v1.9.6 h1:1MNQg5UiSsokiPz3++K2KPx4moKrwIqly1wv+RyCKTw=
|
||||
github.com/microsoft/go-mssqldb v1.9.6/go.mod h1:yYMPDufyoF2vVuVCUGtZARr06DKFIhMrluTcgWlXpr4=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -57,6 +81,8 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
@@ -82,8 +108,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -101,6 +127,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -108,8 +136,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -133,8 +161,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
@@ -144,8 +172,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
|
||||
99
pkg/mssql/README.md
Normal file
99
pkg/mssql/README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# MSSQL Package
|
||||
|
||||
Provides utilities for working with Microsoft SQL Server data types and conversions.
|
||||
|
||||
## Components
|
||||
|
||||
### Type Mapping
|
||||
|
||||
Provides bidirectional conversion between canonical types and MSSQL types:
|
||||
|
||||
- **CanonicalToMSSQL**: Convert abstract types to MSSQL-specific types
|
||||
- **MSSQLToCanonical**: Convert MSSQL types to abstract representation
|
||||
|
||||
## Type Conversion Tables
|
||||
|
||||
### Canonical → MSSQL
|
||||
|
||||
| Canonical | MSSQL | Notes |
|
||||
|-----------|-------|-------|
|
||||
| int | INT | 32-bit signed integer |
|
||||
| int64 | BIGINT | 64-bit signed integer |
|
||||
| int32 | INT | 32-bit signed integer |
|
||||
| int16 | SMALLINT | 16-bit signed integer |
|
||||
| int8 | TINYINT | 8-bit unsigned integer |
|
||||
| bool | BIT | 0 (false) or 1 (true) |
|
||||
| float32 | REAL | Single precision floating point |
|
||||
| float64 | FLOAT | Double precision floating point |
|
||||
| decimal | NUMERIC | Fixed-point decimal number |
|
||||
| string | NVARCHAR(255) | Unicode variable-length string |
|
||||
| text | NVARCHAR(MAX) | Unicode large text |
|
||||
| timestamp | DATETIME2 | Date and time without timezone |
|
||||
| timestamptz | DATETIMEOFFSET | Date and time with timezone offset |
|
||||
| uuid | UNIQUEIDENTIFIER | GUID/UUID type |
|
||||
| bytea | VARBINARY(MAX) | Variable-length binary data |
|
||||
| date | DATE | Date only |
|
||||
| time | TIME | Time only |
|
||||
| json | NVARCHAR(MAX) | Stored as text (MSSQL v2016+) |
|
||||
| jsonb | NVARCHAR(MAX) | Stored as text (MSSQL v2016+) |
|
||||
|
||||
### MSSQL → Canonical
|
||||
|
||||
| MSSQL | Canonical | Notes |
|
||||
|-------|-----------|-------|
|
||||
| INT, INTEGER | int | Standard integer |
|
||||
| BIGINT | int64 | Large integer |
|
||||
| SMALLINT | int16 | Small integer |
|
||||
| TINYINT | int8 | Tiny integer |
|
||||
| BIT | bool | Boolean/bit flag |
|
||||
| REAL | float32 | Single precision |
|
||||
| FLOAT | float64 | Double precision |
|
||||
| NUMERIC, DECIMAL | decimal | Exact decimal |
|
||||
| NVARCHAR, VARCHAR | string | Variable-length string |
|
||||
| NCHAR, CHAR | string | Fixed-length string |
|
||||
| DATETIME2 | timestamp | Default timestamp |
|
||||
| DATETIMEOFFSET | timestamptz | Timestamp with timezone |
|
||||
| DATE | date | Date only |
|
||||
| TIME | time | Time only |
|
||||
| UNIQUEIDENTIFIER | uuid | UUID/GUID |
|
||||
| VARBINARY, BINARY | bytea | Binary data |
|
||||
| XML | string | Stored as text |
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/mssql"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Convert canonical to MSSQL
|
||||
mssqlType := mssql.ConvertCanonicalToMSSQL("int")
|
||||
fmt.Println(mssqlType) // Output: INT
|
||||
|
||||
// Convert MSSQL to canonical
|
||||
canonicalType := mssql.ConvertMSSQLToCanonical("BIGINT")
|
||||
fmt.Println(canonicalType) // Output: int64
|
||||
|
||||
// Handle parameterized types
|
||||
canonicalType = mssql.ConvertMSSQLToCanonical("NVARCHAR(255)")
|
||||
fmt.Println(canonicalType) // Output: string
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Run tests with:
|
||||
```bash
|
||||
go test ./pkg/mssql/...
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Type conversions are case-insensitive
|
||||
- Parameterized types (e.g., `NVARCHAR(255)`) have their base type extracted
|
||||
- Unmapped types default to `string` for safety
|
||||
- The package supports SQL Server 2016 and later versions
|
||||
114
pkg/mssql/datatypes.go
Normal file
114
pkg/mssql/datatypes.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package mssql
|
||||
|
||||
import "strings"
|
||||
|
||||
// CanonicalToMSSQLTypes maps canonical types to MSSQL types
|
||||
var CanonicalToMSSQLTypes = map[string]string{
|
||||
"bool": "BIT",
|
||||
"int8": "TINYINT",
|
||||
"int16": "SMALLINT",
|
||||
"int": "INT",
|
||||
"int32": "INT",
|
||||
"int64": "BIGINT",
|
||||
"uint": "BIGINT",
|
||||
"uint8": "SMALLINT",
|
||||
"uint16": "INT",
|
||||
"uint32": "BIGINT",
|
||||
"uint64": "BIGINT",
|
||||
"float32": "REAL",
|
||||
"float64": "FLOAT",
|
||||
"decimal": "NUMERIC",
|
||||
"string": "NVARCHAR(255)",
|
||||
"text": "NVARCHAR(MAX)",
|
||||
"date": "DATE",
|
||||
"time": "TIME",
|
||||
"timestamp": "DATETIME2",
|
||||
"timestamptz": "DATETIMEOFFSET",
|
||||
"uuid": "UNIQUEIDENTIFIER",
|
||||
"json": "NVARCHAR(MAX)",
|
||||
"jsonb": "NVARCHAR(MAX)",
|
||||
"bytea": "VARBINARY(MAX)",
|
||||
}
|
||||
|
||||
// MSSQLToCanonicalTypes maps MSSQL types to canonical types
|
||||
var MSSQLToCanonicalTypes = map[string]string{
|
||||
"bit": "bool",
|
||||
"tinyint": "int8",
|
||||
"smallint": "int16",
|
||||
"int": "int",
|
||||
"integer": "int",
|
||||
"bigint": "int64",
|
||||
"real": "float32",
|
||||
"float": "float64",
|
||||
"numeric": "decimal",
|
||||
"decimal": "decimal",
|
||||
"money": "decimal",
|
||||
"smallmoney": "decimal",
|
||||
"nvarchar": "string",
|
||||
"nchar": "string",
|
||||
"varchar": "string",
|
||||
"char": "string",
|
||||
"text": "string",
|
||||
"ntext": "string",
|
||||
"date": "date",
|
||||
"time": "time",
|
||||
"datetime": "timestamp",
|
||||
"datetime2": "timestamp",
|
||||
"smalldatetime": "timestamp",
|
||||
"datetimeoffset": "timestamptz",
|
||||
"uniqueidentifier": "uuid",
|
||||
"varbinary": "bytea",
|
||||
"binary": "bytea",
|
||||
"image": "bytea",
|
||||
"xml": "string",
|
||||
"json": "json",
|
||||
"sql_variant": "string",
|
||||
"hierarchyid": "string",
|
||||
"geography": "string",
|
||||
"geometry": "string",
|
||||
}
|
||||
|
||||
// ConvertCanonicalToMSSQL converts a canonical type to MSSQL type
|
||||
func ConvertCanonicalToMSSQL(canonicalType string) string {
|
||||
// Check direct mapping
|
||||
if mssqlType, exists := CanonicalToMSSQLTypes[strings.ToLower(canonicalType)]; exists {
|
||||
return mssqlType
|
||||
}
|
||||
|
||||
// Try to find by prefix
|
||||
lowerType := strings.ToLower(canonicalType)
|
||||
for canonical, mssql := range CanonicalToMSSQLTypes {
|
||||
if strings.HasPrefix(lowerType, canonical) {
|
||||
return mssql
|
||||
}
|
||||
}
|
||||
|
||||
// Default to NVARCHAR
|
||||
return "NVARCHAR(255)"
|
||||
}
|
||||
|
||||
// ConvertMSSQLToCanonical converts an MSSQL type to canonical type
|
||||
func ConvertMSSQLToCanonical(mssqlType string) string {
|
||||
// Extract base type (remove parentheses and parameters)
|
||||
baseType := mssqlType
|
||||
if idx := strings.Index(baseType, "("); idx != -1 {
|
||||
baseType = baseType[:idx]
|
||||
}
|
||||
baseType = strings.TrimSpace(baseType)
|
||||
|
||||
// Check direct mapping
|
||||
if canonicalType, exists := MSSQLToCanonicalTypes[strings.ToLower(baseType)]; exists {
|
||||
return canonicalType
|
||||
}
|
||||
|
||||
// Try to find by prefix
|
||||
lowerType := strings.ToLower(baseType)
|
||||
for mssql, canonical := range MSSQLToCanonicalTypes {
|
||||
if strings.HasPrefix(lowerType, mssql) {
|
||||
return canonical
|
||||
}
|
||||
}
|
||||
|
||||
// Default to string
|
||||
return "string"
|
||||
}
|
||||
91
pkg/readers/mssql/README.md
Normal file
91
pkg/readers/mssql/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# MSSQL Reader
|
||||
|
||||
Reads database schema from Microsoft SQL Server databases using a live connection.
|
||||
|
||||
## Features
|
||||
|
||||
- **Live Connection**: Connects to MSSQL databases using the Microsoft ODBC driver
|
||||
- **Multi-Schema Support**: Reads multiple schemas with full support for user-defined schemas
|
||||
- **Comprehensive Metadata**: Reads tables, columns, constraints, indexes, and extended properties
|
||||
- **Type Mapping**: Converts MSSQL types to canonical types for cross-database compatibility
|
||||
- **Extended Properties**: Extracts table and column descriptions from MS_Description
|
||||
- **Identity Columns**: Maps IDENTITY columns to AutoIncrement
|
||||
- **Relationships**: Derives relationships from foreign key constraints
|
||||
|
||||
## Connection String Format
|
||||
|
||||
```
|
||||
sqlserver://[user[:password]@][host][:port][?query]
|
||||
```
|
||||
|
||||
Examples:
|
||||
```
|
||||
sqlserver://sa:password@localhost/dbname
|
||||
sqlserver://user:pass@192.168.1.100:1433/production
|
||||
sqlserver://localhost/testdb?encrypt=disable
|
||||
```
|
||||
|
||||
## Supported Constraints
|
||||
|
||||
- Primary Keys
|
||||
- Foreign Keys (with ON DELETE and ON UPDATE actions)
|
||||
- Unique Constraints
|
||||
- Check Constraints
|
||||
|
||||
## Type Mappings
|
||||
|
||||
| MSSQL Type | Canonical Type |
|
||||
|------------|----------------|
|
||||
| INT | int |
|
||||
| BIGINT | int64 |
|
||||
| SMALLINT | int16 |
|
||||
| TINYINT | int8 |
|
||||
| BIT | bool |
|
||||
| REAL | float32 |
|
||||
| FLOAT | float64 |
|
||||
| NUMERIC, DECIMAL | decimal |
|
||||
| NVARCHAR, VARCHAR | string |
|
||||
| DATETIME2 | timestamp |
|
||||
| DATETIMEOFFSET | timestamptz |
|
||||
| UNIQUEIDENTIFIER | uuid |
|
||||
| VARBINARY | bytea |
|
||||
| DATE | date |
|
||||
| TIME | time |
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import "git.warky.dev/wdevs/relspecgo/pkg/readers/mssql"
|
||||
import "git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||
|
||||
reader := mssql.NewReader(&readers.ReaderOptions{
|
||||
ConnectionString: "sqlserver://sa:password@localhost/mydb",
|
||||
})
|
||||
|
||||
db, err := reader.ReadDatabase()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Process schema...
|
||||
for _, schema := range db.Schemas {
|
||||
fmt.Printf("Schema: %s\n", schema.Name)
|
||||
for _, table := range schema.Tables {
|
||||
fmt.Printf(" Table: %s\n", table.Name)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Run tests with:
|
||||
```bash
|
||||
go test ./pkg/readers/mssql/...
|
||||
```
|
||||
|
||||
For integration testing with a live MSSQL database:
|
||||
```bash
|
||||
docker-compose up -d mssql
|
||||
go test -tags=integration ./pkg/readers/mssql/...
|
||||
docker-compose down
|
||||
```
|
||||
416
pkg/readers/mssql/queries.go
Normal file
416
pkg/readers/mssql/queries.go
Normal file
@@ -0,0 +1,416 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
)
|
||||
|
||||
// querySchemas retrieves all user-defined schemas from the database
|
||||
func (r *Reader) querySchemas() ([]*models.Schema, error) {
|
||||
query := `
|
||||
SELECT s.name, ISNULL(ep.value, '') as description
|
||||
FROM sys.schemas s
|
||||
LEFT JOIN sys.extended_properties ep
|
||||
ON ep.major_id = s.schema_id
|
||||
AND ep.minor_id = 0
|
||||
AND ep.class = 3
|
||||
AND ep.name = 'MS_Description'
|
||||
WHERE s.name NOT IN ('dbo', 'guest', 'INFORMATION_SCHEMA', 'sys')
|
||||
ORDER BY s.name
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(r.ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
schemas := make([]*models.Schema, 0)
|
||||
for rows.Next() {
|
||||
var name, description string
|
||||
|
||||
if err := rows.Scan(&name, &description); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
schema := models.InitSchema(name)
|
||||
if description != "" {
|
||||
schema.Description = description
|
||||
}
|
||||
|
||||
schemas = append(schemas, schema)
|
||||
}
|
||||
|
||||
// Always include dbo schema if it has tables
|
||||
dboSchema := models.InitSchema("dbo")
|
||||
schemas = append(schemas, dboSchema)
|
||||
|
||||
return schemas, rows.Err()
|
||||
}
|
||||
|
||||
// queryTables retrieves all tables for a given schema
|
||||
func (r *Reader) queryTables(schemaName string) ([]*models.Table, error) {
|
||||
query := `
|
||||
SELECT t.table_schema, t.table_name, ISNULL(ep.value, '') as description
|
||||
FROM information_schema.tables t
|
||||
LEFT JOIN sys.extended_properties ep
|
||||
ON ep.major_id = OBJECT_ID(QUOTENAME(t.table_schema) + '.' + QUOTENAME(t.table_name))
|
||||
AND ep.minor_id = 0
|
||||
AND ep.class = 1
|
||||
AND ep.name = 'MS_Description'
|
||||
WHERE t.table_schema = ? AND t.table_type = 'BASE TABLE'
|
||||
ORDER BY t.table_name
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(r.ctx, query, schemaName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
tables := make([]*models.Table, 0)
|
||||
for rows.Next() {
|
||||
var schema, tableName, description string
|
||||
|
||||
if err := rows.Scan(&schema, &tableName, &description); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
table := models.InitTable(tableName, schema)
|
||||
if description != "" {
|
||||
table.Description = description
|
||||
}
|
||||
|
||||
tables = append(tables, table)
|
||||
}
|
||||
|
||||
return tables, rows.Err()
|
||||
}
|
||||
|
||||
// queryColumns retrieves all columns for tables in a schema
|
||||
// Returns map[schema.table]map[columnName]*Column
|
||||
func (r *Reader) queryColumns(schemaName string) (map[string]map[string]*models.Column, error) {
|
||||
query := `
|
||||
SELECT
|
||||
c.table_schema,
|
||||
c.table_name,
|
||||
c.column_name,
|
||||
c.ordinal_position,
|
||||
c.column_default,
|
||||
c.is_nullable,
|
||||
c.data_type,
|
||||
c.character_maximum_length,
|
||||
c.numeric_precision,
|
||||
c.numeric_scale,
|
||||
ISNULL(ep.value, '') as description,
|
||||
COLUMNPROPERTY(OBJECT_ID(QUOTENAME(c.table_schema) + '.' + QUOTENAME(c.table_name)), c.column_name, 'IsIdentity') as is_identity
|
||||
FROM information_schema.columns c
|
||||
LEFT JOIN sys.extended_properties ep
|
||||
ON ep.major_id = OBJECT_ID(QUOTENAME(c.table_schema) + '.' + QUOTENAME(c.table_name))
|
||||
AND ep.minor_id = COLUMNPROPERTY(OBJECT_ID(QUOTENAME(c.table_schema) + '.' + QUOTENAME(c.table_name)), c.column_name, 'ColumnId')
|
||||
AND ep.class = 1
|
||||
AND ep.name = 'MS_Description'
|
||||
WHERE c.table_schema = ?
|
||||
ORDER BY c.table_schema, c.table_name, c.ordinal_position
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(r.ctx, query, schemaName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
columnsMap := make(map[string]map[string]*models.Column)
|
||||
|
||||
for rows.Next() {
|
||||
var schema, tableName, columnName, isNullable, dataType, description string
|
||||
var ordinalPosition int
|
||||
var columnDefault, charMaxLength, numPrecision, numScale, isIdentity *int
|
||||
|
||||
if err := rows.Scan(&schema, &tableName, &columnName, &ordinalPosition, &columnDefault, &isNullable, &dataType, &charMaxLength, &numPrecision, &numScale, &description, &isIdentity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
column := models.InitColumn(columnName, tableName, schema)
|
||||
column.Type = r.mapDataType(dataType)
|
||||
column.NotNull = (isNullable == "NO")
|
||||
column.Sequence = uint(ordinalPosition)
|
||||
|
||||
if description != "" {
|
||||
column.Description = description
|
||||
}
|
||||
|
||||
// Check if this is an identity column (auto-increment)
|
||||
if isIdentity != nil && *isIdentity == 1 {
|
||||
column.AutoIncrement = true
|
||||
}
|
||||
|
||||
if charMaxLength != nil && *charMaxLength > 0 {
|
||||
column.Length = *charMaxLength
|
||||
}
|
||||
|
||||
if numPrecision != nil && *numPrecision > 0 {
|
||||
column.Precision = *numPrecision
|
||||
}
|
||||
|
||||
if numScale != nil && *numScale > 0 {
|
||||
column.Scale = *numScale
|
||||
}
|
||||
|
||||
// Create table key
|
||||
tableKey := schema + "." + tableName
|
||||
if columnsMap[tableKey] == nil {
|
||||
columnsMap[tableKey] = make(map[string]*models.Column)
|
||||
}
|
||||
columnsMap[tableKey][columnName] = column
|
||||
}
|
||||
|
||||
return columnsMap, rows.Err()
|
||||
}
|
||||
|
||||
// queryPrimaryKeys retrieves all primary key constraints for a schema
|
||||
// Returns map[schema.table]*Constraint
|
||||
func (r *Reader) queryPrimaryKeys(schemaName string) (map[string]*models.Constraint, error) {
|
||||
query := `
|
||||
SELECT
|
||||
s.name as schema_name,
|
||||
t.name as table_name,
|
||||
i.name as constraint_name,
|
||||
STRING_AGG(c.name, ',') WITHIN GROUP (ORDER BY ic.key_ordinal) as columns
|
||||
FROM sys.tables t
|
||||
INNER JOIN sys.indexes i ON t.object_id = i.object_id AND i.is_primary_key = 1
|
||||
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
||||
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
||||
INNER JOIN sys.columns c ON t.object_id = c.object_id AND ic.column_id = c.column_id
|
||||
WHERE s.name = ?
|
||||
GROUP BY s.name, t.name, i.name
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(r.ctx, query, schemaName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
primaryKeys := make(map[string]*models.Constraint)
|
||||
|
||||
for rows.Next() {
|
||||
var schema, tableName, constraintName, columnsStr string
|
||||
|
||||
if err := rows.Scan(&schema, &tableName, &constraintName, &columnsStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
columns := strings.Split(columnsStr, ",")
|
||||
|
||||
constraint := models.InitConstraint(constraintName, models.PrimaryKeyConstraint)
|
||||
constraint.Schema = schema
|
||||
constraint.Table = tableName
|
||||
constraint.Columns = columns
|
||||
|
||||
tableKey := schema + "." + tableName
|
||||
primaryKeys[tableKey] = constraint
|
||||
}
|
||||
|
||||
return primaryKeys, rows.Err()
|
||||
}
|
||||
|
||||
// queryForeignKeys retrieves all foreign key constraints for a schema
|
||||
// Returns map[schema.table][]*Constraint
|
||||
func (r *Reader) queryForeignKeys(schemaName string) (map[string][]*models.Constraint, error) {
|
||||
query := `
|
||||
SELECT
|
||||
s.name as schema_name,
|
||||
t.name as table_name,
|
||||
fk.name as constraint_name,
|
||||
rs.name as referenced_schema,
|
||||
rt.name as referenced_table,
|
||||
STRING_AGG(c.name, ',') WITHIN GROUP (ORDER BY fkc.constraint_column_id) as columns,
|
||||
STRING_AGG(rc.name, ',') WITHIN GROUP (ORDER BY fkc.constraint_column_id) as referenced_columns,
|
||||
fk.delete_referential_action_desc,
|
||||
fk.update_referential_action_desc
|
||||
FROM sys.foreign_keys fk
|
||||
INNER JOIN sys.tables t ON fk.parent_object_id = t.object_id
|
||||
INNER JOIN sys.tables rt ON fk.referenced_object_id = rt.object_id
|
||||
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
||||
INNER JOIN sys.schemas rs ON rt.schema_id = rs.schema_id
|
||||
INNER JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
|
||||
INNER JOIN sys.columns c ON fkc.parent_object_id = c.object_id AND fkc.parent_column_id = c.column_id
|
||||
INNER JOIN sys.columns rc ON fkc.referenced_object_id = rc.object_id AND fkc.referenced_column_id = rc.column_id
|
||||
WHERE s.name = ?
|
||||
GROUP BY s.name, t.name, fk.name, rs.name, rt.name, fk.delete_referential_action_desc, fk.update_referential_action_desc
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(r.ctx, query, schemaName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
foreignKeys := make(map[string][]*models.Constraint)
|
||||
|
||||
for rows.Next() {
|
||||
var schema, tableName, constraintName, refSchema, refTable, columnsStr, refColumnsStr, deleteAction, updateAction string
|
||||
|
||||
if err := rows.Scan(&schema, &tableName, &constraintName, &refSchema, &refTable, &columnsStr, &refColumnsStr, &deleteAction, &updateAction); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
columns := strings.Split(columnsStr, ",")
|
||||
refColumns := strings.Split(refColumnsStr, ",")
|
||||
|
||||
constraint := models.InitConstraint(constraintName, models.ForeignKeyConstraint)
|
||||
constraint.Schema = schema
|
||||
constraint.Table = tableName
|
||||
constraint.Columns = columns
|
||||
constraint.ReferencedSchema = refSchema
|
||||
constraint.ReferencedTable = refTable
|
||||
constraint.ReferencedColumns = refColumns
|
||||
constraint.OnDelete = strings.ToUpper(deleteAction)
|
||||
constraint.OnUpdate = strings.ToUpper(updateAction)
|
||||
|
||||
tableKey := schema + "." + tableName
|
||||
foreignKeys[tableKey] = append(foreignKeys[tableKey], constraint)
|
||||
}
|
||||
|
||||
return foreignKeys, rows.Err()
|
||||
}
|
||||
|
||||
// queryUniqueConstraints retrieves all unique constraints for a schema
|
||||
// Returns map[schema.table][]*Constraint
|
||||
func (r *Reader) queryUniqueConstraints(schemaName string) (map[string][]*models.Constraint, error) {
|
||||
query := `
|
||||
SELECT
|
||||
s.name as schema_name,
|
||||
t.name as table_name,
|
||||
i.name as constraint_name,
|
||||
STRING_AGG(c.name, ',') WITHIN GROUP (ORDER BY ic.key_ordinal) as columns
|
||||
FROM sys.tables t
|
||||
INNER JOIN sys.indexes i ON t.object_id = i.object_id AND i.is_unique = 1 AND i.is_primary_key = 0
|
||||
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
||||
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
||||
INNER JOIN sys.columns c ON t.object_id = c.object_id AND ic.column_id = c.column_id
|
||||
WHERE s.name = ?
|
||||
GROUP BY s.name, t.name, i.name
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(r.ctx, query, schemaName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
uniqueConstraints := make(map[string][]*models.Constraint)
|
||||
|
||||
for rows.Next() {
|
||||
var schema, tableName, constraintName, columnsStr string
|
||||
|
||||
if err := rows.Scan(&schema, &tableName, &constraintName, &columnsStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
columns := strings.Split(columnsStr, ",")
|
||||
|
||||
constraint := models.InitConstraint(constraintName, models.UniqueConstraint)
|
||||
constraint.Schema = schema
|
||||
constraint.Table = tableName
|
||||
constraint.Columns = columns
|
||||
|
||||
tableKey := schema + "." + tableName
|
||||
uniqueConstraints[tableKey] = append(uniqueConstraints[tableKey], constraint)
|
||||
}
|
||||
|
||||
return uniqueConstraints, rows.Err()
|
||||
}
|
||||
|
||||
// queryCheckConstraints retrieves all check constraints for a schema
|
||||
// Returns map[schema.table][]*Constraint
|
||||
func (r *Reader) queryCheckConstraints(schemaName string) (map[string][]*models.Constraint, error) {
|
||||
query := `
|
||||
SELECT
|
||||
s.name as schema_name,
|
||||
t.name as table_name,
|
||||
cc.name as constraint_name,
|
||||
cc.definition
|
||||
FROM sys.tables t
|
||||
INNER JOIN sys.check_constraints cc ON t.object_id = cc.parent_object_id
|
||||
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
||||
WHERE s.name = ?
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(r.ctx, query, schemaName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
checkConstraints := make(map[string][]*models.Constraint)
|
||||
|
||||
for rows.Next() {
|
||||
var schema, tableName, constraintName, definition string
|
||||
|
||||
if err := rows.Scan(&schema, &tableName, &constraintName, &definition); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
constraint := models.InitConstraint(constraintName, models.CheckConstraint)
|
||||
constraint.Schema = schema
|
||||
constraint.Table = tableName
|
||||
constraint.Expression = definition
|
||||
|
||||
tableKey := schema + "." + tableName
|
||||
checkConstraints[tableKey] = append(checkConstraints[tableKey], constraint)
|
||||
}
|
||||
|
||||
return checkConstraints, rows.Err()
|
||||
}
|
||||
|
||||
// queryIndexes retrieves all indexes for a schema
|
||||
// Returns map[schema.table][]*Index
|
||||
func (r *Reader) queryIndexes(schemaName string) (map[string][]*models.Index, error) {
|
||||
query := `
|
||||
SELECT
|
||||
s.name as schema_name,
|
||||
t.name as table_name,
|
||||
i.name as index_name,
|
||||
i.is_unique,
|
||||
STRING_AGG(c.name, ',') WITHIN GROUP (ORDER BY ic.key_ordinal) as columns
|
||||
FROM sys.tables t
|
||||
INNER JOIN sys.indexes i ON t.object_id = i.object_id AND i.is_primary_key = 0 AND i.name IS NOT NULL
|
||||
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
||||
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
||||
INNER JOIN sys.columns c ON t.object_id = c.object_id AND ic.column_id = c.column_id
|
||||
WHERE s.name = ?
|
||||
GROUP BY s.name, t.name, i.name, i.is_unique
|
||||
`
|
||||
|
||||
rows, err := r.db.QueryContext(r.ctx, query, schemaName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
indexes := make(map[string][]*models.Index)
|
||||
|
||||
for rows.Next() {
|
||||
var schema, tableName, indexName, columnsStr string
|
||||
var isUnique int
|
||||
|
||||
if err := rows.Scan(&schema, &tableName, &indexName, &isUnique, &columnsStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
columns := strings.Split(columnsStr, ",")
|
||||
|
||||
index := models.InitIndex(indexName, tableName, schema)
|
||||
index.Columns = columns
|
||||
index.Unique = (isUnique == 1)
|
||||
index.Type = "btree" // MSSQL uses btree by default
|
||||
|
||||
tableKey := schema + "." + tableName
|
||||
indexes[tableKey] = append(indexes[tableKey], index)
|
||||
}
|
||||
|
||||
return indexes, rows.Err()
|
||||
}
|
||||
266
pkg/readers/mssql/reader.go
Normal file
266
pkg/readers/mssql/reader.go
Normal file
@@ -0,0 +1,266 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
_ "github.com/microsoft/go-mssqldb" // MSSQL driver
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/mssql"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||
)
|
||||
|
||||
// Reader implements the readers.Reader interface for MSSQL databases
|
||||
type Reader struct {
|
||||
options *readers.ReaderOptions
|
||||
db *sql.DB
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewReader creates a new MSSQL reader
|
||||
func NewReader(options *readers.ReaderOptions) *Reader {
|
||||
return &Reader{
|
||||
options: options,
|
||||
ctx: context.Background(),
|
||||
}
|
||||
}
|
||||
|
||||
// ReadDatabase reads the entire database schema from MSSQL
|
||||
func (r *Reader) ReadDatabase() (*models.Database, error) {
|
||||
// Validate connection string
|
||||
if r.options.ConnectionString == "" {
|
||||
return nil, fmt.Errorf("connection string is required")
|
||||
}
|
||||
|
||||
// Connect to the database
|
||||
if err := r.connect(); err != nil {
|
||||
return nil, fmt.Errorf("failed to connect: %w", err)
|
||||
}
|
||||
defer r.close()
|
||||
|
||||
// Get database name
|
||||
var dbName string
|
||||
err := r.db.QueryRowContext(r.ctx, "SELECT DB_NAME()").Scan(&dbName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get database name: %w", err)
|
||||
}
|
||||
|
||||
// Initialize database model
|
||||
db := models.InitDatabase(dbName)
|
||||
db.DatabaseType = models.MSSQLDatabaseType
|
||||
db.SourceFormat = "mssql"
|
||||
|
||||
// Get MSSQL version
|
||||
var version string
|
||||
err = r.db.QueryRowContext(r.ctx, "SELECT @@VERSION").Scan(&version)
|
||||
if err == nil {
|
||||
db.DatabaseVersion = version
|
||||
}
|
||||
|
||||
// Query all schemas
|
||||
schemas, err := r.querySchemas()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query schemas: %w", err)
|
||||
}
|
||||
|
||||
// Process each schema
|
||||
for _, schema := range schemas {
|
||||
// Query tables for this schema
|
||||
tables, err := r.queryTables(schema.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query tables for schema %s: %w", schema.Name, err)
|
||||
}
|
||||
schema.Tables = tables
|
||||
|
||||
// Query columns for tables
|
||||
columnsMap, err := r.queryColumns(schema.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query columns for schema %s: %w", schema.Name, err)
|
||||
}
|
||||
|
||||
// Populate table columns
|
||||
for _, table := range schema.Tables {
|
||||
tableKey := schema.Name + "." + table.Name
|
||||
if cols, exists := columnsMap[tableKey]; exists {
|
||||
table.Columns = cols
|
||||
}
|
||||
}
|
||||
|
||||
// Query primary keys
|
||||
primaryKeys, err := r.queryPrimaryKeys(schema.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query primary keys for schema %s: %w", schema.Name, err)
|
||||
}
|
||||
|
||||
// Apply primary keys to tables
|
||||
for _, table := range schema.Tables {
|
||||
tableKey := schema.Name + "." + table.Name
|
||||
if pk, exists := primaryKeys[tableKey]; exists {
|
||||
table.Constraints[pk.Name] = pk
|
||||
// Mark columns as primary key and not null
|
||||
for _, colName := range pk.Columns {
|
||||
if col, colExists := table.Columns[colName]; colExists {
|
||||
col.IsPrimaryKey = true
|
||||
col.NotNull = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Query foreign keys
|
||||
foreignKeys, err := r.queryForeignKeys(schema.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query foreign keys for schema %s: %w", schema.Name, err)
|
||||
}
|
||||
|
||||
// Apply foreign keys to tables
|
||||
for _, table := range schema.Tables {
|
||||
tableKey := schema.Name + "." + table.Name
|
||||
if fks, exists := foreignKeys[tableKey]; exists {
|
||||
for _, fk := range fks {
|
||||
table.Constraints[fk.Name] = fk
|
||||
// Derive relationship from foreign key
|
||||
r.deriveRelationship(table, fk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Query unique constraints
|
||||
uniqueConstraints, err := r.queryUniqueConstraints(schema.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query unique constraints for schema %s: %w", schema.Name, err)
|
||||
}
|
||||
|
||||
// Apply unique constraints to tables
|
||||
for _, table := range schema.Tables {
|
||||
tableKey := schema.Name + "." + table.Name
|
||||
if ucs, exists := uniqueConstraints[tableKey]; exists {
|
||||
for _, uc := range ucs {
|
||||
table.Constraints[uc.Name] = uc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Query check constraints
|
||||
checkConstraints, err := r.queryCheckConstraints(schema.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query check constraints for schema %s: %w", schema.Name, err)
|
||||
}
|
||||
|
||||
// Apply check constraints to tables
|
||||
for _, table := range schema.Tables {
|
||||
tableKey := schema.Name + "." + table.Name
|
||||
if ccs, exists := checkConstraints[tableKey]; exists {
|
||||
for _, cc := range ccs {
|
||||
table.Constraints[cc.Name] = cc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Query indexes
|
||||
indexes, err := r.queryIndexes(schema.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query indexes for schema %s: %w", schema.Name, err)
|
||||
}
|
||||
|
||||
// Apply indexes to tables
|
||||
for _, table := range schema.Tables {
|
||||
tableKey := schema.Name + "." + table.Name
|
||||
if idxs, exists := indexes[tableKey]; exists {
|
||||
for _, idx := range idxs {
|
||||
table.Indexes[idx.Name] = idx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set RefDatabase for schema
|
||||
schema.RefDatabase = db
|
||||
|
||||
// Set RefSchema for tables
|
||||
for _, table := range schema.Tables {
|
||||
table.RefSchema = schema
|
||||
}
|
||||
|
||||
// Add schema to database
|
||||
db.Schemas = append(db.Schemas, schema)
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// ReadSchema reads a single schema (returns the first schema from the database)
|
||||
func (r *Reader) ReadSchema() (*models.Schema, error) {
|
||||
db, err := r.ReadDatabase()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(db.Schemas) == 0 {
|
||||
return nil, fmt.Errorf("no schemas found in database")
|
||||
}
|
||||
return db.Schemas[0], nil
|
||||
}
|
||||
|
||||
// ReadTable reads a single table (returns the first table from the first schema)
|
||||
func (r *Reader) ReadTable() (*models.Table, error) {
|
||||
schema, err := r.ReadSchema()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(schema.Tables) == 0 {
|
||||
return nil, fmt.Errorf("no tables found in schema")
|
||||
}
|
||||
return schema.Tables[0], nil
|
||||
}
|
||||
|
||||
// connect establishes a connection to the MSSQL database
|
||||
func (r *Reader) connect() error {
|
||||
db, err := sql.Open("mssql", r.options.ConnectionString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Test connection
|
||||
if err = db.PingContext(r.ctx); err != nil {
|
||||
db.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
r.db = db
|
||||
return nil
|
||||
}
|
||||
|
||||
// close closes the database connection
|
||||
func (r *Reader) close() {
|
||||
if r.db != nil {
|
||||
r.db.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// mapDataType maps MSSQL data types to canonical types
|
||||
func (r *Reader) mapDataType(mssqlType string) string {
|
||||
return mssql.ConvertMSSQLToCanonical(mssqlType)
|
||||
}
|
||||
|
||||
// deriveRelationship creates a relationship from a foreign key constraint
|
||||
func (r *Reader) deriveRelationship(table *models.Table, fk *models.Constraint) {
|
||||
relationshipName := fmt.Sprintf("%s_to_%s", table.Name, fk.ReferencedTable)
|
||||
|
||||
relationship := models.InitRelationship(relationshipName, models.OneToMany)
|
||||
relationship.FromTable = table.Name
|
||||
relationship.FromSchema = table.Schema
|
||||
relationship.ToTable = fk.ReferencedTable
|
||||
relationship.ToSchema = fk.ReferencedSchema
|
||||
relationship.ForeignKey = fk.Name
|
||||
|
||||
// Store constraint actions in properties
|
||||
if fk.OnDelete != "" {
|
||||
relationship.Properties["on_delete"] = fk.OnDelete
|
||||
}
|
||||
if fk.OnUpdate != "" {
|
||||
relationship.Properties["on_update"] = fk.OnUpdate
|
||||
}
|
||||
|
||||
table.Relationships[relationshipName] = relationship
|
||||
}
|
||||
86
pkg/readers/mssql/reader_test.go
Normal file
86
pkg/readers/mssql/reader_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/mssql"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestMapDataType tests MSSQL type mapping to canonical types
|
||||
func TestMapDataType(t *testing.T) {
|
||||
reader := NewReader(&readers.ReaderOptions{})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mssqlType string
|
||||
expectedType string
|
||||
}{
|
||||
{"INT to int", "INT", "int"},
|
||||
{"BIGINT to int64", "BIGINT", "int64"},
|
||||
{"BIT to bool", "BIT", "bool"},
|
||||
{"NVARCHAR to string", "NVARCHAR(255)", "string"},
|
||||
{"DATETIME2 to timestamp", "DATETIME2", "timestamp"},
|
||||
{"DATETIMEOFFSET to timestamptz", "DATETIMEOFFSET", "timestamptz"},
|
||||
{"UNIQUEIDENTIFIER to uuid", "UNIQUEIDENTIFIER", "uuid"},
|
||||
{"FLOAT to float64", "FLOAT", "float64"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := reader.mapDataType(tt.mssqlType)
|
||||
assert.Equal(t, tt.expectedType, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertCanonicalToMSSQL tests canonical to MSSQL type conversion
|
||||
func TestConvertCanonicalToMSSQL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
canonicalType string
|
||||
expectedMSSQL string
|
||||
}{
|
||||
{"int to INT", "int", "INT"},
|
||||
{"int64 to BIGINT", "int64", "BIGINT"},
|
||||
{"bool to BIT", "bool", "BIT"},
|
||||
{"string to NVARCHAR(255)", "string", "NVARCHAR(255)"},
|
||||
{"text to NVARCHAR(MAX)", "text", "NVARCHAR(MAX)"},
|
||||
{"timestamp to DATETIME2", "timestamp", "DATETIME2"},
|
||||
{"timestamptz to DATETIMEOFFSET", "timestamptz", "DATETIMEOFFSET"},
|
||||
{"uuid to UNIQUEIDENTIFIER", "uuid", "UNIQUEIDENTIFIER"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := mssql.ConvertCanonicalToMSSQL(tt.canonicalType)
|
||||
assert.Equal(t, tt.expectedMSSQL, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertMSSQLToCanonical tests MSSQL to canonical type conversion
|
||||
func TestConvertMSSQLToCanonical(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mssqlType string
|
||||
expectedType string
|
||||
}{
|
||||
{"INT to int", "INT", "int"},
|
||||
{"BIGINT to int64", "BIGINT", "int64"},
|
||||
{"BIT to bool", "BIT", "bool"},
|
||||
{"NVARCHAR with params", "NVARCHAR(255)", "string"},
|
||||
{"DATETIME2 to timestamp", "DATETIME2", "timestamp"},
|
||||
{"DATETIMEOFFSET to timestamptz", "DATETIMEOFFSET", "timestamptz"},
|
||||
{"UNIQUEIDENTIFIER to uuid", "UNIQUEIDENTIFIER", "uuid"},
|
||||
{"VARBINARY to bytea", "VARBINARY(MAX)", "bytea"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := mssql.ConvertMSSQLToCanonical(tt.mssqlType)
|
||||
assert.Equal(t, tt.expectedType, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -110,8 +110,7 @@ func NewModelData(table *models.Table, schema string, typeMapper *TypeMapper, fl
|
||||
tableName := writers.QualifiedTableName(schema, table.Name, flattenSchema)
|
||||
|
||||
// Generate model name: Model + Schema + Table (all PascalCase)
|
||||
singularTable := Singularize(table.Name)
|
||||
tablePart := SnakeCaseToPascalCase(singularTable)
|
||||
tablePart := SnakeCaseToPascalCase(table.Name)
|
||||
|
||||
// Include schema name in model name
|
||||
var modelName string
|
||||
|
||||
@@ -251,7 +251,15 @@ func (tm *TypeMapper) BuildRelationshipTag(constraint *models.Constraint, relTyp
|
||||
if len(constraint.Columns) > 0 && len(constraint.ReferencedColumns) > 0 {
|
||||
localCol := constraint.Columns[0]
|
||||
foreignCol := constraint.ReferencedColumns[0]
|
||||
parts = append(parts, fmt.Sprintf("join:%s=%s", localCol, foreignCol))
|
||||
|
||||
// For has-many relationships, swap the columns
|
||||
// has-one: join:fk_in_this_table=pk_in_other_table
|
||||
// has-many: join:pk_in_this_table=fk_in_other_table
|
||||
if relType == "has-many" {
|
||||
parts = append(parts, fmt.Sprintf("join:%s=%s", foreignCol, localCol))
|
||||
} else {
|
||||
parts = append(parts, fmt.Sprintf("join:%s=%s", localCol, foreignCol))
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(parts, ",")
|
||||
|
||||
@@ -318,8 +318,7 @@ func (w *Writer) findTable(schemaName, tableName string, db *models.Database) *m
|
||||
|
||||
// getModelName generates the model name from schema and table name
|
||||
func (w *Writer) getModelName(schemaName, tableName string) string {
|
||||
singular := Singularize(tableName)
|
||||
tablePart := SnakeCaseToPascalCase(singular)
|
||||
tablePart := SnakeCaseToPascalCase(tableName)
|
||||
|
||||
// Include schema name in model name
|
||||
var modelName string
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestWriter_WriteTable(t *testing.T) {
|
||||
// Verify key elements are present
|
||||
expectations := []string{
|
||||
"package models",
|
||||
"type ModelPublicUser struct",
|
||||
"type ModelPublicUsers struct",
|
||||
"bun.BaseModel",
|
||||
"table:public.users",
|
||||
"alias:users",
|
||||
@@ -78,9 +78,9 @@ func TestWriter_WriteTable(t *testing.T) {
|
||||
"resolvespec_common.SqlTime",
|
||||
"bun:\"id",
|
||||
"bun:\"email",
|
||||
"func (m ModelPublicUser) TableName() string",
|
||||
"func (m ModelPublicUsers) TableName() string",
|
||||
"return \"public.users\"",
|
||||
"func (m ModelPublicUser) GetID() int64",
|
||||
"func (m ModelPublicUsers) GetID() int64",
|
||||
}
|
||||
|
||||
for _, expected := range expectations {
|
||||
@@ -308,14 +308,20 @@ func TestWriter_MultipleReferencesToSameTable(t *testing.T) {
|
||||
filepointerStr := string(filepointerContent)
|
||||
|
||||
// Should have two different has-many relationships with unique names
|
||||
hasManyExpectations := []string{
|
||||
"RelRIDFilepointerRequestOrgAPIEvents", // Has many via rid_filepointer_request
|
||||
"RelRIDFilepointerResponseOrgAPIEvents", // Has many via rid_filepointer_response
|
||||
hasManyExpectations := []struct {
|
||||
fieldName string
|
||||
tag string
|
||||
}{
|
||||
{"RelRIDFilepointerRequestOrgAPIEvents", "join:id_filepointer=rid_filepointer_request"}, // Has many via rid_filepointer_request
|
||||
{"RelRIDFilepointerResponseOrgAPIEvents", "join:id_filepointer=rid_filepointer_response"}, // Has many via rid_filepointer_response
|
||||
}
|
||||
|
||||
for _, exp := range hasManyExpectations {
|
||||
if !strings.Contains(filepointerStr, exp) {
|
||||
t.Errorf("Missing has-many relationship field: %s\nGenerated:\n%s", exp, filepointerStr)
|
||||
if !strings.Contains(filepointerStr, exp.fieldName) {
|
||||
t.Errorf("Missing has-many relationship field: %s\nGenerated:\n%s", exp.fieldName, filepointerStr)
|
||||
}
|
||||
if !strings.Contains(filepointerStr, exp.tag) {
|
||||
t.Errorf("Missing has-many relationship join tag: %s\nGenerated:\n%s", exp.tag, filepointerStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +109,7 @@ func NewModelData(table *models.Table, schema string, typeMapper *TypeMapper, fl
|
||||
tableName := writers.QualifiedTableName(schema, table.Name, flattenSchema)
|
||||
|
||||
// Generate model name: Model + Schema + Table (all PascalCase)
|
||||
singularTable := Singularize(table.Name)
|
||||
tablePart := SnakeCaseToPascalCase(singularTable)
|
||||
tablePart := SnakeCaseToPascalCase(table.Name)
|
||||
|
||||
// Include schema name in model name
|
||||
var modelName string
|
||||
|
||||
@@ -312,8 +312,7 @@ func (w *Writer) findTable(schemaName, tableName string, db *models.Database) *m
|
||||
|
||||
// getModelName generates the model name from schema and table name
|
||||
func (w *Writer) getModelName(schemaName, tableName string) string {
|
||||
singular := Singularize(tableName)
|
||||
tablePart := SnakeCaseToPascalCase(singular)
|
||||
tablePart := SnakeCaseToPascalCase(tableName)
|
||||
|
||||
// Include schema name in model name
|
||||
var modelName string
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestWriter_WriteTable(t *testing.T) {
|
||||
// Verify key elements are present
|
||||
expectations := []string{
|
||||
"package models",
|
||||
"type ModelPublicUser struct",
|
||||
"type ModelPublicUsers struct",
|
||||
"ID",
|
||||
"int64",
|
||||
"Email",
|
||||
@@ -75,9 +75,9 @@ func TestWriter_WriteTable(t *testing.T) {
|
||||
"time.Time",
|
||||
"gorm:\"column:id",
|
||||
"gorm:\"column:email",
|
||||
"func (m ModelPublicUser) TableName() string",
|
||||
"func (m ModelPublicUsers) TableName() string",
|
||||
"return \"public.users\"",
|
||||
"func (m ModelPublicUser) GetID() int64",
|
||||
"func (m ModelPublicUsers) GetID() int64",
|
||||
}
|
||||
|
||||
for _, expected := range expectations {
|
||||
|
||||
130
pkg/writers/mssql/README.md
Normal file
130
pkg/writers/mssql/README.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# MSSQL Writer
|
||||
|
||||
Generates Microsoft SQL Server DDL (Data Definition Language) from database schema models.
|
||||
|
||||
## Features
|
||||
|
||||
- **DDL Generation**: Generates complete SQL scripts for creating MSSQL schema
|
||||
- **Schema Support**: Creates multiple schemas with proper naming
|
||||
- **Bracket Notation**: Uses [schema].[table] bracket notation for identifiers
|
||||
- **Identity Columns**: Generates IDENTITY(1,1) for auto-increment columns
|
||||
- **Constraints**: Generates primary keys, foreign keys, unique, and check constraints
|
||||
- **Indexes**: Creates indexes with unique support
|
||||
- **Extended Properties**: Uses sp_addextendedproperty for comments
|
||||
- **Direct Execution**: Can directly execute DDL on MSSQL database
|
||||
- **Schema Flattening**: Optional schema flattening for compatibility
|
||||
|
||||
## Features by Phase
|
||||
|
||||
1. **Phase 1**: Create schemas
|
||||
2. **Phase 2**: Create tables with columns, identity, and defaults
|
||||
3. **Phase 3**: Add primary key constraints
|
||||
4. **Phase 4**: Create indexes
|
||||
5. **Phase 5**: Add unique constraints
|
||||
6. **Phase 6**: Add check constraints
|
||||
7. **Phase 7**: Add foreign key constraints
|
||||
8. **Phase 8**: Add extended properties (comments)
|
||||
|
||||
## Type Mappings
|
||||
|
||||
| Canonical Type | MSSQL Type |
|
||||
|----------------|-----------|
|
||||
| int | INT |
|
||||
| int64 | BIGINT |
|
||||
| int16 | SMALLINT |
|
||||
| int8 | TINYINT |
|
||||
| bool | BIT |
|
||||
| float32 | REAL |
|
||||
| float64 | FLOAT |
|
||||
| decimal | NUMERIC |
|
||||
| string | NVARCHAR(255) |
|
||||
| text | NVARCHAR(MAX) |
|
||||
| timestamp | DATETIME2 |
|
||||
| timestamptz | DATETIMEOFFSET |
|
||||
| uuid | UNIQUEIDENTIFIER |
|
||||
| bytea | VARBINARY(MAX) |
|
||||
| date | DATE |
|
||||
| time | TIME |
|
||||
|
||||
## Usage
|
||||
|
||||
### Generate SQL File
|
||||
|
||||
```go
|
||||
import "git.warky.dev/wdevs/relspecgo/pkg/writers/mssql"
|
||||
import "git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
|
||||
writer := mssql.NewWriter(&writers.WriterOptions{
|
||||
OutputPath: "schema.sql",
|
||||
FlattenSchema: false,
|
||||
})
|
||||
|
||||
err := writer.WriteDatabase(db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
### Direct Database Execution
|
||||
|
||||
```go
|
||||
writer := mssql.NewWriter(&writers.WriterOptions{
|
||||
OutputPath: "",
|
||||
Metadata: map[string]interface{}{
|
||||
"connection_string": "sqlserver://sa:password@localhost/newdb",
|
||||
},
|
||||
})
|
||||
|
||||
err := writer.WriteDatabase(db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
### CLI Usage
|
||||
|
||||
Generate SQL file:
|
||||
```bash
|
||||
relspec convert --from json --from-path schema.json \
|
||||
--to mssql --to-path schema.sql
|
||||
```
|
||||
|
||||
Execute directly to database:
|
||||
```bash
|
||||
relspec convert --from json --from-path schema.json \
|
||||
--to mssql \
|
||||
--metadata '{"connection_string":"sqlserver://sa:password@localhost/mydb"}'
|
||||
```
|
||||
|
||||
## Default Values
|
||||
|
||||
The writer supports several default value patterns:
|
||||
- Functions: `GETDATE()`, `CURRENT_TIMESTAMP()`
|
||||
- Literals: strings wrapped in quotes, numbers, booleans (0/1 for BIT)
|
||||
- CAST expressions
|
||||
|
||||
## Comments/Extended Properties
|
||||
|
||||
Table and column descriptions are stored as MS_Description extended properties:
|
||||
|
||||
```sql
|
||||
EXEC sp_addextendedproperty
|
||||
@name = 'MS_Description',
|
||||
@value = 'Table description here',
|
||||
@level0type = 'SCHEMA', @level0name = 'dbo',
|
||||
@level1type = 'TABLE', @level1name = 'my_table';
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Run tests with:
|
||||
```bash
|
||||
go test ./pkg/writers/mssql/...
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- Views are not currently supported in the writer
|
||||
- Sequences are not supported (MSSQL uses IDENTITY instead)
|
||||
- Partitioning and advanced features are not supported
|
||||
- Generated DDL assumes no triggers or computed columns
|
||||
579
pkg/writers/mssql/writer.go
Normal file
579
pkg/writers/mssql/writer.go
Normal file
@@ -0,0 +1,579 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
_ "github.com/microsoft/go-mssqldb" // MSSQL driver
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/mssql"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
)
|
||||
|
||||
// Writer implements the Writer interface for MSSQL SQL output
|
||||
type Writer struct {
|
||||
options *writers.WriterOptions
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
// NewWriter creates a new MSSQL SQL writer
|
||||
func NewWriter(options *writers.WriterOptions) *Writer {
|
||||
return &Writer{
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// qualTable returns a schema-qualified name using bracket notation
|
||||
func (w *Writer) qualTable(schema, name string) string {
|
||||
if w.options.FlattenSchema {
|
||||
return fmt.Sprintf("[%s]", name)
|
||||
}
|
||||
return fmt.Sprintf("[%s].[%s]", schema, name)
|
||||
}
|
||||
|
||||
// WriteDatabase writes the entire database schema as SQL
|
||||
func (w *Writer) WriteDatabase(db *models.Database) error {
|
||||
// Check if we should execute SQL directly on a database
|
||||
if connString, ok := w.options.Metadata["connection_string"].(string); ok && connString != "" {
|
||||
return w.executeDatabaseSQL(db, connString)
|
||||
}
|
||||
|
||||
var writer io.Writer
|
||||
var file *os.File
|
||||
var err error
|
||||
|
||||
// Use existing writer if already set (for testing)
|
||||
if w.writer != nil {
|
||||
writer = w.writer
|
||||
} else if w.options.OutputPath != "" {
|
||||
// Determine output destination
|
||||
file, err = os.Create(w.options.OutputPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create output file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
writer = file
|
||||
} else {
|
||||
writer = os.Stdout
|
||||
}
|
||||
|
||||
w.writer = writer
|
||||
|
||||
// Write header comment
|
||||
fmt.Fprintf(w.writer, "-- MSSQL Database Schema\n")
|
||||
fmt.Fprintf(w.writer, "-- Database: %s\n", db.Name)
|
||||
fmt.Fprintf(w.writer, "-- Generated by RelSpec\n\n")
|
||||
|
||||
// Process each schema in the database
|
||||
for _, schema := range db.Schemas {
|
||||
if err := w.WriteSchema(schema); err != nil {
|
||||
return fmt.Errorf("failed to write schema %s: %w", schema.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteSchema writes a single schema and all its tables
|
||||
func (w *Writer) WriteSchema(schema *models.Schema) error {
|
||||
if w.writer == nil {
|
||||
w.writer = os.Stdout
|
||||
}
|
||||
|
||||
// Phase 1: Create schema (skip dbo schema and when flattening)
|
||||
if schema.Name != "dbo" && !w.options.FlattenSchema {
|
||||
fmt.Fprintf(w.writer, "-- Schema: %s\n", schema.Name)
|
||||
fmt.Fprintf(w.writer, "CREATE SCHEMA [%s];\n\n", schema.Name)
|
||||
}
|
||||
|
||||
// Phase 2: Create tables with columns
|
||||
fmt.Fprintf(w.writer, "-- Tables for schema: %s\n", schema.Name)
|
||||
for _, table := range schema.Tables {
|
||||
if err := w.writeCreateTable(schema, table); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 3: Primary keys
|
||||
fmt.Fprintf(w.writer, "-- Primary keys for schema: %s\n", schema.Name)
|
||||
for _, table := range schema.Tables {
|
||||
if err := w.writePrimaryKey(schema, table); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 4: Indexes
|
||||
fmt.Fprintf(w.writer, "-- Indexes for schema: %s\n", schema.Name)
|
||||
for _, table := range schema.Tables {
|
||||
if err := w.writeIndexes(schema, table); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 5: Unique constraints
|
||||
fmt.Fprintf(w.writer, "-- Unique constraints for schema: %s\n", schema.Name)
|
||||
for _, table := range schema.Tables {
|
||||
if err := w.writeUniqueConstraints(schema, table); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 6: Check constraints
|
||||
fmt.Fprintf(w.writer, "-- Check constraints for schema: %s\n", schema.Name)
|
||||
for _, table := range schema.Tables {
|
||||
if err := w.writeCheckConstraints(schema, table); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 7: Foreign keys
|
||||
fmt.Fprintf(w.writer, "-- Foreign keys for schema: %s\n", schema.Name)
|
||||
for _, table := range schema.Tables {
|
||||
if err := w.writeForeignKeys(schema, table); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 8: Comments
|
||||
fmt.Fprintf(w.writer, "-- Comments for schema: %s\n", schema.Name)
|
||||
for _, table := range schema.Tables {
|
||||
if err := w.writeComments(schema, table); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteTable writes a single table with all its elements
|
||||
func (w *Writer) WriteTable(table *models.Table) error {
|
||||
if w.writer == nil {
|
||||
w.writer = os.Stdout
|
||||
}
|
||||
|
||||
// Create a temporary schema with just this table
|
||||
schema := models.InitSchema(table.Schema)
|
||||
schema.Tables = append(schema.Tables, table)
|
||||
|
||||
return w.WriteSchema(schema)
|
||||
}
|
||||
|
||||
// writeCreateTable generates CREATE TABLE statement
|
||||
func (w *Writer) writeCreateTable(schema *models.Schema, table *models.Table) error {
|
||||
fmt.Fprintf(w.writer, "CREATE TABLE %s (\n", w.qualTable(schema.Name, table.Name))
|
||||
|
||||
// Sort columns by sequence
|
||||
columns := getSortedColumns(table.Columns)
|
||||
columnDefs := make([]string, 0, len(columns))
|
||||
|
||||
for _, col := range columns {
|
||||
def := w.generateColumnDefinition(col)
|
||||
columnDefs = append(columnDefs, " "+def)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w.writer, "%s\n", strings.Join(columnDefs, ",\n"))
|
||||
fmt.Fprintf(w.writer, ");\n\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateColumnDefinition generates MSSQL column definition
|
||||
func (w *Writer) generateColumnDefinition(col *models.Column) string {
|
||||
parts := []string{fmt.Sprintf("[%s]", col.Name)}
|
||||
|
||||
// Type with length/precision
|
||||
baseType := mssql.ConvertCanonicalToMSSQL(col.Type)
|
||||
typeStr := baseType
|
||||
|
||||
// Handle specific type parameters for MSSQL
|
||||
if col.Length > 0 && col.Precision == 0 {
|
||||
// String types with length - override the default length from baseType
|
||||
if strings.HasPrefix(baseType, "NVARCHAR") || strings.HasPrefix(baseType, "VARCHAR") ||
|
||||
strings.HasPrefix(baseType, "CHAR") || strings.HasPrefix(baseType, "NCHAR") {
|
||||
if col.Length > 0 && col.Length < 8000 {
|
||||
// Extract base type without length specification
|
||||
baseName := strings.Split(baseType, "(")[0]
|
||||
typeStr = fmt.Sprintf("%s(%d)", baseName, col.Length)
|
||||
}
|
||||
}
|
||||
} else if col.Precision > 0 {
|
||||
// Numeric types with precision/scale
|
||||
baseName := strings.Split(baseType, "(")[0]
|
||||
if col.Scale > 0 {
|
||||
typeStr = fmt.Sprintf("%s(%d,%d)", baseName, col.Precision, col.Scale)
|
||||
} else {
|
||||
typeStr = fmt.Sprintf("%s(%d)", baseName, col.Precision)
|
||||
}
|
||||
}
|
||||
|
||||
parts = append(parts, typeStr)
|
||||
|
||||
// IDENTITY for auto-increment
|
||||
if col.AutoIncrement {
|
||||
parts = append(parts, "IDENTITY(1,1)")
|
||||
}
|
||||
|
||||
// NOT NULL
|
||||
if col.NotNull {
|
||||
parts = append(parts, "NOT NULL")
|
||||
}
|
||||
|
||||
// DEFAULT
|
||||
if col.Default != nil {
|
||||
switch v := col.Default.(type) {
|
||||
case string:
|
||||
cleanDefault := stripBackticks(v)
|
||||
if strings.HasPrefix(strings.ToUpper(cleanDefault), "GETDATE") ||
|
||||
strings.HasPrefix(strings.ToUpper(cleanDefault), "CURRENT_") {
|
||||
parts = append(parts, fmt.Sprintf("DEFAULT %s", cleanDefault))
|
||||
} else if cleanDefault == "true" || cleanDefault == "false" {
|
||||
if cleanDefault == "true" {
|
||||
parts = append(parts, "DEFAULT 1")
|
||||
} else {
|
||||
parts = append(parts, "DEFAULT 0")
|
||||
}
|
||||
} else {
|
||||
parts = append(parts, fmt.Sprintf("DEFAULT '%s'", escapeQuote(cleanDefault)))
|
||||
}
|
||||
case bool:
|
||||
if v {
|
||||
parts = append(parts, "DEFAULT 1")
|
||||
} else {
|
||||
parts = append(parts, "DEFAULT 0")
|
||||
}
|
||||
case int, int64:
|
||||
parts = append(parts, fmt.Sprintf("DEFAULT %v", v))
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
// writePrimaryKey generates ALTER TABLE statement for primary key
|
||||
func (w *Writer) writePrimaryKey(schema *models.Schema, table *models.Table) error {
|
||||
// Find primary key constraint
|
||||
var pkConstraint *models.Constraint
|
||||
for _, constraint := range table.Constraints {
|
||||
if constraint.Type == models.PrimaryKeyConstraint {
|
||||
pkConstraint = constraint
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var columnNames []string
|
||||
pkName := fmt.Sprintf("PK_%s_%s", schema.Name, table.Name)
|
||||
|
||||
if pkConstraint != nil {
|
||||
pkName = pkConstraint.Name
|
||||
columnNames = make([]string, 0, len(pkConstraint.Columns))
|
||||
for _, colName := range pkConstraint.Columns {
|
||||
columnNames = append(columnNames, fmt.Sprintf("[%s]", colName))
|
||||
}
|
||||
} else {
|
||||
// Check for columns with IsPrimaryKey = true
|
||||
for _, col := range table.Columns {
|
||||
if col.IsPrimaryKey {
|
||||
columnNames = append(columnNames, fmt.Sprintf("[%s]", col.Name))
|
||||
}
|
||||
}
|
||||
sort.Strings(columnNames)
|
||||
}
|
||||
|
||||
if len(columnNames) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(w.writer, "ALTER TABLE %s ADD CONSTRAINT [%s] PRIMARY KEY (%s);\n\n",
|
||||
w.qualTable(schema.Name, table.Name), pkName, strings.Join(columnNames, ", "))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeIndexes generates CREATE INDEX statements
|
||||
func (w *Writer) writeIndexes(schema *models.Schema, table *models.Table) error {
|
||||
// Sort indexes by name
|
||||
indexNames := make([]string, 0, len(table.Indexes))
|
||||
for name := range table.Indexes {
|
||||
indexNames = append(indexNames, name)
|
||||
}
|
||||
sort.Strings(indexNames)
|
||||
|
||||
for _, name := range indexNames {
|
||||
index := table.Indexes[name]
|
||||
|
||||
// Skip if it's a primary key index
|
||||
if strings.HasPrefix(strings.ToLower(index.Name), "pk_") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Build column list
|
||||
columnExprs := make([]string, 0, len(index.Columns))
|
||||
for _, colName := range index.Columns {
|
||||
columnExprs = append(columnExprs, fmt.Sprintf("[%s]", colName))
|
||||
}
|
||||
|
||||
if len(columnExprs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
unique := ""
|
||||
if index.Unique {
|
||||
unique = "UNIQUE "
|
||||
}
|
||||
|
||||
fmt.Fprintf(w.writer, "CREATE %sINDEX [%s] ON %s (%s);\n\n",
|
||||
unique, index.Name, w.qualTable(schema.Name, table.Name), strings.Join(columnExprs, ", "))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeUniqueConstraints generates ALTER TABLE statements for unique constraints
|
||||
func (w *Writer) writeUniqueConstraints(schema *models.Schema, table *models.Table) error {
|
||||
// Sort constraints by name
|
||||
constraintNames := make([]string, 0)
|
||||
for name, constraint := range table.Constraints {
|
||||
if constraint.Type == models.UniqueConstraint {
|
||||
constraintNames = append(constraintNames, name)
|
||||
}
|
||||
}
|
||||
sort.Strings(constraintNames)
|
||||
|
||||
for _, name := range constraintNames {
|
||||
constraint := table.Constraints[name]
|
||||
|
||||
// Build column list
|
||||
columnExprs := make([]string, 0, len(constraint.Columns))
|
||||
for _, colName := range constraint.Columns {
|
||||
columnExprs = append(columnExprs, fmt.Sprintf("[%s]", colName))
|
||||
}
|
||||
|
||||
if len(columnExprs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(w.writer, "ALTER TABLE %s ADD CONSTRAINT [%s] UNIQUE (%s);\n\n",
|
||||
w.qualTable(schema.Name, table.Name), constraint.Name, strings.Join(columnExprs, ", "))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeCheckConstraints generates ALTER TABLE statements for check constraints
|
||||
func (w *Writer) writeCheckConstraints(schema *models.Schema, table *models.Table) error {
|
||||
// Sort constraints by name
|
||||
constraintNames := make([]string, 0)
|
||||
for name, constraint := range table.Constraints {
|
||||
if constraint.Type == models.CheckConstraint {
|
||||
constraintNames = append(constraintNames, name)
|
||||
}
|
||||
}
|
||||
sort.Strings(constraintNames)
|
||||
|
||||
for _, name := range constraintNames {
|
||||
constraint := table.Constraints[name]
|
||||
|
||||
if constraint.Expression == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(w.writer, "ALTER TABLE %s ADD CONSTRAINT [%s] CHECK (%s);\n\n",
|
||||
w.qualTable(schema.Name, table.Name), constraint.Name, constraint.Expression)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeForeignKeys generates ALTER TABLE statements for foreign keys
|
||||
func (w *Writer) writeForeignKeys(schema *models.Schema, table *models.Table) error {
|
||||
// Process foreign key constraints
|
||||
constraintNames := make([]string, 0)
|
||||
for name, constraint := range table.Constraints {
|
||||
if constraint.Type == models.ForeignKeyConstraint {
|
||||
constraintNames = append(constraintNames, name)
|
||||
}
|
||||
}
|
||||
sort.Strings(constraintNames)
|
||||
|
||||
for _, name := range constraintNames {
|
||||
constraint := table.Constraints[name]
|
||||
|
||||
// Build column lists
|
||||
sourceColumns := make([]string, 0, len(constraint.Columns))
|
||||
for _, colName := range constraint.Columns {
|
||||
sourceColumns = append(sourceColumns, fmt.Sprintf("[%s]", colName))
|
||||
}
|
||||
|
||||
targetColumns := make([]string, 0, len(constraint.ReferencedColumns))
|
||||
for _, colName := range constraint.ReferencedColumns {
|
||||
targetColumns = append(targetColumns, fmt.Sprintf("[%s]", colName))
|
||||
}
|
||||
|
||||
if len(sourceColumns) == 0 || len(targetColumns) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
refSchema := constraint.ReferencedSchema
|
||||
if refSchema == "" {
|
||||
refSchema = schema.Name
|
||||
}
|
||||
|
||||
onDelete := "NO ACTION"
|
||||
if constraint.OnDelete != "" {
|
||||
onDelete = strings.ToUpper(constraint.OnDelete)
|
||||
}
|
||||
|
||||
onUpdate := "NO ACTION"
|
||||
if constraint.OnUpdate != "" {
|
||||
onUpdate = strings.ToUpper(constraint.OnUpdate)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w.writer, "ALTER TABLE %s ADD CONSTRAINT [%s] FOREIGN KEY (%s)\n",
|
||||
w.qualTable(schema.Name, table.Name), constraint.Name, strings.Join(sourceColumns, ", "))
|
||||
fmt.Fprintf(w.writer, " REFERENCES %s (%s)\n",
|
||||
w.qualTable(refSchema, constraint.ReferencedTable), strings.Join(targetColumns, ", "))
|
||||
fmt.Fprintf(w.writer, " ON DELETE %s ON UPDATE %s;\n\n",
|
||||
onDelete, onUpdate)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeComments generates EXEC sp_addextendedproperty statements for table and column descriptions
|
||||
func (w *Writer) writeComments(schema *models.Schema, table *models.Table) error {
|
||||
// Table comment
|
||||
if table.Description != "" {
|
||||
fmt.Fprintf(w.writer, "EXEC sp_addextendedproperty\n")
|
||||
fmt.Fprintf(w.writer, " @name = 'MS_Description',\n")
|
||||
fmt.Fprintf(w.writer, " @value = '%s',\n", escapeQuote(table.Description))
|
||||
fmt.Fprintf(w.writer, " @level0type = 'SCHEMA', @level0name = '%s',\n", schema.Name)
|
||||
fmt.Fprintf(w.writer, " @level1type = 'TABLE', @level1name = '%s';\n\n", table.Name)
|
||||
}
|
||||
|
||||
// Column comments
|
||||
for _, col := range getSortedColumns(table.Columns) {
|
||||
if col.Description != "" {
|
||||
fmt.Fprintf(w.writer, "EXEC sp_addextendedproperty\n")
|
||||
fmt.Fprintf(w.writer, " @name = 'MS_Description',\n")
|
||||
fmt.Fprintf(w.writer, " @value = '%s',\n", escapeQuote(col.Description))
|
||||
fmt.Fprintf(w.writer, " @level0type = 'SCHEMA', @level0name = '%s',\n", schema.Name)
|
||||
fmt.Fprintf(w.writer, " @level1type = 'TABLE', @level1name = '%s',\n", table.Name)
|
||||
fmt.Fprintf(w.writer, " @level2type = 'COLUMN', @level2name = '%s';\n\n", col.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// executeDatabaseSQL executes SQL statements directly on an MSSQL database
|
||||
func (w *Writer) executeDatabaseSQL(db *models.Database, connString string) error {
|
||||
// Generate SQL statements
|
||||
statements := []string{}
|
||||
statements = append(statements, "-- MSSQL Database Schema")
|
||||
statements = append(statements, fmt.Sprintf("-- Database: %s", db.Name))
|
||||
statements = append(statements, "-- Generated by RelSpec")
|
||||
|
||||
for _, schema := range db.Schemas {
|
||||
if err := w.generateSchemaStatements(schema, &statements); err != nil {
|
||||
return fmt.Errorf("failed to generate statements for schema %s: %w", schema.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to database
|
||||
dbConn, err := sql.Open("mssql", connString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to database: %w", err)
|
||||
}
|
||||
defer dbConn.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
if err = dbConn.PingContext(ctx); err != nil {
|
||||
return fmt.Errorf("failed to ping database: %w", err)
|
||||
}
|
||||
|
||||
// Execute statements
|
||||
executedCount := 0
|
||||
for i, stmt := range statements {
|
||||
stmtTrimmed := strings.TrimSpace(stmt)
|
||||
|
||||
// Skip comments and empty statements
|
||||
if strings.HasPrefix(stmtTrimmed, "--") || stmtTrimmed == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "Executing statement %d/%d...\n", i+1, len(statements))
|
||||
|
||||
_, execErr := dbConn.ExecContext(ctx, stmt)
|
||||
if execErr != nil {
|
||||
fmt.Fprintf(os.Stderr, "⚠ Warning: Statement failed: %v\n", execErr)
|
||||
continue
|
||||
}
|
||||
|
||||
executedCount++
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "✓ Successfully executed %d statements\n", executedCount)
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateSchemaStatements generates SQL statements for a schema
|
||||
func (w *Writer) generateSchemaStatements(schema *models.Schema, statements *[]string) error {
|
||||
// Phase 1: Create schema
|
||||
if schema.Name != "dbo" && !w.options.FlattenSchema {
|
||||
*statements = append(*statements, fmt.Sprintf("-- Schema: %s", schema.Name))
|
||||
*statements = append(*statements, fmt.Sprintf("CREATE SCHEMA [%s];", schema.Name))
|
||||
}
|
||||
|
||||
// Phase 2: Create tables
|
||||
*statements = append(*statements, fmt.Sprintf("-- Tables for schema: %s", schema.Name))
|
||||
for _, table := range schema.Tables {
|
||||
createTableSQL := fmt.Sprintf("CREATE TABLE %s (", w.qualTable(schema.Name, table.Name))
|
||||
columnDefs := make([]string, 0)
|
||||
|
||||
columns := getSortedColumns(table.Columns)
|
||||
for _, col := range columns {
|
||||
def := w.generateColumnDefinition(col)
|
||||
columnDefs = append(columnDefs, " "+def)
|
||||
}
|
||||
|
||||
createTableSQL += "\n" + strings.Join(columnDefs, ",\n") + "\n)"
|
||||
*statements = append(*statements, createTableSQL)
|
||||
}
|
||||
|
||||
// Phase 3-7: Constraints and indexes will be added by WriteSchema logic
|
||||
// For now, just create tables
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
// getSortedColumns returns columns sorted by sequence
|
||||
func getSortedColumns(columns map[string]*models.Column) []*models.Column {
|
||||
names := make([]string, 0, len(columns))
|
||||
for name := range columns {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
sorted := make([]*models.Column, 0, len(columns))
|
||||
for _, name := range names {
|
||||
sorted = append(sorted, columns[name])
|
||||
}
|
||||
return sorted
|
||||
}
|
||||
|
||||
// escapeQuote escapes single quotes in strings for SQL
|
||||
func escapeQuote(s string) string {
|
||||
return strings.ReplaceAll(s, "'", "''")
|
||||
}
|
||||
|
||||
// stripBackticks removes backticks from SQL expressions
|
||||
func stripBackticks(s string) string {
|
||||
return strings.ReplaceAll(s, "`", "")
|
||||
}
|
||||
205
pkg/writers/mssql/writer_test.go
Normal file
205
pkg/writers/mssql/writer_test.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestGenerateColumnDefinition tests column definition generation
|
||||
func TestGenerateColumnDefinition(t *testing.T) {
|
||||
writer := NewWriter(&writers.WriterOptions{})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
column *models.Column
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "INT NOT NULL",
|
||||
column: &models.Column{
|
||||
Name: "id",
|
||||
Type: "int",
|
||||
NotNull: true,
|
||||
Sequence: 1,
|
||||
},
|
||||
expected: "[id] INT NOT NULL",
|
||||
},
|
||||
{
|
||||
name: "VARCHAR with length",
|
||||
column: &models.Column{
|
||||
Name: "name",
|
||||
Type: "string",
|
||||
Length: 100,
|
||||
NotNull: true,
|
||||
Sequence: 2,
|
||||
},
|
||||
expected: "[name] NVARCHAR(100) NOT NULL",
|
||||
},
|
||||
{
|
||||
name: "DATETIME2 with default",
|
||||
column: &models.Column{
|
||||
Name: "created_at",
|
||||
Type: "timestamp",
|
||||
NotNull: true,
|
||||
Default: "GETDATE()",
|
||||
Sequence: 3,
|
||||
},
|
||||
expected: "[created_at] DATETIME2 NOT NULL DEFAULT GETDATE()",
|
||||
},
|
||||
{
|
||||
name: "IDENTITY column",
|
||||
column: &models.Column{
|
||||
Name: "id",
|
||||
Type: "int",
|
||||
AutoIncrement: true,
|
||||
NotNull: true,
|
||||
Sequence: 1,
|
||||
},
|
||||
expected: "[id] INT IDENTITY(1,1) NOT NULL",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := writer.generateColumnDefinition(tt.column)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWriteCreateTable tests CREATE TABLE statement generation
|
||||
func TestWriteCreateTable(t *testing.T) {
|
||||
writer := NewWriter(&writers.WriterOptions{})
|
||||
|
||||
// Create a test schema with a table
|
||||
schema := models.InitSchema("dbo")
|
||||
table := models.InitTable("users", "dbo")
|
||||
|
||||
col1 := models.InitColumn("id", "users", "dbo")
|
||||
col1.Type = "int"
|
||||
col1.AutoIncrement = true
|
||||
col1.NotNull = true
|
||||
col1.Sequence = 1
|
||||
|
||||
col2 := models.InitColumn("email", "users", "dbo")
|
||||
col2.Type = "string"
|
||||
col2.Length = 255
|
||||
col2.NotNull = true
|
||||
col2.Sequence = 2
|
||||
|
||||
table.Columns["id"] = col1
|
||||
table.Columns["email"] = col2
|
||||
|
||||
// Write to buffer
|
||||
buf := &bytes.Buffer{}
|
||||
writer.writer = buf
|
||||
|
||||
err := writer.writeCreateTable(schema, table)
|
||||
assert.NoError(t, err)
|
||||
|
||||
output := buf.String()
|
||||
assert.Contains(t, output, "CREATE TABLE [dbo].[users]")
|
||||
assert.Contains(t, output, "[id] INT IDENTITY(1,1) NOT NULL")
|
||||
assert.Contains(t, output, "[email] NVARCHAR(255) NOT NULL")
|
||||
}
|
||||
|
||||
// TestWritePrimaryKey tests PRIMARY KEY constraint generation
|
||||
func TestWritePrimaryKey(t *testing.T) {
|
||||
writer := NewWriter(&writers.WriterOptions{})
|
||||
|
||||
schema := models.InitSchema("dbo")
|
||||
table := models.InitTable("users", "dbo")
|
||||
|
||||
// Add primary key constraint
|
||||
pk := models.InitConstraint("PK_users_id", models.PrimaryKeyConstraint)
|
||||
pk.Columns = []string{"id"}
|
||||
table.Constraints[pk.Name] = pk
|
||||
|
||||
// Add column
|
||||
col := models.InitColumn("id", "users", "dbo")
|
||||
col.Type = "int"
|
||||
col.Sequence = 1
|
||||
table.Columns["id"] = col
|
||||
|
||||
// Write to buffer
|
||||
buf := &bytes.Buffer{}
|
||||
writer.writer = buf
|
||||
|
||||
err := writer.writePrimaryKey(schema, table)
|
||||
assert.NoError(t, err)
|
||||
|
||||
output := buf.String()
|
||||
assert.Contains(t, output, "ALTER TABLE [dbo].[users]")
|
||||
assert.Contains(t, output, "PRIMARY KEY")
|
||||
assert.Contains(t, output, "[id]")
|
||||
}
|
||||
|
||||
// TestWriteForeignKey tests FOREIGN KEY constraint generation
|
||||
func TestWriteForeignKey(t *testing.T) {
|
||||
writer := NewWriter(&writers.WriterOptions{})
|
||||
|
||||
schema := models.InitSchema("dbo")
|
||||
table := models.InitTable("orders", "dbo")
|
||||
|
||||
// Add foreign key constraint
|
||||
fk := models.InitConstraint("FK_orders_users", models.ForeignKeyConstraint)
|
||||
fk.Columns = []string{"user_id"}
|
||||
fk.ReferencedSchema = "dbo"
|
||||
fk.ReferencedTable = "users"
|
||||
fk.ReferencedColumns = []string{"id"}
|
||||
fk.OnDelete = "CASCADE"
|
||||
fk.OnUpdate = "NO ACTION"
|
||||
table.Constraints[fk.Name] = fk
|
||||
|
||||
// Add column
|
||||
col := models.InitColumn("user_id", "orders", "dbo")
|
||||
col.Type = "int"
|
||||
col.Sequence = 1
|
||||
table.Columns["user_id"] = col
|
||||
|
||||
// Write to buffer
|
||||
buf := &bytes.Buffer{}
|
||||
writer.writer = buf
|
||||
|
||||
err := writer.writeForeignKeys(schema, table)
|
||||
assert.NoError(t, err)
|
||||
|
||||
output := buf.String()
|
||||
assert.Contains(t, output, "ALTER TABLE [dbo].[orders]")
|
||||
assert.Contains(t, output, "FK_orders_users")
|
||||
assert.Contains(t, output, "FOREIGN KEY")
|
||||
assert.Contains(t, output, "CASCADE")
|
||||
assert.Contains(t, output, "NO ACTION")
|
||||
}
|
||||
|
||||
// TestWriteComments tests extended property generation for comments
|
||||
func TestWriteComments(t *testing.T) {
|
||||
writer := NewWriter(&writers.WriterOptions{})
|
||||
|
||||
schema := models.InitSchema("dbo")
|
||||
table := models.InitTable("users", "dbo")
|
||||
table.Description = "User accounts table"
|
||||
|
||||
col := models.InitColumn("id", "users", "dbo")
|
||||
col.Type = "int"
|
||||
col.Description = "Primary key"
|
||||
col.Sequence = 1
|
||||
table.Columns["id"] = col
|
||||
|
||||
// Write to buffer
|
||||
buf := &bytes.Buffer{}
|
||||
writer.writer = buf
|
||||
|
||||
err := writer.writeComments(schema, table)
|
||||
assert.NoError(t, err)
|
||||
|
||||
output := buf.String()
|
||||
assert.Contains(t, output, "sp_addextendedproperty")
|
||||
assert.Contains(t, output, "MS_Description")
|
||||
assert.Contains(t, output, "User accounts table")
|
||||
assert.Contains(t, output, "Primary key")
|
||||
}
|
||||
286
test_data/mssql/TESTING.md
Normal file
286
test_data/mssql/TESTING.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# MSSQL Reader and Writer Testing Guide
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- RelSpec binary built (`make build`)
|
||||
- jq (optional, for JSON processing)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Start SQL Server Express
|
||||
|
||||
```bash
|
||||
docker-compose up -d mssql
|
||||
|
||||
# Wait for container to be healthy
|
||||
docker-compose ps
|
||||
|
||||
# Monitor startup logs
|
||||
docker-compose logs -f mssql
|
||||
```
|
||||
|
||||
### 2. Verify Database Creation
|
||||
|
||||
```bash
|
||||
docker exec -it $(docker-compose ps -q mssql) \
|
||||
/opt/mssql-tools/bin/sqlcmd \
|
||||
-S localhost \
|
||||
-U sa \
|
||||
-P 'StrongPassword123!' \
|
||||
-Q "SELECT name FROM sys.databases WHERE name = 'RelSpecTest'"
|
||||
```
|
||||
|
||||
## Testing Scenarios
|
||||
|
||||
### Scenario 1: Read MSSQL Database to JSON
|
||||
|
||||
Read the test schema from MSSQL and export to JSON:
|
||||
|
||||
```bash
|
||||
./build/relspec convert \
|
||||
--from mssql \
|
||||
--from-conn "sqlserver://sa:StrongPassword123!@localhost:1433/RelSpecTest" \
|
||||
--to json \
|
||||
--to-path test_output.json
|
||||
```
|
||||
|
||||
Verify output:
|
||||
```bash
|
||||
jq '.Schemas[0].Tables | length' test_output.json
|
||||
jq '.Schemas[0].Tables[0]' test_output.json
|
||||
```
|
||||
|
||||
### Scenario 2: Read MSSQL Database to DBML
|
||||
|
||||
Convert MSSQL schema to DBML format:
|
||||
|
||||
```bash
|
||||
./build/relspec convert \
|
||||
--from mssql \
|
||||
--from-conn "sqlserver://sa:StrongPassword123!@localhost:1433/RelSpecTest" \
|
||||
--to dbml \
|
||||
--to-path test_output.dbml
|
||||
```
|
||||
|
||||
### Scenario 3: Generate SQL Script (No Direct Execution)
|
||||
|
||||
Generate SQL script without executing:
|
||||
|
||||
```bash
|
||||
./build/relspec convert \
|
||||
--from mssql \
|
||||
--from-conn "sqlserver://sa:StrongPassword123!@localhost:1433/RelSpecTest" \
|
||||
--to mssql \
|
||||
--to-path test_output.sql
|
||||
```
|
||||
|
||||
Inspect generated SQL:
|
||||
```bash
|
||||
head -50 test_output.sql
|
||||
```
|
||||
|
||||
### Scenario 4: Round-Trip Conversion (MSSQL → JSON → MSSQL)
|
||||
|
||||
Test bidirectional conversion:
|
||||
|
||||
```bash
|
||||
# Step 1: MSSQL → JSON
|
||||
./build/relspec convert \
|
||||
--from mssql \
|
||||
--from-conn "sqlserver://sa:StrongPassword123!@localhost:1433/RelSpecTest" \
|
||||
--to json \
|
||||
--to-path backup.json
|
||||
|
||||
# Step 2: JSON → MSSQL SQL
|
||||
./build/relspec convert \
|
||||
--from json \
|
||||
--from-path backup.json \
|
||||
--to mssql \
|
||||
--to-path restore.sql
|
||||
|
||||
# Inspect SQL
|
||||
cat restore.sql | head -50
|
||||
```
|
||||
|
||||
### Scenario 5: Cross-Database Conversion
|
||||
|
||||
If you have PostgreSQL running, test conversion:
|
||||
|
||||
```bash
|
||||
# MSSQL → PostgreSQL SQL
|
||||
./build/relspec convert \
|
||||
--from mssql \
|
||||
--from-conn "sqlserver://sa:StrongPassword123!@localhost:1433/RelSpecTest" \
|
||||
--to pgsql \
|
||||
--to-path mssql_to_pg.sql
|
||||
```
|
||||
|
||||
### Scenario 6: Test Type Mappings
|
||||
|
||||
Create a JSON file with various types and convert to MSSQL:
|
||||
|
||||
```json
|
||||
{
|
||||
"Name": "TypeTest",
|
||||
"Schemas": [
|
||||
{
|
||||
"Name": "dbo",
|
||||
"Tables": [
|
||||
{
|
||||
"Name": "type_samples",
|
||||
"Columns": {
|
||||
"id": {
|
||||
"Name": "id",
|
||||
"Type": "int",
|
||||
"AutoIncrement": true,
|
||||
"NotNull": true,
|
||||
"Sequence": 1
|
||||
},
|
||||
"big_num": {
|
||||
"Name": "big_num",
|
||||
"Type": "int64",
|
||||
"Sequence": 2
|
||||
},
|
||||
"is_active": {
|
||||
"Name": "is_active",
|
||||
"Type": "bool",
|
||||
"Sequence": 3
|
||||
},
|
||||
"description": {
|
||||
"Name": "description",
|
||||
"Type": "text",
|
||||
"Sequence": 4
|
||||
},
|
||||
"created_at": {
|
||||
"Name": "created_at",
|
||||
"Type": "timestamp",
|
||||
"NotNull": true,
|
||||
"Default": "GETDATE()",
|
||||
"Sequence": 5
|
||||
},
|
||||
"unique_id": {
|
||||
"Name": "unique_id",
|
||||
"Type": "uuid",
|
||||
"Sequence": 6
|
||||
},
|
||||
"metadata": {
|
||||
"Name": "metadata",
|
||||
"Type": "json",
|
||||
"Sequence": 7
|
||||
},
|
||||
"binary_data": {
|
||||
"Name": "binary_data",
|
||||
"Type": "bytea",
|
||||
"Sequence": 8
|
||||
}
|
||||
},
|
||||
"Constraints": {
|
||||
"PK_type_samples_id": {
|
||||
"Name": "PK_type_samples_id",
|
||||
"Type": "PRIMARY_KEY",
|
||||
"Columns": ["id"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Convert to MSSQL:
|
||||
```bash
|
||||
./build/relspec convert \
|
||||
--from json \
|
||||
--from-path type_test.json \
|
||||
--to mssql \
|
||||
--to-path type_test.sql
|
||||
|
||||
cat type_test.sql
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
|
||||
Stop and remove the SQL Server container:
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
|
||||
# Clean up test files
|
||||
rm -f test_output.* backup.json restore.sql
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container won't start
|
||||
|
||||
Check Docker daemon is running and database logs:
|
||||
```bash
|
||||
docker-compose logs mssql
|
||||
```
|
||||
|
||||
### Connection refused errors
|
||||
|
||||
Wait for container to be healthy:
|
||||
```bash
|
||||
docker-compose ps
|
||||
# Wait until STATUS shows "healthy"
|
||||
|
||||
# Or check manually
|
||||
docker exec -it $(docker-compose ps -q mssql) \
|
||||
/opt/mssql-tools/bin/sqlcmd \
|
||||
-S localhost \
|
||||
-U sa \
|
||||
-P 'StrongPassword123!' \
|
||||
-Q "SELECT @@VERSION"
|
||||
```
|
||||
|
||||
### Test schema not found
|
||||
|
||||
Initialize the test schema:
|
||||
```bash
|
||||
docker exec -i $(docker-compose ps -q mssql) \
|
||||
/opt/mssql-tools/bin/sqlcmd \
|
||||
-S localhost \
|
||||
-U sa \
|
||||
-P 'StrongPassword123!' \
|
||||
< test_data/mssql/test_schema.sql
|
||||
```
|
||||
|
||||
### Connection string format issues
|
||||
|
||||
Use the correct format for connection strings:
|
||||
- Default port: 1433
|
||||
- Username: `sa`
|
||||
- Password: `StrongPassword123!`
|
||||
- Database: `RelSpecTest`
|
||||
|
||||
Format: `sqlserver://sa:StrongPassword123!@localhost:1433/RelSpecTest`
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Initial reader setup may take a few seconds
|
||||
- Type mapping queries are cached within a single read operation
|
||||
- Direct execution mode is atomic per table/constraint
|
||||
- Large schemas (100+ tables) should complete in under 5 seconds
|
||||
|
||||
## Unit Test Verification
|
||||
|
||||
Run the MSSQL-specific tests:
|
||||
|
||||
```bash
|
||||
# Type mapping tests
|
||||
go test ./pkg/mssql/... -v
|
||||
|
||||
# Reader tests
|
||||
go test ./pkg/readers/mssql/... -v
|
||||
|
||||
# Writer tests
|
||||
go test ./pkg/writers/mssql/... -v
|
||||
|
||||
# All together
|
||||
go test ./pkg/mssql/... ./pkg/readers/mssql/... ./pkg/writers/mssql/... -v
|
||||
```
|
||||
|
||||
Expected output: All tests should PASS
|
||||
187
test_data/mssql/test_schema.sql
Normal file
187
test_data/mssql/test_schema.sql
Normal file
@@ -0,0 +1,187 @@
|
||||
-- Test schema for MSSQL Reader integration tests
|
||||
-- This script creates a sample database for testing the MSSQL reader
|
||||
|
||||
USE master;
|
||||
GO
|
||||
|
||||
-- Drop existing database if it exists
|
||||
IF EXISTS (SELECT 1 FROM sys.databases WHERE name = 'RelSpecTest')
|
||||
BEGIN
|
||||
ALTER DATABASE RelSpecTest SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
|
||||
DROP DATABASE RelSpecTest;
|
||||
END
|
||||
GO
|
||||
|
||||
-- Create test database
|
||||
CREATE DATABASE RelSpecTest;
|
||||
GO
|
||||
|
||||
USE RelSpecTest;
|
||||
GO
|
||||
|
||||
-- Create schemas
|
||||
CREATE SCHEMA [public];
|
||||
GO
|
||||
|
||||
CREATE SCHEMA [auth];
|
||||
GO
|
||||
|
||||
-- Create tables in public schema
|
||||
CREATE TABLE [public].[users] (
|
||||
[id] INT IDENTITY(1,1) NOT NULL,
|
||||
[email] NVARCHAR(255) NOT NULL,
|
||||
[username] NVARCHAR(100) NOT NULL,
|
||||
[created_at] DATETIME2 NOT NULL DEFAULT GETDATE(),
|
||||
[updated_at] DATETIME2 NULL,
|
||||
[is_active] BIT NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY ([id]),
|
||||
UNIQUE ([email]),
|
||||
UNIQUE ([username])
|
||||
);
|
||||
GO
|
||||
|
||||
CREATE TABLE [public].[posts] (
|
||||
[id] INT IDENTITY(1,1) NOT NULL,
|
||||
[user_id] INT NOT NULL,
|
||||
[title] NVARCHAR(255) NOT NULL,
|
||||
[content] NVARCHAR(MAX) NOT NULL,
|
||||
[published_at] DATETIME2 NULL,
|
||||
[created_at] DATETIME2 NOT NULL DEFAULT GETDATE(),
|
||||
PRIMARY KEY ([id])
|
||||
);
|
||||
GO
|
||||
|
||||
CREATE TABLE [public].[comments] (
|
||||
[id] INT IDENTITY(1,1) NOT NULL,
|
||||
[post_id] INT NOT NULL,
|
||||
[user_id] INT NOT NULL,
|
||||
[content] NVARCHAR(MAX) NOT NULL,
|
||||
[created_at] DATETIME2 NOT NULL DEFAULT GETDATE(),
|
||||
PRIMARY KEY ([id])
|
||||
);
|
||||
GO
|
||||
|
||||
-- Create tables in auth schema
|
||||
CREATE TABLE [auth].[roles] (
|
||||
[id] INT IDENTITY(1,1) NOT NULL,
|
||||
[name] NVARCHAR(100) NOT NULL,
|
||||
[description] NVARCHAR(MAX) NULL,
|
||||
PRIMARY KEY ([id]),
|
||||
UNIQUE ([name])
|
||||
);
|
||||
GO
|
||||
|
||||
CREATE TABLE [auth].[user_roles] (
|
||||
[id] INT IDENTITY(1,1) NOT NULL,
|
||||
[user_id] INT NOT NULL,
|
||||
[role_id] INT NOT NULL,
|
||||
PRIMARY KEY ([id]),
|
||||
UNIQUE ([user_id], [role_id])
|
||||
);
|
||||
GO
|
||||
|
||||
-- Add foreign keys
|
||||
ALTER TABLE [public].[posts]
|
||||
ADD CONSTRAINT [FK_posts_users]
|
||||
FOREIGN KEY ([user_id])
|
||||
REFERENCES [public].[users] ([id])
|
||||
ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
GO
|
||||
|
||||
ALTER TABLE [public].[comments]
|
||||
ADD CONSTRAINT [FK_comments_posts]
|
||||
FOREIGN KEY ([post_id])
|
||||
REFERENCES [public].[posts] ([id])
|
||||
ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
GO
|
||||
|
||||
ALTER TABLE [public].[comments]
|
||||
ADD CONSTRAINT [FK_comments_users]
|
||||
FOREIGN KEY ([user_id])
|
||||
REFERENCES [public].[users] ([id])
|
||||
ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
GO
|
||||
|
||||
ALTER TABLE [auth].[user_roles]
|
||||
ADD CONSTRAINT [FK_user_roles_users]
|
||||
FOREIGN KEY ([user_id])
|
||||
REFERENCES [public].[users] ([id])
|
||||
ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
GO
|
||||
|
||||
ALTER TABLE [auth].[user_roles]
|
||||
ADD CONSTRAINT [FK_user_roles_roles]
|
||||
FOREIGN KEY ([role_id])
|
||||
REFERENCES [auth].[roles] ([id])
|
||||
ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
GO
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX [IDX_users_email] ON [public].[users] ([email]);
|
||||
GO
|
||||
|
||||
CREATE INDEX [IDX_posts_user_id] ON [public].[posts] ([user_id]);
|
||||
GO
|
||||
|
||||
CREATE INDEX [IDX_comments_post_id] ON [public].[comments] ([post_id]);
|
||||
GO
|
||||
|
||||
CREATE INDEX [IDX_comments_user_id] ON [public].[comments] ([user_id]);
|
||||
GO
|
||||
|
||||
-- Add extended properties (comments)
|
||||
EXEC sp_addextendedproperty
|
||||
@name = 'MS_Description',
|
||||
@value = 'User accounts table',
|
||||
@level0type = 'SCHEMA', @level0name = 'public',
|
||||
@level1type = 'TABLE', @level1name = 'users';
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
@name = 'MS_Description',
|
||||
@value = 'User unique identifier',
|
||||
@level0type = 'SCHEMA', @level0name = 'public',
|
||||
@level1type = 'TABLE', @level1name = 'users',
|
||||
@level2type = 'COLUMN', @level2name = 'id';
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
@name = 'MS_Description',
|
||||
@value = 'User email address',
|
||||
@level0type = 'SCHEMA', @level0name = 'public',
|
||||
@level1type = 'TABLE', @level1name = 'users',
|
||||
@level2type = 'COLUMN', @level2name = 'email';
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
@name = 'MS_Description',
|
||||
@value = 'Blog posts table',
|
||||
@level0type = 'SCHEMA', @level0name = 'public',
|
||||
@level1type = 'TABLE', @level1name = 'posts';
|
||||
GO
|
||||
|
||||
EXEC sp_addextendedproperty
|
||||
@name = 'MS_Description',
|
||||
@value = 'User roles mapping table',
|
||||
@level0type = 'SCHEMA', @level0name = 'auth',
|
||||
@level1type = 'TABLE', @level1name = 'user_roles';
|
||||
GO
|
||||
|
||||
-- Add check constraint
|
||||
ALTER TABLE [public].[users]
|
||||
ADD CONSTRAINT [CK_users_email_format]
|
||||
CHECK (LEN(email) > 0 AND email LIKE '%@%.%');
|
||||
GO
|
||||
|
||||
-- Verify schema was created
|
||||
SELECT
|
||||
SCHEMA_NAME(s.schema_id) as [Schema],
|
||||
t.name as [Table],
|
||||
COUNT(c.column_id) as [ColumnCount]
|
||||
FROM sys.tables t
|
||||
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
||||
LEFT JOIN sys.columns c ON t.object_id = c.object_id
|
||||
WHERE SCHEMA_NAME(s.schema_id) IN ('public', 'auth')
|
||||
GROUP BY SCHEMA_NAME(s.schema_id), t.name
|
||||
ORDER BY [Schema], [Table];
|
||||
GO
|
||||
73
vendor/github.com/golang-sql/civil/CONTRIBUTING.md
generated
vendored
Normal file
73
vendor/github.com/golang-sql/civil/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
# Contributing
|
||||
|
||||
1. Sign one of the contributor license agreements below.
|
||||
|
||||
#### Running
|
||||
|
||||
Once you've done the necessary setup, you can run the integration tests by
|
||||
running:
|
||||
|
||||
``` sh
|
||||
$ go test -v github.com/golang-sql/civil
|
||||
```
|
||||
|
||||
## Contributor License Agreements
|
||||
|
||||
Before we can accept your pull requests you'll need to sign a Contributor
|
||||
License Agreement (CLA):
|
||||
|
||||
- **If you are an individual writing original source code** and **you own the
|
||||
intellectual property**, then you'll need to sign an [individual CLA][indvcla].
|
||||
- **If you work for a company that wants to allow you to contribute your
|
||||
work**, then you'll need to sign a [corporate CLA][corpcla].
|
||||
|
||||
You can sign these electronically (just scroll to the bottom). After that,
|
||||
we'll be able to accept your pull requests.
|
||||
|
||||
## Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project,
|
||||
and in the interest of fostering an open and welcoming community,
|
||||
we pledge to respect all people who contribute through reporting issues,
|
||||
posting feature requests, updating documentation,
|
||||
submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project
|
||||
a harassment-free experience for everyone,
|
||||
regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance,
|
||||
body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information,
|
||||
such as physical or electronic
|
||||
addresses, without explicit permission
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct.
|
||||
By adopting this Code of Conduct,
|
||||
project maintainers commit themselves to fairly and consistently
|
||||
applying these principles to every aspect of managing this project.
|
||||
Project maintainers who do not follow or enforce the Code of Conduct
|
||||
may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior
|
||||
may be reported by opening an issue
|
||||
or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
|
||||
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
|
||||
|
||||
[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/
|
||||
[indvcla]: https://developers.google.com/open-source/cla/individual
|
||||
[corpcla]: https://developers.google.com/open-source/cla/corporate
|
||||
202
vendor/github.com/golang-sql/civil/LICENSE
generated
vendored
Normal file
202
vendor/github.com/golang-sql/civil/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
15
vendor/github.com/golang-sql/civil/README.md
generated
vendored
Normal file
15
vendor/github.com/golang-sql/civil/README.md
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Civil Date and Time
|
||||
|
||||
[](https://godoc.org/github.com/golang-sql/civil)
|
||||
|
||||
Civil provides Date, Time of Day, and DateTime data types.
|
||||
|
||||
While there are many uses, using specific types when working
|
||||
with databases make is conceptually eaiser to understand what value
|
||||
is set in the remote system.
|
||||
|
||||
## Source
|
||||
|
||||
This civil package was extracted and forked from `cloud.google.com/go/civil`.
|
||||
As such the license and contributing requirements remain the same as that
|
||||
module.
|
||||
292
vendor/github.com/golang-sql/civil/civil.go
generated
vendored
Normal file
292
vendor/github.com/golang-sql/civil/civil.go
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
// Copyright 2016 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package civil implements types for civil time, a time-zone-independent
|
||||
// representation of time that follows the rules of the proleptic
|
||||
// Gregorian calendar with exactly 24-hour days, 60-minute hours, and 60-second
|
||||
// minutes.
|
||||
//
|
||||
// Because they lack location information, these types do not represent unique
|
||||
// moments or intervals of time. Use time.Time for that purpose.
|
||||
package civil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Date represents a date (year, month, day).
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique 24-hour timespan.
|
||||
type Date struct {
|
||||
Year int // Year (e.g., 2014).
|
||||
Month time.Month // Month of the year (January = 1, ...).
|
||||
Day int // Day of the month, starting at 1.
|
||||
}
|
||||
|
||||
// DateOf returns the Date in which a time occurs in that time's location.
|
||||
func DateOf(t time.Time) Date {
|
||||
var d Date
|
||||
d.Year, d.Month, d.Day = t.Date()
|
||||
return d
|
||||
}
|
||||
|
||||
// ParseDate parses a string in RFC3339 full-date format and returns the date value it represents.
|
||||
func ParseDate(s string) (Date, error) {
|
||||
t, err := time.Parse("2006-01-02", s)
|
||||
if err != nil {
|
||||
return Date{}, err
|
||||
}
|
||||
return DateOf(t), nil
|
||||
}
|
||||
|
||||
// String returns the date in RFC3339 full-date format.
|
||||
func (d Date) String() string {
|
||||
return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
|
||||
}
|
||||
|
||||
// IsValid reports whether the date is valid.
|
||||
func (d Date) IsValid() bool {
|
||||
return DateOf(d.In(time.UTC)) == d
|
||||
}
|
||||
|
||||
// In returns the time corresponding to time 00:00:00 of the date in the location.
|
||||
//
|
||||
// In is always consistent with time.Date, even when time.Date returns a time
|
||||
// on a different day. For example, if loc is America/Indiana/Vincennes, then both
|
||||
// time.Date(1955, time.May, 1, 0, 0, 0, 0, loc)
|
||||
// and
|
||||
// civil.Date{Year: 1955, Month: time.May, Day: 1}.In(loc)
|
||||
// return 23:00:00 on April 30, 1955.
|
||||
//
|
||||
// In panics if loc is nil.
|
||||
func (d Date) In(loc *time.Location) time.Time {
|
||||
return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, loc)
|
||||
}
|
||||
|
||||
// AddDays returns the date that is n days in the future.
|
||||
// n can also be negative to go into the past.
|
||||
func (d Date) AddDays(n int) Date {
|
||||
return DateOf(d.In(time.UTC).AddDate(0, 0, n))
|
||||
}
|
||||
|
||||
// DaysSince returns the signed number of days between the date and s, not including the end day.
|
||||
// This is the inverse operation to AddDays.
|
||||
func (d Date) DaysSince(s Date) (days int) {
|
||||
// We convert to Unix time so we do not have to worry about leap seconds:
|
||||
// Unix time increases by exactly 86400 seconds per day.
|
||||
deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix()
|
||||
return int(deltaUnix / 86400)
|
||||
}
|
||||
|
||||
// Before reports whether d1 occurs before d2.
|
||||
func (d1 Date) Before(d2 Date) bool {
|
||||
if d1.Year != d2.Year {
|
||||
return d1.Year < d2.Year
|
||||
}
|
||||
if d1.Month != d2.Month {
|
||||
return d1.Month < d2.Month
|
||||
}
|
||||
return d1.Day < d2.Day
|
||||
}
|
||||
|
||||
// After reports whether d1 occurs after d2.
|
||||
func (d1 Date) After(d2 Date) bool {
|
||||
return d2.Before(d1)
|
||||
}
|
||||
|
||||
// IsZero reports whether date fields are set to their default value.
|
||||
func (d Date) IsZero() bool {
|
||||
return (d.Year == 0) && (int(d.Month) == 0) && (d.Day == 0)
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of d.String().
|
||||
func (d Date) MarshalText() ([]byte, error) {
|
||||
return []byte(d.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The date is expected to be a string in a format accepted by ParseDate.
|
||||
func (d *Date) UnmarshalText(data []byte) error {
|
||||
var err error
|
||||
*d, err = ParseDate(string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// A Time represents a time with nanosecond precision.
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique moment in time.
|
||||
//
|
||||
// This type exists to represent the TIME type in storage-based APIs like BigQuery.
|
||||
// Most operations on Times are unlikely to be meaningful. Prefer the DateTime type.
|
||||
type Time struct {
|
||||
Hour int // The hour of the day in 24-hour format; range [0-23]
|
||||
Minute int // The minute of the hour; range [0-59]
|
||||
Second int // The second of the minute; range [0-59]
|
||||
Nanosecond int // The nanosecond of the second; range [0-999999999]
|
||||
}
|
||||
|
||||
// TimeOf returns the Time representing the time of day in which a time occurs
|
||||
// in that time's location. It ignores the date.
|
||||
func TimeOf(t time.Time) Time {
|
||||
var tm Time
|
||||
tm.Hour, tm.Minute, tm.Second = t.Clock()
|
||||
tm.Nanosecond = t.Nanosecond()
|
||||
return tm
|
||||
}
|
||||
|
||||
// ParseTime parses a string and returns the time value it represents.
|
||||
// ParseTime accepts an extended form of the RFC3339 partial-time format. After
|
||||
// the HH:MM:SS part of the string, an optional fractional part may appear,
|
||||
// consisting of a decimal point followed by one to nine decimal digits.
|
||||
// (RFC3339 admits only one digit after the decimal point).
|
||||
func ParseTime(s string) (Time, error) {
|
||||
t, err := time.Parse("15:04:05.999999999", s)
|
||||
if err != nil {
|
||||
return Time{}, err
|
||||
}
|
||||
return TimeOf(t), nil
|
||||
}
|
||||
|
||||
// String returns the date in the format described in ParseTime. If Nanoseconds
|
||||
// is zero, no fractional part will be generated. Otherwise, the result will
|
||||
// end with a fractional part consisting of a decimal point and nine digits.
|
||||
func (t Time) String() string {
|
||||
s := fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second)
|
||||
if t.Nanosecond == 0 {
|
||||
return s
|
||||
}
|
||||
return s + fmt.Sprintf(".%09d", t.Nanosecond)
|
||||
}
|
||||
|
||||
// IsValid reports whether the time is valid.
|
||||
func (t Time) IsValid() bool {
|
||||
// Construct a non-zero time.
|
||||
tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC)
|
||||
return TimeOf(tm) == t
|
||||
}
|
||||
|
||||
// IsZero reports whether time fields are set to their default value.
|
||||
func (t Time) IsZero() bool {
|
||||
return (t.Hour == 0) && (t.Minute == 0) && (t.Second == 0) && (t.Nanosecond == 0)
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of t.String().
|
||||
func (t Time) MarshalText() ([]byte, error) {
|
||||
return []byte(t.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The time is expected to be a string in a format accepted by ParseTime.
|
||||
func (t *Time) UnmarshalText(data []byte) error {
|
||||
var err error
|
||||
*t, err = ParseTime(string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// A DateTime represents a date and time.
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique moment in time.
|
||||
type DateTime struct {
|
||||
Date Date
|
||||
Time Time
|
||||
}
|
||||
|
||||
// Note: We deliberately do not embed Date into DateTime, to avoid promoting AddDays and Sub.
|
||||
|
||||
// DateTimeOf returns the DateTime in which a time occurs in that time's location.
|
||||
func DateTimeOf(t time.Time) DateTime {
|
||||
return DateTime{
|
||||
Date: DateOf(t),
|
||||
Time: TimeOf(t),
|
||||
}
|
||||
}
|
||||
|
||||
// ParseDateTime parses a string and returns the DateTime it represents.
|
||||
// ParseDateTime accepts a variant of the RFC3339 date-time format that omits
|
||||
// the time offset but includes an optional fractional time, as described in
|
||||
// ParseTime. Informally, the accepted format is
|
||||
// YYYY-MM-DDTHH:MM:SS[.FFFFFFFFF]
|
||||
// where the 'T' may be a lower-case 't'.
|
||||
func ParseDateTime(s string) (DateTime, error) {
|
||||
t, err := time.Parse("2006-01-02T15:04:05.999999999", s)
|
||||
if err != nil {
|
||||
t, err = time.Parse("2006-01-02t15:04:05.999999999", s)
|
||||
if err != nil {
|
||||
return DateTime{}, err
|
||||
}
|
||||
}
|
||||
return DateTimeOf(t), nil
|
||||
}
|
||||
|
||||
// String returns the date in the format described in ParseDate.
|
||||
func (dt DateTime) String() string {
|
||||
return dt.Date.String() + "T" + dt.Time.String()
|
||||
}
|
||||
|
||||
// IsValid reports whether the datetime is valid.
|
||||
func (dt DateTime) IsValid() bool {
|
||||
return dt.Date.IsValid() && dt.Time.IsValid()
|
||||
}
|
||||
|
||||
// In returns the time corresponding to the DateTime in the given location.
|
||||
//
|
||||
// If the time is missing or ambigous at the location, In returns the same
|
||||
// result as time.Date. For example, if loc is America/Indiana/Vincennes, then
|
||||
// both
|
||||
// time.Date(1955, time.May, 1, 0, 30, 0, 0, loc)
|
||||
// and
|
||||
// civil.DateTime{
|
||||
// civil.Date{Year: 1955, Month: time.May, Day: 1}},
|
||||
// civil.Time{Minute: 30}}.In(loc)
|
||||
// return 23:30:00 on April 30, 1955.
|
||||
//
|
||||
// In panics if loc is nil.
|
||||
func (dt DateTime) In(loc *time.Location) time.Time {
|
||||
return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc)
|
||||
}
|
||||
|
||||
// Before reports whether dt1 occurs before dt2.
|
||||
func (dt1 DateTime) Before(dt2 DateTime) bool {
|
||||
return dt1.In(time.UTC).Before(dt2.In(time.UTC))
|
||||
}
|
||||
|
||||
// After reports whether dt1 occurs after dt2.
|
||||
func (dt1 DateTime) After(dt2 DateTime) bool {
|
||||
return dt2.Before(dt1)
|
||||
}
|
||||
|
||||
// IsZero reports whether datetime fields are set to their default value.
|
||||
func (dt DateTime) IsZero() bool {
|
||||
return dt.Date.IsZero() && dt.Time.IsZero()
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of dt.String().
|
||||
func (dt DateTime) MarshalText() ([]byte, error) {
|
||||
return []byte(dt.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The datetime is expected to be a string in a format accepted by ParseDateTime
|
||||
func (dt *DateTime) UnmarshalText(data []byte) error {
|
||||
var err error
|
||||
*dt, err = ParseDateTime(string(data))
|
||||
return err
|
||||
}
|
||||
27
vendor/github.com/golang-sql/sqlexp/LICENSE
generated
vendored
Normal file
27
vendor/github.com/golang-sql/sqlexp/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2017 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
22
vendor/github.com/golang-sql/sqlexp/PATENTS
generated
vendored
Normal file
22
vendor/github.com/golang-sql/sqlexp/PATENTS
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
||||
5
vendor/github.com/golang-sql/sqlexp/README.md
generated
vendored
Normal file
5
vendor/github.com/golang-sql/sqlexp/README.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# golang-sql exp
|
||||
|
||||
https://godoc.org/github.com/golang-sql/sqlexp
|
||||
|
||||
All contributions must have a valid golang CLA.
|
||||
8
vendor/github.com/golang-sql/sqlexp/doc.go
generated
vendored
Normal file
8
vendor/github.com/golang-sql/sqlexp/doc.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package sqlexp provides interfaces and functions that may be adopted into
|
||||
// the database/sql package in the future. All features may change or be removed
|
||||
// in the future.
|
||||
package sqlexp // imports github.com/golang-sql/sqlexp
|
||||
80
vendor/github.com/golang-sql/sqlexp/messages.go
generated
vendored
Normal file
80
vendor/github.com/golang-sql/sqlexp/messages.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package sqlexp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// RawMessage is returned from RowsMessage.
|
||||
type RawMessage interface{}
|
||||
|
||||
// ReturnMessage may be passed into a Query argument.
|
||||
//
|
||||
// Drivers must implement driver.NamedValueChecker,
|
||||
// call ReturnMessageInit on it, save it internally,
|
||||
// and return driver.ErrOmitArgument to prevent
|
||||
// this from appearing in the query arguments.
|
||||
//
|
||||
// Queries that recieve this message should also not return
|
||||
// SQL errors from the Query method, but wait to return
|
||||
// it in a Message.
|
||||
type ReturnMessage struct {
|
||||
queue chan RawMessage
|
||||
}
|
||||
|
||||
// Message is called by clients after Query to dequeue messages.
|
||||
func (m *ReturnMessage) Message(ctx context.Context) RawMessage {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return MsgNextResultSet{}
|
||||
case raw := <-m.queue:
|
||||
return raw
|
||||
}
|
||||
}
|
||||
|
||||
// ReturnMessageEnqueue is called by the driver to enqueue the driver.
|
||||
// Drivers should not call this until after it returns from Query.
|
||||
func ReturnMessageEnqueue(ctx context.Context, m *ReturnMessage, raw RawMessage) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case m.queue <- raw:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ReturnMessageInit is called by database/sql setup the ReturnMessage internals.
|
||||
func ReturnMessageInit(m *ReturnMessage) {
|
||||
m.queue = make(chan RawMessage, 15)
|
||||
}
|
||||
|
||||
type (
|
||||
// MsgNextResultSet must be checked for. When received, NextResultSet
|
||||
// should be called and if false the message loop should be exited.
|
||||
MsgNextResultSet struct{}
|
||||
|
||||
// MsgNext indicates the result set ready to be scanned.
|
||||
// This message will often be followed with:
|
||||
//
|
||||
// for rows.Next() {
|
||||
// rows.Scan(&v)
|
||||
// }
|
||||
MsgNext struct{}
|
||||
|
||||
// MsgRowsAffected returns the number of rows affected.
|
||||
// Not all operations that affect rows return results, thus this message
|
||||
// may be received multiple times.
|
||||
MsgRowsAffected struct{ Count int64 }
|
||||
|
||||
// MsgLastInsertID returns the value of last inserted row. For many
|
||||
// database systems and tables this will return int64. Some databases
|
||||
// may return a string or GUID equivalent.
|
||||
MsgLastInsertID struct{ Value interface{} }
|
||||
|
||||
// MsgNotice is raised from the SQL text and is only informational.
|
||||
MsgNotice struct{ Message fmt.Stringer }
|
||||
|
||||
// MsgError returns SQL errors from the database system (not transport
|
||||
// or other system level errors).
|
||||
MsgError struct{ Error error }
|
||||
)
|
||||
73
vendor/github.com/golang-sql/sqlexp/mssql.go
generated
vendored
Normal file
73
vendor/github.com/golang-sql/sqlexp/mssql.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlexp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type mssql struct{}
|
||||
|
||||
var (
|
||||
_ DriverNamer = mssql{}
|
||||
_ DriverQuoter = mssql{}
|
||||
_ DriverSavepointer = mssql{}
|
||||
)
|
||||
|
||||
func (mssql) Open(string) (driver.Conn, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (mssql) Namer(ctx context.Context) (Namer, error) {
|
||||
return sqlServerNamer{}, nil
|
||||
}
|
||||
|
||||
func (mssql) Quoter(ctx context.Context) (Quoter, error) {
|
||||
return sqlServerQuoter{}, nil
|
||||
}
|
||||
|
||||
func (mssql) Savepointer() (Savepointer, error) {
|
||||
return sqlServerSavepointer{}, nil
|
||||
}
|
||||
|
||||
type sqlServerNamer struct{}
|
||||
|
||||
func (sqlServerNamer) Name() string {
|
||||
return "sqlserver"
|
||||
}
|
||||
func (sqlServerNamer) Dialect() string {
|
||||
return DialectTSQL
|
||||
}
|
||||
|
||||
type sqlServerQuoter struct{}
|
||||
|
||||
func (sqlServerQuoter) ID(name string) string {
|
||||
return "[" + strings.Replace(name, "]", "]]", -1) + "]"
|
||||
}
|
||||
func (sqlServerQuoter) Value(v interface{}) string {
|
||||
switch v := v.(type) {
|
||||
default:
|
||||
panic("unsupported value")
|
||||
case string:
|
||||
return "'" + strings.Replace(v, "'", "''", -1) + "'"
|
||||
}
|
||||
}
|
||||
|
||||
type sqlServerSavepointer struct{}
|
||||
|
||||
func (sqlServerSavepointer) Release(name string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sqlServerSavepointer) Create(name string) string {
|
||||
return fmt.Sprintf("save tran %s;", name)
|
||||
}
|
||||
|
||||
func (sqlServerSavepointer) Rollback(name string) string {
|
||||
return fmt.Sprintf("rollback tran %s;", name)
|
||||
}
|
||||
59
vendor/github.com/golang-sql/sqlexp/namer.go
generated
vendored
Normal file
59
vendor/github.com/golang-sql/sqlexp/namer.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlexp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
DialectPostgres = "postgres"
|
||||
DialectTSQL = "tsql"
|
||||
DialectMySQL = "mysql"
|
||||
DialectSQLite = "sqlite"
|
||||
DialectOracle = "oracle"
|
||||
)
|
||||
|
||||
// Namer returns the name of the database and the SQL dialect it
|
||||
// uses.
|
||||
type Namer interface {
|
||||
// Name of the database management system.
|
||||
//
|
||||
// Examples:
|
||||
// "posgresql-9.6"
|
||||
// "sqlserver-10.54.32"
|
||||
// "cockroachdb-1.0"
|
||||
Name() string
|
||||
|
||||
// Dialect of SQL used in the database.
|
||||
Dialect() string
|
||||
}
|
||||
|
||||
// DriverNamer may be implemented on the driver.Driver interface.
|
||||
// It may need to request information from the server to return
|
||||
// the correct information.
|
||||
type DriverNamer interface {
|
||||
Namer(ctx context.Context) (Namer, error)
|
||||
}
|
||||
|
||||
// NamerFromDriver returns the DriverNamer from the DB if
|
||||
// it is implemented.
|
||||
func NamerFromDriver(d driver.Driver, ctx context.Context) (Namer, error) {
|
||||
if q, is := d.(DriverNamer); is {
|
||||
return q.Namer(ctx)
|
||||
}
|
||||
dv := reflect.ValueOf(d)
|
||||
|
||||
d, found := internalDrivers[dv.Type().String()]
|
||||
if found {
|
||||
if q, is := d.(DriverNamer); is {
|
||||
return q.Namer(ctx)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("namer not found")
|
||||
}
|
||||
67
vendor/github.com/golang-sql/sqlexp/pg.go
generated
vendored
Normal file
67
vendor/github.com/golang-sql/sqlexp/pg.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlexp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type postgresql struct{}
|
||||
|
||||
var (
|
||||
_ DriverNamer = postgresql{}
|
||||
_ DriverQuoter = postgresql{}
|
||||
_ DriverSavepointer = postgresql{}
|
||||
)
|
||||
|
||||
func (postgresql) Open(string) (driver.Conn, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (postgresql) Namer(ctx context.Context) (Namer, error) {
|
||||
return pgNamer{}, nil
|
||||
}
|
||||
|
||||
func (postgresql) Quoter(ctx context.Context) (Quoter, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (postgresql) Savepointer() (Savepointer, error) {
|
||||
return pgSavepointer{}, nil
|
||||
}
|
||||
|
||||
type pgNamer struct{}
|
||||
|
||||
func (pgNamer) Name() string {
|
||||
return "postgresql"
|
||||
}
|
||||
func (pgNamer) Dialect() string {
|
||||
return DialectPostgres
|
||||
}
|
||||
|
||||
type pgQuoter struct{}
|
||||
|
||||
func (pgQuoter) ID(name string) string {
|
||||
return ""
|
||||
}
|
||||
func (pgQuoter) Value(v interface{}) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type pgSavepointer struct{}
|
||||
|
||||
func (pgSavepointer) Release(name string) string {
|
||||
return fmt.Sprintf("release savepoint %s;", name)
|
||||
}
|
||||
|
||||
func (pgSavepointer) Create(name string) string {
|
||||
return fmt.Sprintf("savepoint %s;", name)
|
||||
}
|
||||
|
||||
func (pgSavepointer) Rollback(name string) string {
|
||||
return fmt.Sprintf("rollback to savepoint %s;", name)
|
||||
}
|
||||
22
vendor/github.com/golang-sql/sqlexp/querier.go
generated
vendored
Normal file
22
vendor/github.com/golang-sql/sqlexp/querier.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlexp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// Querier is the common interface to execute queries on a DB, Tx, or Conn.
|
||||
type Querier interface {
|
||||
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
|
||||
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
|
||||
QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
var (
|
||||
_ Querier = &sql.DB{}
|
||||
_ Querier = &sql.Tx{}
|
||||
)
|
||||
57
vendor/github.com/golang-sql/sqlexp/quoter.go
generated
vendored
Normal file
57
vendor/github.com/golang-sql/sqlexp/quoter.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlexp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// BUG(kardianos): Both the Quoter and Namer may need to access the server.
|
||||
|
||||
// Quoter returns safe and valid SQL strings to use when building a SQL text.
|
||||
type Quoter interface {
|
||||
// ID quotes identifiers such as schema, table, or column names.
|
||||
// ID does not operate on multipart identifiers such as "public.Table",
|
||||
// it only operates on single identifiers such as "public" and "Table".
|
||||
ID(name string) string
|
||||
|
||||
// Value quotes database values such as string or []byte types as strings
|
||||
// that are suitable and safe to embed in SQL text. The returned value
|
||||
// of a string will include all surrounding quotes.
|
||||
//
|
||||
// If a value type is not supported it must panic.
|
||||
Value(v interface{}) string
|
||||
}
|
||||
|
||||
// DriverQuoter returns a Quoter interface and is suitable for extending
|
||||
// the driver.Driver type.
|
||||
//
|
||||
// The driver may need to hit the database to determine how it is configured to
|
||||
// ensure the correct escaping rules are used.
|
||||
type DriverQuoter interface {
|
||||
Quoter(ctx context.Context) (Quoter, error)
|
||||
}
|
||||
|
||||
// QuoterFromDriver takes a database driver, often obtained through a sql.DB.Driver
|
||||
// call or from using it directly to get the quoter interface.
|
||||
//
|
||||
// Currently MssqlDriver is hard-coded to also return a valided Quoter.
|
||||
func QuoterFromDriver(d driver.Driver, ctx context.Context) (Quoter, error) {
|
||||
if q, is := d.(DriverQuoter); is {
|
||||
return q.Quoter(ctx)
|
||||
}
|
||||
dv := reflect.ValueOf(d)
|
||||
|
||||
d, found := internalDrivers[dv.Type().String()]
|
||||
if found {
|
||||
if q, is := d.(DriverQuoter); is {
|
||||
return q.Quoter(ctx)
|
||||
}
|
||||
}
|
||||
return nil, errors.New("quoter interface not found")
|
||||
}
|
||||
15
vendor/github.com/golang-sql/sqlexp/registry.go
generated
vendored
Normal file
15
vendor/github.com/golang-sql/sqlexp/registry.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlexp
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
)
|
||||
|
||||
var internalDrivers = map[string]driver.Driver{
|
||||
"*mssql.MssqlDriver": mssql{},
|
||||
"*pq.Driver": postgresql{},
|
||||
"*stdlib.Driver": postgresql{},
|
||||
}
|
||||
37
vendor/github.com/golang-sql/sqlexp/savepoint.go
generated
vendored
Normal file
37
vendor/github.com/golang-sql/sqlexp/savepoint.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sqlexp
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Savepointer interface {
|
||||
Release(name string) string
|
||||
Create(name string) string
|
||||
Rollback(name string) string
|
||||
}
|
||||
|
||||
type DriverSavepointer interface {
|
||||
Savepointer() (Savepointer, error)
|
||||
}
|
||||
|
||||
// SavepointFromDriver
|
||||
func SavepointFromDriver(d driver.Driver) (Savepointer, error) {
|
||||
if q, is := d.(DriverSavepointer); is {
|
||||
return q.Savepointer()
|
||||
}
|
||||
dv := reflect.ValueOf(d)
|
||||
|
||||
d, found := internalDrivers[dv.Type().String()]
|
||||
if found {
|
||||
if q, is := d.(DriverSavepointer); is {
|
||||
return q.Savepointer()
|
||||
}
|
||||
}
|
||||
return nil, errors.New("savepointer interface not found")
|
||||
}
|
||||
24
vendor/github.com/microsoft/go-mssqldb/.gitignore
generated
vendored
Normal file
24
vendor/github.com/microsoft/go-mssqldb/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
/.idea
|
||||
/.connstr
|
||||
.vscode
|
||||
.terraform
|
||||
*.tfstate*
|
||||
*.log
|
||||
*.swp
|
||||
*~
|
||||
coverage.json
|
||||
coverage.txt
|
||||
coverage.xml
|
||||
testresults.xml
|
||||
.azureconnstr
|
||||
|
||||
# Example binaries
|
||||
examples/*/simple
|
||||
examples/*/azuread-service-principal
|
||||
examples/*/tsql
|
||||
examples/*/bulk
|
||||
examples/*/routine
|
||||
examples/*/tvp
|
||||
examples/*/aws-rds-proxy-iam-auth
|
||||
examples/*/azuread-accesstoken
|
||||
examples/*/azuread-service-principal-authtoken
|
||||
10
vendor/github.com/microsoft/go-mssqldb/.golangci.yml
generated
vendored
Normal file
10
vendor/github.com/microsoft/go-mssqldb/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
version: "2"
|
||||
linters:
|
||||
enable:
|
||||
# basic go linters
|
||||
- govet
|
||||
- revive # replacing golint as it is deprecated
|
||||
|
||||
# sql related linters
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
147
vendor/github.com/microsoft/go-mssqldb/CHANGELOG.md
generated
vendored
Normal file
147
vendor/github.com/microsoft/go-mssqldb/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
# Changelog
|
||||
## 1.9.6
|
||||
|
||||
### Features
|
||||
|
||||
* Added new `serverCertificate` connection parameter for byte-for-byte certificate validation, matching Microsoft.Data.SqlClient behavior. This parameter skips hostname validation, chain validation, and expiry checks, only verifying that the server's certificate exactly matches the provided file. This is useful when the server's hostname doesn't match the certificate CN/SAN. (#304)
|
||||
* The existing `certificate` parameter maintains backward compatibility with traditional X.509 chain validation including hostname checks, expiry validation, and chain-of-trust verification.
|
||||
* `serverCertificate` cannot be used with `certificate` or `hostnameincertificate` parameters to prevent conflicting validation methods.
|
||||
|
||||
## 1.9.3
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fix parsing of ADO connection strings with double-quoted values containing semicolons (#282)
|
||||
|
||||
## 1.9.2
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fix race condition in message queue query model (#277)
|
||||
|
||||
## 1.9.1
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fix bulk insert failure with datetime values near midnight due to day overflow (#271)
|
||||
* Fix: apply guidConversion option in TestBulkcopy (#255)
|
||||
|
||||
### Features
|
||||
|
||||
* support configuring custom time.Location for datetime encoding and decoding via DSN (#260)
|
||||
* Implement support for the latest Azure credential types in the azuread package (#269)
|
||||
|
||||
## 1.8.2
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Added "Pwd" as a recognized alias for "Password" in connection strings (#262)
|
||||
* Updated `isProc` to detect more keywords
|
||||
|
||||
## 1.7.0
|
||||
|
||||
### Changed
|
||||
|
||||
* Changed always encrypted key provider error handling not to panic on failure
|
||||
|
||||
### Features
|
||||
|
||||
* Support DER certificates for server authentication (#152)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Improved speed of CharsetToUTF8 (#154)
|
||||
|
||||
## 1.7.0
|
||||
|
||||
### Changed
|
||||
|
||||
* krb5 authenticator supports standard Kerberos environment variables for configuration
|
||||
|
||||
## 1.6.0
|
||||
|
||||
### Changed
|
||||
|
||||
* Go.mod updated to Go 1.17
|
||||
* Azure SDK for Go dependencies updated
|
||||
|
||||
### Features
|
||||
|
||||
* Added `ActiveDirectoryAzCli` and `ActiveDirectoryDeviceCode` authentication types to `azuread` package
|
||||
* Always Encrypted encryption and decryption with 2 hour key cache (#116)
|
||||
* 'pfx', 'MSSQL_CERTIFICATE_STORE', and 'AZURE_KEY_VAULT' encryption key providers
|
||||
* TDS8 can now be used for connections by setting encrypt="strict"
|
||||
|
||||
## 1.5.0
|
||||
|
||||
### Features
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Handle extended character in SQL instance names for browser lookup (#122)
|
||||
|
||||
## 1.4.0
|
||||
|
||||
### Features
|
||||
|
||||
* Adds UnmarshalJSON interface for UniqueIdentifier (#126)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fixes MarshalText prototype for UniqueIdentifier
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### Features
|
||||
|
||||
* A connector's dialer can now be used to resolve DNS if the dialer implements the `HostDialer` interface
|
||||
|
||||
## 1.0.0
|
||||
|
||||
### Features
|
||||
|
||||
* `admin` protocol for dedicated administrator connections
|
||||
|
||||
### Changed
|
||||
|
||||
* Added `Hidden()` method to `ProtocolParser` interface
|
||||
|
||||
## 0.21.0
|
||||
|
||||
### Features
|
||||
|
||||
* Updated azidentity to 1.2.1, which adds in memory cache for managed credentials ([#90](https://github.com/microsoft/go-mssqldb/pull/90))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fixed uninitialized server name in TLS config ([#93](https://github.com/microsoft/go-mssqldb/issues/93))([#94](https://github.com/microsoft/go-mssqldb/pull/94))
|
||||
* Fixed several kerberos authentication usages on Linux with new krb5 authentication provider. ([#65](https://github.com/microsoft/go-mssqldb/pull/65))
|
||||
|
||||
### Changed
|
||||
|
||||
* New kerberos authenticator implementation uses more explicit connection string parameters.
|
||||
|
||||
| Old | New |
|
||||
|--------------|--------------------|
|
||||
| krb5conffile | krb5-configfile |
|
||||
| krbcache | krb5-credcachefile |
|
||||
| keytabfile | krb5-keytabfile |
|
||||
| realm | krb5-realm |
|
||||
|
||||
## 0.20.0
|
||||
|
||||
### Features
|
||||
|
||||
* Add driver version and name to TDS login packets
|
||||
* Add `pipe` connection string parameter for named pipe dialer
|
||||
* Expose network errors that occur during connection establishment. Now they are
|
||||
wrapped, and can be detected by using errors.As/Is practise. This connection
|
||||
errors can, and could even before, happen anytime the sql.DB doesn't have free
|
||||
connection for executed query.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Added checks while reading prelogin for invalid data ([#64](https://github.com/microsoft/go-mssqldb/issues/64))([86ecefd8b](https://github.com/microsoft/go-mssqldb/commit/86ecefd8b57683aeb5ad9328066ee73fbccd62f5))
|
||||
|
||||
* Fixed multi-protocol dialer path to avoid unneeded SQL Browser queries
|
||||
|
||||
14
vendor/github.com/microsoft/go-mssqldb/CONTRIBUTING.md
generated
vendored
Normal file
14
vendor/github.com/microsoft/go-mssqldb/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to
|
||||
agree to a Contributor License Agreement (CLA) declaring that you have the right to,
|
||||
and actually do, grant us the rights to use your contribution. For details, visit
|
||||
https://cla.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA-bot will automatically determine whether you need
|
||||
to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the
|
||||
instructions provided by the bot. You will only need to do this once across all repositories using our CLA.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
28
vendor/github.com/microsoft/go-mssqldb/LICENSE.txt
generated
vendored
Normal file
28
vendor/github.com/microsoft/go-mssqldb/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
664
vendor/github.com/microsoft/go-mssqldb/README.md
generated
vendored
Normal file
664
vendor/github.com/microsoft/go-mssqldb/README.md
generated
vendored
Normal file
@@ -0,0 +1,664 @@
|
||||
# Microsoft's official Go MSSQL driver
|
||||
|
||||
[](https://pkg.go.dev/github.com/microsoft/go-mssqldb)
|
||||
[](https://ci.appveyor.com/project/microsoft/go-mssqldb)
|
||||
[](https://codecov.io/gh/microsoft/go-mssqldb)
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
Requires Go 1.17 or above.
|
||||
|
||||
Install with `go install github.com/microsoft/go-mssqldb@latest`.
|
||||
|
||||
## Connection Parameters and DSN
|
||||
|
||||
The recommended connection string uses a URL format:
|
||||
`sqlserver://username:password@host/instance?param1=value¶m2=value`
|
||||
Other supported formats are listed below.
|
||||
|
||||
### Common parameters
|
||||
|
||||
* `user id` - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used. The user domain sensitive to the case which is defined in the connection string.
|
||||
* `password`
|
||||
* `database`
|
||||
* `connection timeout` - in seconds (default is 0 for no timeout), set to 0 for no timeout. Recommended to set to 0 and use context to manage query and connection timeouts.
|
||||
* `dial timeout` - in seconds (default is 15 times the number of registered protocols), set to 0 for no timeout.
|
||||
* `encrypt`
|
||||
* `strict` - Data sent between client and server is encrypted E2E using [TDS8](https://learn.microsoft.com/en-us/sql/relational-databases/security/networking/tds-8?view=sql-server-ver16).
|
||||
* `disable` - Data send between client and server is not encrypted.
|
||||
* `false`/`optional`/`no`/`0`/`f` - Data sent between client and server is not encrypted beyond the login packet. (Default)
|
||||
* `true`/`mandatory`/`yes`/`1`/`t` - Data sent between client and server is encrypted.
|
||||
* `app name` - The application name (default is go-mssqldb)
|
||||
* `authenticator` - Can be used to specify use of a registered authentication provider. (e.g. ntlm, winsspi (on windows) or krb5 (on linux))
|
||||
* `timezone` - Sets the time zone used by the driver when parsing time types. For example: `timezone=Asia/Shanghai`. Supports [IANA](https://www.iana.org/time-zones) time zone names.
|
||||
|
||||
### Connection parameters for ODBC and ADO style connection strings
|
||||
|
||||
* `server` - host or host\instance (default localhost)
|
||||
* `port` - specifies the host\instance port (default 1433). If instance name is provided but no port, the driver will use SQL Server Browser to discover the port.
|
||||
|
||||
### Less common parameters
|
||||
|
||||
* `keepAlive` - in seconds; 0 to disable (default is 30)
|
||||
* `failoverpartner` - host or host\instance (default is no partner).
|
||||
* `failoverport` - used only when there is no instance in failoverpartner (default 1433)
|
||||
* `packet size` - in bytes; 512 to 32767 (default is 4096)
|
||||
* Encrypted connections have a maximum packet size of 16383 bytes
|
||||
* Further information on usage: <https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option>
|
||||
* `log` - logging flags (default `0`/no logging, `255` for full logging)
|
||||
* `1` log errors
|
||||
* `2` log messages
|
||||
* `4` log rows affected
|
||||
* `8` trace sql statements
|
||||
* `16` log statement parameters
|
||||
* `32` log transaction begin/end
|
||||
* `64` additional debug logs
|
||||
* `128` log retries
|
||||
* `TrustServerCertificate`
|
||||
* false - Server certificate is checked. Default is false if encrypt is specified.
|
||||
* true - Server certificate is not checked. Default is true if encrypt is not specified. If trust server certificate is true, driver accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing.
|
||||
* `certificate` - The file path to a certificate authority (CA) certificate or server certificate for traditional X.509 chain validation. The specified certificate overrides the go platform specific CA certificates. The driver validates the certificate chain, expiry, and hostname. Supports PEM and DER formats.
|
||||
* `serverCertificate` - The file path to a server certificate for byte-for-byte comparison validation (new in v1.9.6). The driver validates that the server's certificate exactly matches this file, skipping chain validation, expiry checks, and hostname validation. This matches Microsoft.Data.SqlClient behavior. Cannot be used with `certificate` or `hostnameincertificate`. Supports PEM and DER formats.
|
||||
* `hostNameInCertificate` - Specifies the Common Name (CN) in the server certificate. Default value is the server host. Used with the `certificate` parameter, not applicable for `serverCertificate`.
|
||||
* `tlsmin` - Specifies the minimum TLS version for negotiating encryption with the server. Recognized values are `1.0`, `1.1`, `1.2`, `1.3`. If not set to a recognized value the default value for the `tls` package will be used. The default is currently `1.2`.
|
||||
* `ServerSPN` - The kerberos SPN (Service Principal Name) for the server. Default is MSSQLSvc/host:port.
|
||||
* `Workstation ID` - The workstation name (default is the host name)
|
||||
* `ApplicationIntent` - Can be given the value `ReadOnly` to initiate a read-only connection to an Availability Group listener. The `database` must be specified when connecting with `Application Intent` set to `ReadOnly`.
|
||||
* `protocol` - forces use of a protocol. Make sure the corresponding package is imported.
|
||||
* `columnencryption` or `column encryption setting` - a boolean value indicating whether Always Encrypted should be enabled on the connection.
|
||||
* `multisubnetfailover`
|
||||
* `true` (Default) Client attempt to connect to all IPs simultaneously.
|
||||
* `false` Client attempts to connect to IPs in serial.
|
||||
* `guid conversion` - Enables the conversion of GUIDs, so that byte order is preserved. UniqueIdentifier isn't supported for nullable fields, NullUniqueIdentifier must be used instead.
|
||||
|
||||
### Connection parameters for namedpipe package
|
||||
* `pipe` - If set, no Browser query is made and named pipe used will be `\\<host>\pipe\<pipe>`
|
||||
* `protocol` can be set to `np`
|
||||
* For a non-URL DSN, the `server` parameter can be set to the full pipe name like `\\host\pipe\sql\query`
|
||||
|
||||
If no pipe name can be derived from the DSN, connection attempts will first query the SQL Browser service to find the pipe name for the instance.
|
||||
|
||||
### DNS Resolution through a Custom Dialer
|
||||
|
||||
Custom Dialers can be used to resolve DNS if the Connection's Dialer implements the `HostDialer` interface. This is helpful when the dialer is proxying requests to a different, private network and the DNS record is local to the private network.
|
||||
|
||||
### Protocol configuration
|
||||
|
||||
To force a specific protocol for the connection there two several options:
|
||||
1. Prepend the server name in a DSN with the protocol and a colon, like `np:host` or `lpc:host` or `tcp:host`
|
||||
2. Set the `protocol` parameter to the protocol name
|
||||
|
||||
`msdsn.ProtocolParsers` can be reordered to prioritize other protocols ahead of `tcp`
|
||||
|
||||
The `admin` protocol will not be used for dialing unless the connection string explicitly specifies it. Note SQL Server allows only 1 admin (or DAC) connection to be active at a time.
|
||||
|
||||
### Kerberos Active Directory authentication outside Windows
|
||||
|
||||
To connect with kerberos authentication from a Linux server you can use the optional krb5 package.
|
||||
Imported krb alongside the main driver
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
...
|
||||
_ "github.com/microsoft/go-mssqldb"
|
||||
_ "github.com/microsoft/go-mssqldb/integratedauth/krb5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
It will become available for use when the connection string parameter "authenticator=krb5" is used.
|
||||
|
||||
The package supports authentication via 3 methods.
|
||||
|
||||
* Keytabs - Specify the username, keytab file, the krb5.conf file, and realm.
|
||||
|
||||
authenticator=krb5;server=DatabaseServerName;database=DBName;user id=MyUserName;krb5-realm=domain.com;krb5-configfile=/etc/krb5.conf;krb5-keytabfile=~/MyUserName.keytab
|
||||
|
||||
* Credential Cache - Specify the krb5.conf file path and credential cache file path.
|
||||
|
||||
authenticator=krb5;server=DatabaseServerName;database=DBName;krb5-configfile=/etc/krb5.conf;krb5-credcachefile=~/MyUserNameCachedCreds
|
||||
|
||||
* Raw credentials - Specity krb5.confg, Username, Password and Realm.
|
||||
|
||||
authenticator=krb5;server=DatabaseServerName;database=DBName;user id=MyUserName;password=foo;krb5-realm=comani.com;krb5-configfile=/etc/krb5.conf;
|
||||
|
||||
### Kerberos Parameters
|
||||
|
||||
* `authenticator` - set this to `krb5` to enable kerberos authentication. If this is not present, the default provider would be `ntlm` for unix and `winsspi` for windows.
|
||||
* `krb5-configfile` (optional) - path to kerberos configuration file. Defaults to `/etc/krb5.conf`. Can also be set using `KRB5_CONFIG` environment variable.
|
||||
* `krb5-realm` (required with keytab and raw credentials) - Domain name for kerberos authentication. Omit this parameter if the realm is part of the user name like `username@REALM`.
|
||||
* `krb5-keytabfile` - path to Keytab file. Can also be set using environment variable `KRB5_KTNAME`. If no parameter or environment variable is set, the `DefaultClientKeytabName` value from the krb5 config file is used.
|
||||
* `krb5-credcachefile` - path to Credential cache. Can also be set using environment variable `KRBCCNAME`.
|
||||
* `krb5-dnslookupkdc` - Optional parameter in all contexts. Set to lookup KDCs in DNS. Boolean. Default is true.
|
||||
* `krb5-udppreferencelimit` - Optional parameter in all contexts. 1 means to always use tcp. MIT krb5 has a default value of 1465, and it prevents user setting more than 32700. Integer. Default is 1.
|
||||
|
||||
For further information on usage:
|
||||
* <https://web.mit.edu/kerberos/krb5-1.12/doc/admin/conf_files/krb5_conf.html>
|
||||
* <https://web.mit.edu/kerberos/krb5-1.12/doc/basic/index.html>
|
||||
|
||||
### The connection string can be specified in one of three formats
|
||||
|
||||
1. URL: with `sqlserver` scheme. username and password appears before the host. Any instance appears as
|
||||
the first segment in the path. All other options are query parameters. Examples:
|
||||
|
||||
* `sqlserver://username:password@host/instance?param1=value¶m2=value`
|
||||
* `sqlserver://username:password@host:port?param1=value¶m2=value`
|
||||
* `sqlserver://sa@localhost/SQLExpress?database=master&connection+timeout=30` // `SQLExpress instance.
|
||||
* `sqlserver://sa:mypass@localhost?database=master&connection+timeout=30` // username=sa, password=mypass.
|
||||
* `sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30` // port 1234 on localhost.
|
||||
* `sqlserver://sa:my%7Bpass@somehost?connection+timeout=30` // password is "my{pass"
|
||||
A string of this format can be constructed using the `URL` type in the `net/url` package.
|
||||
|
||||
```go
|
||||
|
||||
query := url.Values{}
|
||||
query.Add("app name", "MyAppName")
|
||||
|
||||
u := &url.URL{
|
||||
Scheme: "sqlserver",
|
||||
User: url.UserPassword(username, password),
|
||||
Host: fmt.Sprintf("%s:%d", hostname, port),
|
||||
// Path: instance, // if connecting to an instance instead of a port
|
||||
RawQuery: query.Encode(),
|
||||
}
|
||||
db, err := sql.Open("sqlserver", u.String())
|
||||
|
||||
```
|
||||
|
||||
* `sqlserver://username@host/instance?krb5-configfile=path/to/file&krb5-credcachefile=/path/to/cache`
|
||||
* `sqlserver://username@host/instance?krb5-configfile=path/to/file&krb5-realm=domain.com&krb5-keytabfile=/path/to/keytabfile`
|
||||
|
||||
2. ADO: `key=value` pairs separated by `;`. Values can contain `;` and other special characters by enclosing them in double quotes. Leading and trailing whitespace is ignored.
|
||||
Examples:
|
||||
|
||||
* `server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName`
|
||||
* `server=localhost;user id=sa;database=master;app name=MyAppName`
|
||||
* `server=localhost;user id=sa;password="my;complex;password";database=master` // Password with semicolons
|
||||
* `server=localhost;user id=sa;password="value with ""quotes"" inside";database=master` // Escaped quotes using double quotes
|
||||
* `server=localhost;user id=sa;database=master;app name=MyAppName;krb5-configfile=path/to/file;krb5-credcachefile=path/to/cache;authenticator=krb5`
|
||||
* `server=localhost;user id=sa;database=master;app name=MyAppName;krb5-configfile=path/to/file;krb5-realm=domain.com;krb5-keytabfile=path/to/keytabfile;authenticator=krb5`
|
||||
|
||||
|
||||
ADO strings support synonyms for database, app name, user id, and server
|
||||
* server <= addr, address, network address, data source
|
||||
* user id <= user, uid
|
||||
* database <= initial catalog
|
||||
* app name <= application name
|
||||
|
||||
3. ODBC: Prefix with `odbc`, `key=value` pairs separated by `;`. Allow `;` by wrapping
|
||||
values in `{}`. Examples:
|
||||
|
||||
* `odbc:server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName`
|
||||
* `odbc:server=localhost;user id=sa;database=master;app name=MyAppName`
|
||||
* `odbc:server=localhost;user id=sa;password={foo;bar}` // Value marked with `{}`, password is "foo;bar"
|
||||
* `odbc:server=localhost;user id=sa;password={foo{bar}` // Value marked with `{}`, password is "foo{bar"
|
||||
* `odbc:server=localhost;user id=sa;password={foobar }` // Value marked with `{}`, password is "foobar "
|
||||
* `odbc:server=localhost;user id=sa;password=foo{bar` // Literal `{`, password is "foo{bar"
|
||||
* `odbc:server=localhost;user id=sa;password=foo}bar` // Literal `}`, password is "foo}bar"
|
||||
* `odbc:server=localhost;user id=sa;password={foo{bar}` // Literal `{`, password is "foo{bar"
|
||||
* `odbc:server=localhost;user id=sa;password={foo}}bar}` // Escaped `} with`}}`, password is "foo}bar"
|
||||
* `odbc:server=localhost;user id=sa;database=master;app name=MyAppName;krb5-configfile=path/to/file;krb5-credcachefile=path/to/cache;authenticator=krb5`
|
||||
* `odbc:server=localhost;user id=sa;database=master;app name=MyAppName;krb5-configfile=path/to/file;krb5-realm=domain.com;krb5-keytabfile=path/to/keytabfile;authenticator=krb5`
|
||||
|
||||
### Using server certificates with encryption
|
||||
|
||||
The driver supports two ways to validate server certificates:
|
||||
|
||||
#### 1. `serverCertificate` - Byte-for-byte certificate comparison (New in v1.9.6)
|
||||
|
||||
When you provide a `serverCertificate` parameter, the driver validates the server by comparing the certificate bytes exactly with the provided file. This:
|
||||
- Skips hostname validation (allows mismatched hostnames)
|
||||
- Skips certificate chain validation and expiry checks
|
||||
- Only accepts connections where the server's certificate exactly matches the provided file
|
||||
- Matches the behavior of Microsoft.Data.SqlClient
|
||||
|
||||
This is useful when:
|
||||
- The server's DNS name doesn't match the certificate CN/SAN
|
||||
- You want to validate against a specific certificate without hostname validation
|
||||
- You're connecting through proxies or load balancers with different hostnames
|
||||
|
||||
**Restrictions**: `serverCertificate` cannot be used with `certificate` or `hostnameincertificate` parameters.
|
||||
|
||||
#### 2. `certificate` - Traditional chain validation (Backward compatible)
|
||||
|
||||
The `certificate` parameter performs standard X.509 certificate chain validation:
|
||||
- Validates the certificate chain against the provided CA certificate(s)
|
||||
- Checks certificate expiry and validity
|
||||
- Enforces hostname validation (unless `hostnameincertificate` is used)
|
||||
|
||||
#### Obtaining the server certificate
|
||||
|
||||
You can obtain a copy of the server's certificate using OpenSSL:
|
||||
|
||||
```bash
|
||||
openssl s_client -connect server:1433 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM > cert.pem
|
||||
```
|
||||
|
||||
#### Example connection strings
|
||||
|
||||
Using `serverCertificate` for byte-comparison (skips hostname validation):
|
||||
|
||||
URL format:
|
||||
```
|
||||
sqlserver://username:password@host:1433?database=master&encrypt=true&serverCertificate=/path/to/cert.pem
|
||||
```
|
||||
|
||||
ADO format:
|
||||
```
|
||||
server=myserver;user id=sa;password=mypass;database=master;encrypt=true;serverCertificate=/path/to/cert.pem
|
||||
```
|
||||
|
||||
Using `certificate` for traditional chain validation:
|
||||
|
||||
URL format:
|
||||
```
|
||||
sqlserver://username:password@host:1433?database=master&encrypt=true&certificate=/path/to/ca.pem
|
||||
```
|
||||
|
||||
ADO format:
|
||||
```
|
||||
server=myserver;user id=sa;password=mypass;database=master;encrypt=true;certificate=/path/to/ca.pem
|
||||
```
|
||||
|
||||
### Azure Active Directory authentication
|
||||
|
||||
Azure Active Directory authentication uses temporary authentication tokens to authenticate.
|
||||
The `mssql` package does not provide an implementation to obtain tokens: instead, import the `azuread` package and use driver name `azuresql`. This driver uses [azidentity](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#section-readme) to acquire tokens using a variety of credential types.
|
||||
|
||||
To reduce friction in local development, `ActiveDirectoryDefault` can authenticate as the user signed into the Azure CLI.
|
||||
|
||||
Run the following command to sign into the Azure CLI before running your application using the `ActiveDirectoryDefault` connection string parameter:
|
||||
|
||||
```azurecli
|
||||
az login
|
||||
```
|
||||
|
||||
Azure CLI authentication isn't recommended for applications running in Azure. More details are available via the [Azure authentication with the Azure Identity module for Go](https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication) tutorial.
|
||||
|
||||
The credential type is determined by the new `fedauth` connection string parameter.
|
||||
|
||||
* `fedauth=ActiveDirectoryServicePrincipal` or `fedauth=ActiveDirectoryApplication` - authenticates using an Azure Active Directory application client ID and client secret or certificate. Implemented using [ClientSecretCredential or CertificateCredential](https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/azidentity#authenticating-service-principals)
|
||||
* `clientcertpath=<path to certificate file>;password=<certificate password>` or
|
||||
* `password=<client secret>`
|
||||
* `user id=<application id>[@tenantid]` Note the `@tenantid` component can be omitted if the server's tenant is the same as the application's tenant.
|
||||
* `fedauth=ActiveDirectoryPassword` - authenticates using a user name and password.
|
||||
* `user id=username@domain`
|
||||
* `password=<password>`
|
||||
* `applicationclientid=<application id>` - This guid identifies an Azure Active Directory enterprise application that the AAD admin has approved for accessing Azure SQL database resources in the tenant. This driver does not have an associated application id of its own.
|
||||
* `fedauth=ActiveDirectoryDefault` - authenticates using a chained set of credentials. The chain is built from EnvironmentCredential -> ManagedIdentityCredential->AzureCLICredential. See [DefaultAzureCredential docs](https://github.com/Azure/azure-sdk-for-go/wiki/Set-up-Your-Environment-for-Authentication#configure-defaultazurecredential) for instructions on setting up your host environment to use it. Using this option allows you to have the same connection string in a service deployment as on your interactive development machine.
|
||||
* `fedauth=ActiveDirectoryManagedIdentity` or `fedauth=ActiveDirectoryMSI` - authenticates using a system-assigned or user-assigned Azure Managed Identity.
|
||||
* `user id=<identity id>` - optional id of user-assigned managed identity. If empty, system-assigned managed identity is used.
|
||||
* `resource id=<resource id>` - optional resource id of user-assigned managed identity. If empty, system-assigned managed identity or user id are used (if both user id and resource id are provided, resource id will be used)
|
||||
* `fedauth=ActiveDirectoryInteractive` - authenticates using credentials acquired from an external web browser. Only suitable for use with human interaction.
|
||||
* `applicationclientid=<application id>` - This guid identifies an Azure Active Directory enterprise application that the AAD admin has approved for accessing Azure SQL database resources in the tenant. This driver does not have an associated application id of its own.
|
||||
* `fedauth=ActiveDirectoryDeviceCode` - prints a message to stdout giving the user a URL and code to authenticate. Connection continues after user completes the login separately.
|
||||
* `fedauth=ActiveDirectoryAzCli` - reuses local authentication the user already performed using Azure CLI.
|
||||
* `fedauth=ActiveDirectoryAzureDeveloperCli` - reuses local authentication the user already performed using Azure Developer CLI.
|
||||
* `fedauth=ActiveDirectoryEnvironment` - authenticates using environment variables. Uses the same environment variables as [EnvironmentCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#EnvironmentCredential).
|
||||
* `fedauth=ActiveDirectoryWorkloadIdentity` - authenticates using workload identity credentials for Kubernetes and other OIDC environments.
|
||||
* `fedauth=ActiveDirectoryAzurePipelines` - authenticates using Azure Pipelines service connection.
|
||||
* `user id=<service principal id>[@tenantid]` - The service principal client ID and tenant ID. If not provided, uses `AZURESUBSCRIPTION_CLIENT_ID` and `AZURESUBSCRIPTION_TENANT_ID` environment variables.
|
||||
* `serviceconnectionid=<connection id>` - The service connection ID from Azure DevOps. If not provided, uses `AZURESUBSCRIPTION_SERVICE_CONNECTION_ID` environment variable.
|
||||
* `systemtoken=<system token>` - The system access token for the pipeline. If not provided, uses `SYSTEM_ACCESSTOKEN` environment variable.
|
||||
* Note: Environment variables are automatically configured by Azure Pipelines in AzureCLI@2 and AzurePowerShell@5 tasks.
|
||||
* `fedauth=ActiveDirectoryClientAssertion` - authenticates using a client assertion (JWT token).
|
||||
* `user id=<client id>[@tenantid]` - The client ID and tenant ID.
|
||||
* `clientassertion=<jwt token>` - The JWT assertion token.
|
||||
* `fedauth=ActiveDirectoryOnBehalfOf` - authenticates using the on-behalf-of flow for delegated access.
|
||||
* `user id=<client id>[@tenantid]` - The client ID and tenant ID.
|
||||
* `userassertion=<user token>` - The user assertion token.
|
||||
* Use one of the following for client authentication:
|
||||
* `password=<client secret>` - Client secret
|
||||
* `clientcertpath=<path to certificate file>;password=<certificate password>` - Client certificate
|
||||
* `clientassertion=<jwt token>` - Client assertion JWT
|
||||
|
||||
#### Common Credential Options
|
||||
|
||||
The following connection string parameters can be used with most Azure credential types to provide additional configuration:
|
||||
|
||||
* `additionallyallowedtenants=<tenant1,tenant2>` - Comma or semicolon-separated list of additional tenant IDs that the credential may authenticate to. Use "*" to allow any tenant.
|
||||
* `disableinstancediscovery=true` - Disables Microsoft Entra instance discovery. Set to `true` only for disconnected or private clouds like Azure Stack.
|
||||
* `tokenfilepath=<path>` - For `ActiveDirectoryWorkloadIdentity`, specifies the path to the Kubernetes service account token file.
|
||||
* `sendcertificatechain=true` - For certificate-based authentication, controls whether to send the full certificate chain in token requests. Required for Subject Name/Issuer (SNI) authentication.
|
||||
|
||||
```go
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/url"
|
||||
|
||||
// Import the Azure AD driver module (also imports the regular driver package)
|
||||
"github.com/microsoft/go-mssqldb/azuread"
|
||||
)
|
||||
|
||||
func ConnectWithMSI() (*sql.DB, error) {
|
||||
return sql.Open(azuread.DriverName, "sqlserver://azuresql.database.windows.net?database=yourdb&fedauth=ActiveDirectoryMSI")
|
||||
}
|
||||
|
||||
func ConnectWithEnvironmentCredential() (*sql.DB, error) {
|
||||
// Requires AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET environment variables
|
||||
return sql.Open(azuread.DriverName, "sqlserver://azuresql.database.windows.net?database=yourdb&fedauth=ActiveDirectoryEnvironment")
|
||||
}
|
||||
|
||||
func ConnectWithWorkloadIdentity() (*sql.DB, error) {
|
||||
// For use in Kubernetes environments with workload identity
|
||||
return sql.Open(azuread.DriverName, "sqlserver://azuresql.database.windows.net?database=yourdb&fedauth=ActiveDirectoryWorkloadIdentity")
|
||||
}
|
||||
|
||||
func ConnectWithAzurePipelines() (*sql.DB, error) {
|
||||
// For use in Azure DevOps Pipelines with explicit parameters
|
||||
connStr := "sqlserver://azuresql.database.windows.net?database=yourdb&fedauth=ActiveDirectoryAzurePipelines"
|
||||
connStr += "&user+id=" + url.QueryEscape("client-id@tenant-id")
|
||||
connStr += "&serviceconnectionid=connection-id"
|
||||
connStr += "&systemtoken=access-token"
|
||||
return sql.Open(azuread.DriverName, connStr)
|
||||
}
|
||||
|
||||
func ConnectWithAzurePipelinesEnvVars() (*sql.DB, error) {
|
||||
// For use in Azure DevOps Pipelines with AzureCLI@2 or AzurePowerShell@5 tasks
|
||||
// Environment variables are automatically set by these tasks
|
||||
connStr := "sqlserver://azuresql.database.windows.net?database=yourdb&fedauth=ActiveDirectoryAzurePipelines"
|
||||
connStr += "&systemtoken=access-token" // Only systemtoken needs to be provided
|
||||
return sql.Open(azuread.DriverName, connStr)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Executing Stored Procedures
|
||||
|
||||
To run a stored procedure, set the query text to the procedure name:
|
||||
|
||||
```go
|
||||
|
||||
var account = "abc"
|
||||
_, err := db.ExecContext(ctx, "sp_RunMe",
|
||||
sql.Named("ID", 123),
|
||||
sql.Named("Account", sql.Out{Dest: &account}),
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
## Reading Output Parameters from a Stored Procedure with Resultset
|
||||
|
||||
To read output parameters from a stored procedure with resultset, make sure you read all the rows before reading the output parameters:
|
||||
|
||||
```go
|
||||
|
||||
sqltextcreate := `
|
||||
CREATE PROCEDURE spwithoutputandrows
|
||||
@bitparam BIT OUTPUT
|
||||
AS BEGIN
|
||||
SET @bitparam = 1
|
||||
SELECT 'Row 1'
|
||||
END
|
||||
`
|
||||
var bitout int64
|
||||
rows, err := db.QueryContext(ctx, "spwithoutputandrows", sql.Named("bitparam", sql.Out{Dest: &bitout}))
|
||||
var strrow string
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&strrow)
|
||||
}
|
||||
fmt.Printf("bitparam is %d", bitout)
|
||||
|
||||
```
|
||||
|
||||
## Caveat for local temporary tables
|
||||
|
||||
Due to protocol limitations, temporary tables will only be allocated on the connection
|
||||
as a result of executing a query with zero parameters. The following query
|
||||
will, due to the use of a parameter, execute in its own session,
|
||||
and `#mytemp` will be de-allocated right away:
|
||||
|
||||
```go
|
||||
conn, err := pool.Conn(ctx)
|
||||
defer conn.Close()
|
||||
_, err := conn.ExecContext(ctx, "select @p1 as x into #mytemp", 1)
|
||||
// at this point #mytemp is already dropped again as the session of the ExecContext is over
|
||||
```
|
||||
|
||||
To work around this, always explicitly create the local temporary
|
||||
table in a query without any parameters. As a special case, the driver
|
||||
will then be able to execute the query directly on the
|
||||
connection-scoped session. The following example works:
|
||||
|
||||
```go
|
||||
conn, err := pool.Conn(ctx)
|
||||
|
||||
// Set us up so that temp table is always cleaned up, since conn.Close()
|
||||
// merely returns conn to pool, rather than actually closing the connection.
|
||||
defer func() {
|
||||
_, _ = conn.ExecContext(ctx, "drop table #mytemp") // always clean up
|
||||
conn.Close() // merely returns conn to pool
|
||||
}()
|
||||
|
||||
|
||||
// Since we not pass any parameters below, the query will execute on the scope of
|
||||
// the connection and succeed in creating the table.
|
||||
_, err := conn.ExecContext(ctx, "create table #mytemp ( x int )")
|
||||
|
||||
// #mytemp is now available even if you pass parameters
|
||||
_, err := conn.ExecContext(ctx, "insert into #mytemp (x) values (@p1)", 1)
|
||||
|
||||
```
|
||||
|
||||
## Return Status
|
||||
|
||||
To get the procedure return status, pass into the parameters a
|
||||
`*mssql.ReturnStatus`. For example:
|
||||
|
||||
```go
|
||||
|
||||
var rs mssql.ReturnStatus
|
||||
_, err := db.ExecContext(ctx, "theproc", &rs)
|
||||
log.Printf("status=%d", rs)
|
||||
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```go
|
||||
var rs mssql.ReturnStatus
|
||||
_, err := db.QueryContext(ctx, "theproc", &rs)
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&val)
|
||||
}
|
||||
log.Printf("status=%d", rs)
|
||||
|
||||
```
|
||||
|
||||
Limitation: ReturnStatus cannot be retrieved using `QueryRow`.
|
||||
|
||||
## Parameters
|
||||
|
||||
The `sqlserver` driver uses normal MS SQL Server syntax and expects parameters in
|
||||
the sql query to be in the form of either `@Name` or `@p1` to `@pN` (ordinal position).
|
||||
|
||||
```go
|
||||
|
||||
db.QueryContext(ctx, `select * from t where ID = @ID and Name = @p2;`, sql.Named("ID", 6), "Bob")
|
||||
|
||||
```
|
||||
|
||||
### Parameter Types
|
||||
|
||||
To pass specific types to the query parameters, say `varchar` or `date` types,
|
||||
you must convert the types to the type before passing in. The following types
|
||||
are supported:
|
||||
|
||||
* string -> nvarchar
|
||||
* mssql.VarChar -> varchar
|
||||
* time.Time -> datetimeoffset or datetime (TDS version dependent)
|
||||
* mssql.DateTime1 -> datetime
|
||||
* mssql.DateTimeOffset -> datetimeoffset
|
||||
* "github.com/golang-sql/civil".Date -> date
|
||||
* "github.com/golang-sql/civil".DateTime -> datetime2
|
||||
* "github.com/golang-sql/civil".Time -> time
|
||||
* mssql.TVP -> Table Value Parameter (TDS version dependent)
|
||||
* "github.com/shopspring/decimal".Decimal -> decimal
|
||||
* mssql.Money -> money
|
||||
|
||||
Using an `int` parameter will send a 4 byte value (int) from a 32bit app and an 8 byte value (bigint) from a 64bit app.
|
||||
To make sure your integer parameter matches the size of the SQL parameter, use the appropriate sized type like `int32` or `int8`.
|
||||
|
||||
```go
|
||||
// If this is passed directly as a parameter,
|
||||
// the SQL parameter generated would be nvarchar
|
||||
name := "Bob"
|
||||
// If the user_name is defined as varchar,
|
||||
// it needs to be converted like this:
|
||||
db.QueryContext(ctx, `select * from t2 where user_name = @p1;`, mssql.VarChar(name))
|
||||
// Note: Mismatched data types on table and parameter may cause long running queries
|
||||
```
|
||||
|
||||
## Using Always Encrypted
|
||||
|
||||
The protocol and cryptography details for AE are [detailed elsewhere](https://learn.microsoft.com/sql/relational-databases/security/encryption/always-encrypted-database-engine?view=sql-server-ver16).
|
||||
|
||||
### Enablement
|
||||
|
||||
To enable AE on a connection, set the `ColumnEncryption` value to true on a config or pass `columnencryption=true` in the connection string.
|
||||
|
||||
Decryption and encryption won't succeed, however, without also including a decryption key provider. To avoid code size impacts on non-AE applications, key providers are not included by default.
|
||||
|
||||
Include the local certificate providers:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/microsoft/go-mssqldb/aecmk/localcert"
|
||||
)
|
||||
```
|
||||
|
||||
You can also instantiate a key provider directly in code and hand it to a `Connector` instance.
|
||||
|
||||
```go
|
||||
c := mssql.NewConnectorConfig(myconfig)
|
||||
c.RegisterCekProvider(providerName, MyProviderType{})
|
||||
```
|
||||
|
||||
### Decryption
|
||||
|
||||
If the correct key provider is included in your application, decryption of encrypted cells happens automatically with no extra server round trips.
|
||||
|
||||
### Encryption
|
||||
|
||||
Encryption of parameters passed to `Exec` and `Query` variants requires an extra round trip per query to fetch the encryption metadata. If the error returned by a query attempt indicates a type mismatch between the parameter and the destination table, most likely your input type is not a strict match for the SQL Server data type of the destination. You may be using a Go `string` when you need to use one of the driver-specific aliases like `VarChar` or `NVarCharMax`.
|
||||
|
||||
*** NOTE *** - Currently `char` and `varchar` types do not include a collation parameter component so can't be used for inserting encrypted values.
|
||||
https://github.com/microsoft/go-mssqldb/issues/129
|
||||
|
||||
|
||||
### Local certificate AE key provider
|
||||
|
||||
Key provider configuration is managed separately without any properties in the connection string.
|
||||
The `pfx` provider exposes its instance as the variable `PfxKeyProvider`. You can give it passwords for certificates using `SetCertificatePassword(pathToCertificate, path)`. Use an empty string or `"*"` as the path to use the same password for all certificates.
|
||||
|
||||
The `MSSQL_CERTIFICATE_STORE` provider exposes its instance as the variable `WindowsCertificateStoreKeyProvider`.
|
||||
|
||||
Both providers can be constrained to an allowed list of encryption key paths by appending paths to `provider.AllowedLocations`.
|
||||
|
||||
|
||||
### Azure Key Vault (AZURE_KEY_VAULT) key provider
|
||||
|
||||
Import this provider using `github.com/microsoft/go-mssqldb/aecmk/akv`
|
||||
|
||||
Constrain the provider to an allowed list of key vaults by appending vault host strings like "mykeyvault.vault.azure.net" to `akv.KeyProvider.AllowedLocations`.
|
||||
|
||||
## Important Notes
|
||||
|
||||
|
||||
* [LastInsertId](https://golang.org/pkg/database/sql/#Result.LastInsertId) should
|
||||
not be used with this driver (or SQL Server) due to how the TDS protocol
|
||||
works. Please use the [OUTPUT Clause](https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql)
|
||||
or add a `select ID = convert(bigint, SCOPE_IDENTITY());` to the end of your
|
||||
query (ref [SCOPE_IDENTITY](https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql)).
|
||||
This will ensure you are getting the correct ID and will prevent a network round trip.
|
||||
* [NewConnector](https://godoc.org/github.com/microsoft/go-mssqldb#NewConnector)
|
||||
may be used with [OpenDB](https://golang.org/pkg/database/sql/#OpenDB).
|
||||
* [Connector.SessionInitSQL](https://godoc.org/github.com/microsoft/go-mssqldb#Connector.SessionInitSQL)
|
||||
may be set to set any driver specific session settings after the session
|
||||
has been reset. If empty the session will still be reset but use the database
|
||||
defaults in Go1.10+.
|
||||
|
||||
## Features
|
||||
|
||||
* Can be used with SQL Server 2005 or newer
|
||||
* Can be used with Microsoft Azure SQL Database
|
||||
* Can be used on all go supported platforms (e.g. Linux, Mac OS X and Windows)
|
||||
* Supports new date/time types: date, time, datetime2, datetimeoffset
|
||||
* Supports string parameters longer than 8000 characters
|
||||
* Supports encryption using SSL/TLS
|
||||
* Supports SQL Server and Windows Authentication
|
||||
* Supports Single-Sign-On on Windows
|
||||
* Supports connections to AlwaysOn Availability Group listeners, including re-direction to read-only replicas.
|
||||
* Supports query notifications
|
||||
* Supports Kerberos Authentication
|
||||
* Supports handling the `uniqueidentifier` data type with the `UniqueIdentifier` and `NullUniqueIdentifier` go types
|
||||
* Pluggable Dialer implementations through `msdsn.ProtocolParsers` and `msdsn.ProtocolDialers`
|
||||
* A `namedpipe` package to support connections using named pipes (np:) on Windows
|
||||
* A `sharedmemory` package to support connections using shared memory (lpc:) on Windows
|
||||
* Dedicated Administrator Connection (DAC) is supported using `admin` protocol
|
||||
* Always Encrypted
|
||||
- `MSSQL_CERTIFICATE_STORE` provider on Windows
|
||||
- `pfx` provider on Linux and Windows
|
||||
|
||||
## Tests
|
||||
|
||||
`go test` is used for testing. A running instance of MSSQL server is required.
|
||||
Environment variables are used to pass login information.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
env SQLSERVER_DSN=sqlserver://user:pass@hostname/instance?database=test1 go test
|
||||
```
|
||||
|
||||
`AZURESERVER_DSN` environment variable provides the connection string for Azure Active Directory-based authentication. If it's not set the AAD test will be skipped.
|
||||
|
||||
## Deprecated
|
||||
|
||||
These features still exist in the driver, but they are are deprecated.
|
||||
|
||||
### Query Parameter Token Replace (driver "mssql")
|
||||
|
||||
If you use the driver name "mssql" (rather then "sqlserver") the SQL text
|
||||
will be loosly parsed and an attempt to extract identifiers using one of
|
||||
|
||||
* ?
|
||||
* ?nnn
|
||||
* :nnn
|
||||
* $nnn
|
||||
|
||||
will be used. This is not recommended with SQL Server.
|
||||
There is at least one existing `won't fix` issue with the query parsing.
|
||||
|
||||
Use the native "@Name" parameters instead with the "sqlserver" driver name.
|
||||
|
||||
## Known Issues
|
||||
|
||||
* SQL Server 2008 and 2008 R2 engine cannot handle login records when SSL encryption is not disabled.
|
||||
To fix SQL Server 2008 R2 issue, install SQL Server 2008 R2 Service Pack 2.
|
||||
To fix SQL Server 2008 issue, install Microsoft SQL Server 2008 Service Pack 3 and Cumulative update package 3 for SQL Server 2008 SP3.
|
||||
More information: <http://support.microsoft.com/kb/2653857>
|
||||
|
||||
* Bulk copy does not yet support encrypting column values using Always Encrypted. Tracked in [#127](https://github.com/microsoft/go-mssqldb/issues/127)
|
||||
|
||||
# Contributing
|
||||
This project is a fork of [https://github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) and welcomes new and previous contributors. For more informaton on contributing to this project, please see [Contributing](./CONTRIBUTING.md).
|
||||
|
||||
For more information on the roadmap for go-mssqldb, [project plans](https://github.com/microsoft/go-mssqldb/projects) are available for viewing and discussion.
|
||||
|
||||
|
||||
# Microsoft Open Source Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
|
||||
Resources:
|
||||
|
||||
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
||||
41
vendor/github.com/microsoft/go-mssqldb/SECURITY.md
generated
vendored
Normal file
41
vendor/github.com/microsoft/go-mssqldb/SECURITY.md
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
||||
32
vendor/github.com/microsoft/go-mssqldb/accesstokenconnector.go
generated
vendored
Normal file
32
vendor/github.com/microsoft/go-mssqldb/accesstokenconnector.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
//go:build go1.10
|
||||
// +build go1.10
|
||||
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// NewAccessTokenConnector creates a new connector from a DSN and a token provider.
|
||||
// The token provider func will be called when a new connection is requested and should return a valid access token.
|
||||
// The returned connector may be used with sql.OpenDB.
|
||||
func NewAccessTokenConnector(dsn string, tokenProvider func() (string, error)) (driver.Connector, error) {
|
||||
if tokenProvider == nil {
|
||||
return nil, errors.New("mssql: tokenProvider cannot be nil")
|
||||
}
|
||||
|
||||
conn, err := NewConnector(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn.fedAuthRequired = true
|
||||
conn.fedAuthLibrary = FedAuthLibrarySecurityToken
|
||||
conn.securityTokenProvider = func(ctx context.Context) (string, error) {
|
||||
return tokenProvider()
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
39
vendor/github.com/microsoft/go-mssqldb/aecmk/error.go
generated
vendored
Normal file
39
vendor/github.com/microsoft/go-mssqldb/aecmk/error.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package aecmk
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Operation specifies the action that returned an error
|
||||
type Operation int
|
||||
|
||||
const (
|
||||
Decryption Operation = iota
|
||||
Encryption
|
||||
Validation
|
||||
)
|
||||
|
||||
// Error is the type of all errors returned by key encryption providers
|
||||
type Error struct {
|
||||
Operation Operation
|
||||
err error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
func (e *Error) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func NewError(operation Operation, msg string, err error) error {
|
||||
return &Error{
|
||||
Operation: operation,
|
||||
msg: msg,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func KeyPathNotAllowed(path string, operation Operation) error {
|
||||
return NewError(operation, fmt.Sprintf("Key path not allowed: %s", path), nil)
|
||||
}
|
||||
115
vendor/github.com/microsoft/go-mssqldb/aecmk/keyprovider.go
generated
vendored
Normal file
115
vendor/github.com/microsoft/go-mssqldb/aecmk/keyprovider.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
package aecmk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
CertificateStoreKeyProvider = "MSSQL_CERTIFICATE_STORE"
|
||||
CspKeyProvider = "MSSQL_CSP_PROVIDER"
|
||||
CngKeyProvider = "MSSQL_CNG_STORE"
|
||||
AzureKeyVaultKeyProvider = "AZURE_KEY_VAULT"
|
||||
JavaKeyProvider = "MSSQL_JAVA_KEYSTORE"
|
||||
KeyEncryptionAlgorithm = "RSA_OAEP"
|
||||
)
|
||||
|
||||
// ColumnEncryptionKeyLifetime is the default lifetime of decrypted Column Encryption Keys in the global cache.
|
||||
// The default is 2 hours
|
||||
var ColumnEncryptionKeyLifetime time.Duration = 2 * time.Hour
|
||||
|
||||
type cekCacheEntry struct {
|
||||
Expiry time.Time
|
||||
Key []byte
|
||||
}
|
||||
|
||||
type cekCache map[string]cekCacheEntry
|
||||
|
||||
type CekProvider struct {
|
||||
Provider ColumnEncryptionKeyProvider
|
||||
decryptedKeys cekCache
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewCekProvider(provider ColumnEncryptionKeyProvider) *CekProvider {
|
||||
return &CekProvider{Provider: provider, decryptedKeys: make(cekCache), mutex: sync.Mutex{}}
|
||||
}
|
||||
|
||||
func (cp *CekProvider) GetDecryptedKey(ctx context.Context, keyPath string, encryptedBytes []byte) (decryptedKey []byte, err error) {
|
||||
cp.mutex.Lock()
|
||||
ev, cachedKey := cp.decryptedKeys[keyPath]
|
||||
if cachedKey {
|
||||
if ev.Expiry.Before(time.Now()) {
|
||||
delete(cp.decryptedKeys, keyPath)
|
||||
cachedKey = false
|
||||
} else {
|
||||
decryptedKey = ev.Key
|
||||
}
|
||||
}
|
||||
// decrypting a key can take a while, so let multiple callers race
|
||||
// Key providers can choose to optimize their own concurrency.
|
||||
// For example - there's probably minimal value in serializing access to a local certificate,
|
||||
// but there'd be high value in having a queue of waiters for decrypting a key stored in the cloud.
|
||||
cp.mutex.Unlock()
|
||||
if !cachedKey {
|
||||
decryptedKey, err = cp.Provider.DecryptColumnEncryptionKey(ctx, keyPath, KeyEncryptionAlgorithm, encryptedBytes)
|
||||
}
|
||||
if err == nil && !cachedKey {
|
||||
duration := cp.Provider.KeyLifetime()
|
||||
if duration == nil {
|
||||
duration = &ColumnEncryptionKeyLifetime
|
||||
}
|
||||
expiry := time.Now().Add(*duration)
|
||||
cp.mutex.Lock()
|
||||
cp.decryptedKeys[keyPath] = cekCacheEntry{Expiry: expiry, Key: decryptedKey}
|
||||
cp.mutex.Unlock()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// no synchronization on this map. Providers register during init.
|
||||
type ColumnEncryptionKeyProviderMap map[string]*CekProvider
|
||||
|
||||
var globalCekProviderFactoryMap = ColumnEncryptionKeyProviderMap{}
|
||||
|
||||
// ColumnEncryptionKeyProvider is the interface for decrypting and encrypting column encryption keys.
|
||||
// It is similar to .Net https://learn.microsoft.com/dotnet/api/microsoft.data.sqlclient.sqlcolumnencryptionkeystoreprovider.
|
||||
type ColumnEncryptionKeyProvider interface {
|
||||
// DecryptColumnEncryptionKey decrypts the specified encrypted value of a column encryption key.
|
||||
// The encrypted value is expected to be encrypted using the column master key with the specified key path and using the specified algorithm.
|
||||
DecryptColumnEncryptionKey(ctx context.Context, masterKeyPath string, encryptionAlgorithm string, encryptedCek []byte) ([]byte, error)
|
||||
// EncryptColumnEncryptionKey encrypts a column encryption key using the column master key with the specified key path and using the specified algorithm.
|
||||
EncryptColumnEncryptionKey(ctx context.Context, masterKeyPath string, encryptionAlgorithm string, cek []byte) ([]byte, error)
|
||||
// SignColumnMasterKeyMetadata digitally signs the column master key metadata with the column master key
|
||||
// referenced by the masterKeyPath parameter. The input values used to generate the signature should be the
|
||||
// specified values of the masterKeyPath and allowEnclaveComputations parameters. May return an empty slice if not supported.
|
||||
SignColumnMasterKeyMetadata(ctx context.Context, masterKeyPath string, allowEnclaveComputations bool) ([]byte, error)
|
||||
// VerifyColumnMasterKeyMetadata verifies the specified signature is valid for the column master key
|
||||
// with the specified key path and the specified enclave behavior. Return nil if not supported.
|
||||
VerifyColumnMasterKeyMetadata(ctx context.Context, masterKeyPath string, allowEnclaveComputations bool) (*bool, error)
|
||||
// KeyLifetime is an optional Duration. Keys fetched by this provider will be discarded after their lifetime expires.
|
||||
// If it returns nil, the keys will expire based on the value of ColumnEncryptionKeyLifetime.
|
||||
// If it returns zero, the keys will not be cached.
|
||||
KeyLifetime() *time.Duration
|
||||
}
|
||||
|
||||
// RegisterCekProvider adds the named provider to the global provider list
|
||||
func RegisterCekProvider(name string, provider ColumnEncryptionKeyProvider) error {
|
||||
_, ok := globalCekProviderFactoryMap[name]
|
||||
if ok {
|
||||
return fmt.Errorf("CEK provider %s is already registered", name)
|
||||
}
|
||||
globalCekProviderFactoryMap[name] = &CekProvider{Provider: provider, decryptedKeys: cekCache{}, mutex: sync.Mutex{}}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetGlobalCekProviders enumerates all globally registered providers
|
||||
func GetGlobalCekProviders() (providers ColumnEncryptionKeyProviderMap) {
|
||||
providers = make(ColumnEncryptionKeyProviderMap)
|
||||
for i, p := range globalCekProviderFactoryMap {
|
||||
providers[i] = p
|
||||
}
|
||||
return
|
||||
}
|
||||
71
vendor/github.com/microsoft/go-mssqldb/appveyor.yml
generated
vendored
Normal file
71
vendor/github.com/microsoft/go-mssqldb/appveyor.yml
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
version: 1.0.{build}
|
||||
|
||||
image:
|
||||
- Visual Studio 2015
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\microsoft\go-mssqldb
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
HOST: localhost
|
||||
SQLUSER: sa
|
||||
SQLPASSWORD: Password12!
|
||||
DATABASE: test
|
||||
GOVERSION: 124
|
||||
COLUMNENCRYPTION:
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
|
||||
TAGS:
|
||||
matrix:
|
||||
- SQLINSTANCE: SQL2017
|
||||
- GOVERSION: 124
|
||||
SQLINSTANCE: SQL2017
|
||||
- GOVERSION: 124
|
||||
SQLINSTANCE: SQL2019
|
||||
COLUMNENCRYPTION: 1
|
||||
# Cover 32bit and named pipes protocol
|
||||
- GOVERSION: 123-x86
|
||||
SQLINSTANCE: SQL2017
|
||||
GOARCH: 386
|
||||
PROTOCOL: np
|
||||
TAGS: -tags np
|
||||
# Cover SSPI and lpc protocol
|
||||
- GOVERSION: 124
|
||||
SQLINSTANCE: SQL2019
|
||||
PROTOCOL: lpc
|
||||
TAGS: -tags sm
|
||||
SQLUSER:
|
||||
SQLPASSWORD:
|
||||
install:
|
||||
- set GOROOT=c:\go%GOVERSION%
|
||||
- set PATH=%GOPATH%\bin;%GOROOT%\bin;%PATH%
|
||||
- go version
|
||||
- go env
|
||||
|
||||
build_script:
|
||||
- go build
|
||||
|
||||
before_test:
|
||||
# setup SQL Server
|
||||
- ps: |
|
||||
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null
|
||||
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | Out-Null
|
||||
$smo = 'Microsoft.SqlServer.Management.Smo.'
|
||||
$wmi = new-object ($smo + 'Wmi.ManagedComputer')
|
||||
$serverName = $env:COMPUTERNAME
|
||||
$instanceName = $env:SQLINSTANCE
|
||||
# Enable named pipes
|
||||
$uri = "ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Np']"
|
||||
$Np = $wmi.GetSmoObject($uri)
|
||||
$Np.IsEnabled = $true
|
||||
$Np.Alter()
|
||||
Start-Service "SQLBrowser"
|
||||
Start-Service "MSSQL`$$instanceName"
|
||||
Start-Sleep -Seconds 10
|
||||
- sqlcmd -S "(local)\%SQLINSTANCE%" -Q "Use [master]; CREATE DATABASE test;"
|
||||
- sqlcmd -S "np:.\%SQLINSTANCE%" -h -1 -Q "set nocount on; Select @@version"
|
||||
- pip install codecov
|
||||
|
||||
test_script:
|
||||
- go test -coverprofile=coverage.txt -covermode=atomic %TAGS%
|
||||
- codecov -f coverage.txt
|
||||
16
vendor/github.com/microsoft/go-mssqldb/auth_unix.go
generated
vendored
Normal file
16
vendor/github.com/microsoft/go-mssqldb/auth_unix.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"github.com/microsoft/go-mssqldb/integratedauth"
|
||||
// nolint importing the ntlm package causes it to be registered as an available authentication provider
|
||||
_ "github.com/microsoft/go-mssqldb/integratedauth/ntlm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// we set the default authentication provider name here, rather than within each imported package,
|
||||
// to force a known default. Go will order execution of init() calls but it is better to be explicit.
|
||||
integratedauth.DefaultProviderName = "ntlm"
|
||||
}
|
||||
19
vendor/github.com/microsoft/go-mssqldb/auth_windows.go
generated
vendored
Normal file
19
vendor/github.com/microsoft/go-mssqldb/auth_windows.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"github.com/microsoft/go-mssqldb/integratedauth"
|
||||
|
||||
// nolint importing the ntlm package causes it to be registered as an available authentication provider
|
||||
_ "github.com/microsoft/go-mssqldb/integratedauth/ntlm"
|
||||
// nolint importing the winsspi package causes it to be registered as an available authentication provider
|
||||
_ "github.com/microsoft/go-mssqldb/integratedauth/winsspi"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// we set the default authentication provider name here, rather than within each imported package,
|
||||
// to force a known default. Go will order execution of init() calls but it is better to be explicit.
|
||||
integratedauth.DefaultProviderName = "winsspi"
|
||||
}
|
||||
315
vendor/github.com/microsoft/go-mssqldb/buf.go
generated
vendored
Normal file
315
vendor/github.com/microsoft/go-mssqldb/buf.go
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type packetType uint8
|
||||
|
||||
type header struct {
|
||||
PacketType packetType
|
||||
Status uint8
|
||||
Size uint16
|
||||
Spid uint16
|
||||
PacketNo uint8
|
||||
Pad uint8
|
||||
}
|
||||
|
||||
// bufpool provides buffers which are used for reading and writing in the tdsBuffer instances
|
||||
var bufpool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
b := make([]byte, 1<<16)
|
||||
// If the return value is not a pointer, any conversion from interface{} will
|
||||
// involve an allocation.
|
||||
return &b
|
||||
},
|
||||
}
|
||||
|
||||
// tdsBuffer reads and writes TDS packets of data to the transport.
|
||||
// The write and read buffers are separate to make sending attn signals
|
||||
// possible without locks. Currently attn signals are only sent during
|
||||
// reads, not writes.
|
||||
type tdsBuffer struct {
|
||||
transport io.ReadWriteCloser
|
||||
|
||||
packetSize int
|
||||
|
||||
// bufClose is responsible for returning the buffer back to the pool
|
||||
bufClose func()
|
||||
|
||||
// Write fields.
|
||||
wbuf []byte
|
||||
wpos int
|
||||
wPacketSeq byte
|
||||
wPacketType packetType
|
||||
|
||||
// Read fields.
|
||||
rbuf []byte
|
||||
rpos int
|
||||
rsize int
|
||||
final bool
|
||||
rPacketType packetType
|
||||
|
||||
// afterFirst is assigned to right after tdsBuffer is created and
|
||||
// before the first use. It is executed after the first packet is
|
||||
// written and then removed.
|
||||
afterFirst func()
|
||||
}
|
||||
|
||||
func newTdsBuffer(bufsize uint16, transport io.ReadWriteCloser) *tdsBuffer {
|
||||
|
||||
// pull an existing buf if one is available or get and add a new buf to the bufpool
|
||||
buf := bufpool.Get().(*[]byte)
|
||||
|
||||
return &tdsBuffer{
|
||||
packetSize: int(bufsize),
|
||||
wbuf: (*buf)[:1<<15],
|
||||
rbuf: (*buf)[1<<15:],
|
||||
bufClose: func() { bufpool.Put(buf) },
|
||||
rpos: 8,
|
||||
transport: transport,
|
||||
}
|
||||
}
|
||||
|
||||
func (rw *tdsBuffer) ResizeBuffer(packetSize int) {
|
||||
rw.packetSize = packetSize
|
||||
}
|
||||
|
||||
func (w *tdsBuffer) PackageSize() int {
|
||||
return w.packetSize
|
||||
}
|
||||
|
||||
func (w *tdsBuffer) flush() (err error) {
|
||||
// Write packet size.
|
||||
w.wbuf[0] = byte(w.wPacketType)
|
||||
binary.BigEndian.PutUint16(w.wbuf[2:], uint16(w.wpos))
|
||||
w.wbuf[6] = w.wPacketSeq
|
||||
|
||||
// Write packet into underlying transport.
|
||||
if _, err = w.transport.Write(w.wbuf[:w.wpos]); err != nil {
|
||||
return err
|
||||
}
|
||||
// It is possible to create a whole new buffer after a flush.
|
||||
// Useful for debugging. Normally reuse the buffer.
|
||||
// w.wbuf = make([]byte, 1<<16)
|
||||
|
||||
// Execute afterFirst hook if it is set.
|
||||
if w.afterFirst != nil {
|
||||
w.afterFirst()
|
||||
w.afterFirst = nil
|
||||
}
|
||||
|
||||
w.wpos = 8
|
||||
w.wPacketSeq++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *tdsBuffer) Write(p []byte) (total int, err error) {
|
||||
for {
|
||||
copied := copy(w.wbuf[w.wpos:w.packetSize], p)
|
||||
w.wpos += copied
|
||||
total += copied
|
||||
if copied == len(p) {
|
||||
return
|
||||
}
|
||||
if err = w.flush(); err != nil {
|
||||
return
|
||||
}
|
||||
p = p[copied:]
|
||||
}
|
||||
}
|
||||
|
||||
func (w *tdsBuffer) WriteByte(b byte) error {
|
||||
if int(w.wpos) == len(w.wbuf) || w.wpos == w.packetSize {
|
||||
if err := w.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.wbuf[w.wpos] = b
|
||||
w.wpos += 1
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *tdsBuffer) BeginPacket(packetType packetType, resetSession bool) {
|
||||
status := byte(0)
|
||||
if resetSession {
|
||||
switch packetType {
|
||||
// Reset session can only be set on the following packet types.
|
||||
case packSQLBatch, packRPCRequest, packTransMgrReq:
|
||||
status = 0x8
|
||||
}
|
||||
}
|
||||
w.wbuf[1] = status // Packet is incomplete. This byte is set again in FinishPacket.
|
||||
w.wpos = 8
|
||||
w.wPacketSeq = 1
|
||||
w.wPacketType = packetType
|
||||
}
|
||||
|
||||
func (w *tdsBuffer) FinishPacket() error {
|
||||
w.wbuf[1] |= 1 // Mark this as the last packet in the message.
|
||||
return w.flush()
|
||||
}
|
||||
|
||||
var headerSize = binary.Size(header{})
|
||||
|
||||
func (r *tdsBuffer) readNextPacket() error {
|
||||
buf := r.rbuf[:headerSize]
|
||||
_, err := io.ReadFull(r.transport, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := header{
|
||||
PacketType: packetType(buf[0]),
|
||||
Status: buf[1],
|
||||
Size: binary.BigEndian.Uint16(buf[2:4]),
|
||||
Spid: binary.BigEndian.Uint16(buf[4:6]),
|
||||
PacketNo: buf[6],
|
||||
Pad: buf[7],
|
||||
}
|
||||
if int(h.Size) > r.packetSize {
|
||||
return errors.New("invalid packet size, it is longer than buffer size")
|
||||
}
|
||||
if headerSize > int(h.Size) {
|
||||
return errors.New("invalid packet size, it is shorter than header size")
|
||||
}
|
||||
_, err = io.ReadFull(r.transport, r.rbuf[headerSize:h.Size])
|
||||
//s := base64.StdEncoding.EncodeToString(r.rbuf[headerSize:h.Size])
|
||||
//fmt.Print(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.rpos = headerSize
|
||||
r.rsize = int(h.Size)
|
||||
r.final = h.Status != 0
|
||||
r.rPacketType = h.PacketType
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) BeginRead() (packetType, error) {
|
||||
err := r.readNextPacket()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return r.rPacketType, nil
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) ReadByte() (res byte, err error) {
|
||||
if r.rpos == r.rsize {
|
||||
if r.final {
|
||||
return 0, io.EOF
|
||||
}
|
||||
err = r.readNextPacket()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
res = r.rbuf[r.rpos]
|
||||
r.rpos++
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) byte() byte {
|
||||
b, err := r.ReadByte()
|
||||
if err != nil {
|
||||
badStreamPanic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) ReadFull(buf []byte) {
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
badStreamPanic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) uint64() uint64 {
|
||||
// have we got enough room in the buffer to read 8 bytes, if not, do a ReadFull, else read directly from r.rbuf
|
||||
if r.rpos+7 >= r.rsize {
|
||||
var buf [8]byte
|
||||
r.ReadFull(buf[:])
|
||||
|
||||
return uint64(buf[0]) | uint64(buf[1])<<8 | uint64(buf[2])<<16 | uint64(buf[3])<<24 |
|
||||
uint64(buf[4])<<32 | uint64(buf[5])<<40 | uint64(buf[6])<<48 | uint64(buf[7])<<56
|
||||
}
|
||||
|
||||
res := uint64(r.rbuf[r.rpos]) | uint64(r.rbuf[r.rpos+1])<<8 | uint64(r.rbuf[r.rpos+2])<<16 | uint64(r.rbuf[r.rpos+3])<<24 |
|
||||
uint64(r.rbuf[r.rpos+4])<<32 | uint64(r.rbuf[r.rpos+5])<<40 | uint64(r.rbuf[r.rpos+6])<<48 | uint64(r.rbuf[r.rpos+7])<<56
|
||||
|
||||
r.rpos += 8
|
||||
return res
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) int32() int32 {
|
||||
return int32(r.uint32())
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) uint32() uint32 {
|
||||
// have we got enough room in the buffer to read 4 bytes, if not, do a ReadFull, else read directly from r.rbuf
|
||||
if r.rpos+3 >= r.rsize {
|
||||
var buf [4]byte
|
||||
r.ReadFull(buf[:])
|
||||
return uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
|
||||
}
|
||||
|
||||
res := uint32(r.rbuf[r.rpos]) | uint32(r.rbuf[r.rpos+1])<<8 | uint32(r.rbuf[r.rpos+2])<<16 | uint32(r.rbuf[r.rpos+3])<<24
|
||||
r.rpos += 4
|
||||
return res
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) uint16() uint16 {
|
||||
// have we got enough room in the buffer to read 2 bytes, if not, do a ReadFull, else read directly from r.rbuf
|
||||
if r.rpos+1 >= r.rsize {
|
||||
var buf [2]byte
|
||||
r.ReadFull(buf[:])
|
||||
return uint16(buf[0]) | uint16(buf[1])<<8
|
||||
}
|
||||
|
||||
res := uint16(r.rbuf[r.rpos]) | uint16(r.rbuf[r.rpos+1])<<8
|
||||
r.rpos += 2
|
||||
return res
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) BVarChar() string {
|
||||
return readBVarCharOrPanic(r)
|
||||
}
|
||||
|
||||
func readBVarCharOrPanic(r io.Reader) string {
|
||||
s, err := readBVarChar(r)
|
||||
if err != nil {
|
||||
badStreamPanic(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func readUsVarCharOrPanic(r io.Reader) string {
|
||||
s, err := readUsVarChar(r)
|
||||
if err != nil {
|
||||
badStreamPanic(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) UsVarChar() string {
|
||||
return readUsVarCharOrPanic(r)
|
||||
}
|
||||
|
||||
func (r *tdsBuffer) Read(buf []byte) (copied int, err error) {
|
||||
copied = 0
|
||||
err = nil
|
||||
if r.rpos == r.rsize {
|
||||
if r.final {
|
||||
return 0, io.EOF
|
||||
}
|
||||
err = r.readNextPacket()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
copied = copy(buf, r.rbuf[r.rpos:r.rsize])
|
||||
r.rpos += copied
|
||||
return
|
||||
}
|
||||
693
vendor/github.com/microsoft/go-mssqldb/bulkcopy.go
generated
vendored
Normal file
693
vendor/github.com/microsoft/go-mssqldb/bulkcopy.go
generated
vendored
Normal file
@@ -0,0 +1,693 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/microsoft/go-mssqldb/internal/decimal"
|
||||
"github.com/microsoft/go-mssqldb/msdsn"
|
||||
shopspring "github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
type Bulk struct {
|
||||
// ctx is used only for AddRow and Done methods.
|
||||
// This could be removed if AddRow and Done accepted
|
||||
// a ctx field as well, which is available with the
|
||||
// database/sql call.
|
||||
ctx context.Context
|
||||
|
||||
cn *Conn
|
||||
metadata []columnStruct
|
||||
bulkColumns []columnStruct
|
||||
columnsName []string
|
||||
tablename string
|
||||
numRows int
|
||||
|
||||
headerSent bool
|
||||
Options BulkOptions
|
||||
Debug bool
|
||||
}
|
||||
type BulkOptions struct {
|
||||
CheckConstraints bool
|
||||
FireTriggers bool
|
||||
KeepNulls bool
|
||||
KilobytesPerBatch int
|
||||
RowsPerBatch int
|
||||
Order []string
|
||||
Tablock bool
|
||||
}
|
||||
|
||||
type DataValue interface{}
|
||||
|
||||
const (
|
||||
sqlDateFormat = "2006-01-02"
|
||||
sqlDateTimeFormat = "2006-01-02 15:04:05.999999999Z07:00"
|
||||
sqlTimeFormat = "15:04:05.9999999"
|
||||
)
|
||||
|
||||
func (c *Conn) CreateBulk(table string, columns []string) (_ *Bulk) {
|
||||
b := Bulk{ctx: context.Background(), cn: c, tablename: table, headerSent: false, columnsName: columns}
|
||||
b.Debug = false
|
||||
return &b
|
||||
}
|
||||
|
||||
func (c *Conn) CreateBulkContext(ctx context.Context, table string, columns []string) (_ *Bulk) {
|
||||
b := Bulk{ctx: ctx, cn: c, tablename: table, headerSent: false, columnsName: columns}
|
||||
b.Debug = false
|
||||
return &b
|
||||
}
|
||||
|
||||
func (b *Bulk) sendBulkCommand(ctx context.Context) (err error) {
|
||||
//get table columns info
|
||||
err = b.getMetadata(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//match the columns
|
||||
for _, colname := range b.columnsName {
|
||||
var bulkCol *columnStruct
|
||||
|
||||
for _, m := range b.metadata {
|
||||
if m.ColName == colname {
|
||||
bulkCol = &m
|
||||
break
|
||||
}
|
||||
}
|
||||
if bulkCol != nil {
|
||||
|
||||
if bulkCol.ti.TypeId == typeUdt {
|
||||
//send udt as binary
|
||||
bulkCol.ti.TypeId = typeBigVarBin
|
||||
}
|
||||
b.bulkColumns = append(b.bulkColumns, *bulkCol)
|
||||
b.dlogf(ctx, "Adding column %s %s %#x", colname, bulkCol.ColName, bulkCol.ti.TypeId)
|
||||
} else {
|
||||
return fmt.Errorf("column %s does not exist in destination table %s", colname, b.tablename)
|
||||
}
|
||||
}
|
||||
|
||||
//create the bulk command
|
||||
|
||||
//columns definitions
|
||||
var col_defs bytes.Buffer
|
||||
for i, col := range b.bulkColumns {
|
||||
if i != 0 {
|
||||
col_defs.WriteString(", ")
|
||||
}
|
||||
col_defs.WriteString("[" + col.ColName + "] " + makeDecl(col.ti))
|
||||
}
|
||||
|
||||
//options
|
||||
var with_opts []string
|
||||
|
||||
if b.Options.CheckConstraints {
|
||||
with_opts = append(with_opts, "CHECK_CONSTRAINTS")
|
||||
}
|
||||
if b.Options.FireTriggers {
|
||||
with_opts = append(with_opts, "FIRE_TRIGGERS")
|
||||
}
|
||||
if b.Options.KeepNulls {
|
||||
with_opts = append(with_opts, "KEEP_NULLS")
|
||||
}
|
||||
if b.Options.KilobytesPerBatch > 0 {
|
||||
with_opts = append(with_opts, fmt.Sprintf("KILOBYTES_PER_BATCH = %d", b.Options.KilobytesPerBatch))
|
||||
}
|
||||
if b.Options.RowsPerBatch > 0 {
|
||||
with_opts = append(with_opts, fmt.Sprintf("ROWS_PER_BATCH = %d", b.Options.RowsPerBatch))
|
||||
}
|
||||
if len(b.Options.Order) > 0 {
|
||||
with_opts = append(with_opts, fmt.Sprintf("ORDER(%s)", strings.Join(b.Options.Order, ",")))
|
||||
}
|
||||
if b.Options.Tablock {
|
||||
with_opts = append(with_opts, "TABLOCK")
|
||||
}
|
||||
var with_part string
|
||||
if len(with_opts) > 0 {
|
||||
with_part = fmt.Sprintf("WITH (%s)", strings.Join(with_opts, ","))
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("INSERT BULK %s (%s) %s", b.tablename, col_defs.String(), with_part)
|
||||
|
||||
stmt, err := b.cn.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Prepare failed: %s", err.Error())
|
||||
}
|
||||
b.dlogf(ctx, "%s", query)
|
||||
|
||||
_, err = stmt.(*Stmt).ExecContext(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.headerSent = true
|
||||
|
||||
var buf = b.cn.sess.buf
|
||||
buf.BeginPacket(packBulkLoadBCP, false)
|
||||
|
||||
// Send the columns metadata.
|
||||
columnMetadata := b.createColMetadata()
|
||||
_, err = buf.Write(columnMetadata)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddRow immediately writes the row to the destination table.
|
||||
// The arguments are the row values in the order they were specified.
|
||||
func (b *Bulk) AddRow(row []interface{}) (err error) {
|
||||
if !b.headerSent {
|
||||
err = b.sendBulkCommand(b.ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(row) != len(b.bulkColumns) {
|
||||
return fmt.Errorf("row does not have the same number of columns than the destination table %d %d",
|
||||
len(row), len(b.bulkColumns))
|
||||
}
|
||||
|
||||
bytes, err := b.makeRowData(row)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = b.cn.sess.buf.Write(bytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b.numRows = b.numRows + 1
|
||||
return
|
||||
}
|
||||
|
||||
func (b *Bulk) makeRowData(row []interface{}) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(tokenRow))
|
||||
|
||||
var logcol bytes.Buffer
|
||||
for i, col := range b.bulkColumns {
|
||||
|
||||
if b.Debug {
|
||||
logcol.WriteString(fmt.Sprintf(" col[%d]='%v' ", i, row[i]))
|
||||
}
|
||||
param, err := b.makeParam(row[i], col)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bulkcopy: %s", err.Error())
|
||||
}
|
||||
|
||||
if col.ti.Writer == nil {
|
||||
return nil, fmt.Errorf("no writer for column: %s, TypeId: %#x",
|
||||
col.ColName, col.ti.TypeId)
|
||||
}
|
||||
err = col.ti.Writer(buf, param.ti, param.buffer, b.cn.sess.encoding)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bulkcopy: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
b.dlogf(b.ctx, "row[%d] %s", b.numRows, logcol.String())
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (b *Bulk) Done() (rowcount int64, err error) {
|
||||
if !b.headerSent {
|
||||
//no rows had been sent
|
||||
return 0, nil
|
||||
}
|
||||
var buf = b.cn.sess.buf
|
||||
buf.WriteByte(byte(tokenDone))
|
||||
|
||||
binary.Write(buf, binary.LittleEndian, uint16(doneFinal))
|
||||
binary.Write(buf, binary.LittleEndian, uint16(0)) // curcmd
|
||||
|
||||
if b.cn.sess.loginAck.TDSVersion >= verTDS72 {
|
||||
binary.Write(buf, binary.LittleEndian, uint64(0)) //rowcount 0
|
||||
} else {
|
||||
binary.Write(buf, binary.LittleEndian, uint32(0)) //rowcount 0
|
||||
}
|
||||
|
||||
buf.FinishPacket()
|
||||
|
||||
reader := startReading(b.cn.sess, b.ctx, outputs{})
|
||||
err = reader.iterateResponse()
|
||||
if err != nil {
|
||||
return 0, b.cn.checkBadConn(b.ctx, err, false)
|
||||
}
|
||||
|
||||
return reader.rowCount, nil
|
||||
}
|
||||
|
||||
func (b *Bulk) createColMetadata() []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte(byte(tokenColMetadata)) // token
|
||||
binary.Write(buf, binary.LittleEndian, uint16(len(b.bulkColumns))) // column count
|
||||
|
||||
// TODO: Write a valid CEK table if any parameters have cekTableEntry values
|
||||
if b.cn.sess.alwaysEncrypted {
|
||||
binary.Write(buf, binary.LittleEndian, uint16(0))
|
||||
}
|
||||
for i, col := range b.bulkColumns {
|
||||
|
||||
if b.cn.sess.loginAck.TDSVersion >= verTDS72 {
|
||||
binary.Write(buf, binary.LittleEndian, uint32(col.UserType)) // usertype, always 0?
|
||||
} else {
|
||||
binary.Write(buf, binary.LittleEndian, uint16(col.UserType))
|
||||
}
|
||||
binary.Write(buf, binary.LittleEndian, uint16(col.Flags))
|
||||
|
||||
writeTypeInfo(buf, &b.bulkColumns[i].ti, false, b.cn.sess.encoding)
|
||||
|
||||
if col.ti.TypeId == typeNText ||
|
||||
col.ti.TypeId == typeText ||
|
||||
col.ti.TypeId == typeImage {
|
||||
|
||||
tablename_ucs2 := str2ucs2(b.tablename)
|
||||
binary.Write(buf, binary.LittleEndian, uint16(len(tablename_ucs2)/2))
|
||||
buf.Write(tablename_ucs2)
|
||||
}
|
||||
colname_ucs2 := str2ucs2(col.ColName)
|
||||
buf.WriteByte(uint8(len(colname_ucs2) / 2))
|
||||
buf.Write(colname_ucs2)
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (b *Bulk) getMetadata(ctx context.Context) (err error) {
|
||||
stmt, err := b.cn.prepareContext(ctx, "SET FMTONLY ON")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = stmt.ExecContext(ctx, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure we always SET FMTONLY OFF even if the next statement fails
|
||||
resetFmtonly := true
|
||||
defer func() {
|
||||
if !resetFmtonly {
|
||||
return
|
||||
}
|
||||
|
||||
// Don't let resetErr shadow the "real" error, since this should
|
||||
// generally only happen if one of the calls below failed
|
||||
stmt, resetErr := b.cn.prepareContext(ctx, "SET FMTONLY OFF")
|
||||
if resetErr != nil {
|
||||
// This _should_ be infallible as prepareContext doesn't
|
||||
// actually contact the server
|
||||
b.cn.sess.logger.Log(ctx, msdsn.LogErrors, fmt.Sprintf("Could not reset FMTONLY: %v", resetErr))
|
||||
return
|
||||
}
|
||||
// stmt.Close is a no-op so ignore it
|
||||
_, resetErr = stmt.ExecContext(ctx, nil)
|
||||
if resetErr != nil {
|
||||
b.cn.sess.logger.Log(ctx, msdsn.LogErrors, fmt.Sprintf("Could not reset FMTONLY: %v", resetErr))
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// Get columns info.
|
||||
stmt, err = b.cn.prepareContext(ctx, fmt.Sprintf("select * from %s SET FMTONLY OFF", b.tablename))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rows, err := stmt.QueryContext(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get columns info failed: %v", err)
|
||||
}
|
||||
resetFmtonly = false
|
||||
b.metadata = rows.(*Rows).cols
|
||||
|
||||
if b.Debug {
|
||||
for _, col := range b.metadata {
|
||||
b.dlogf(ctx, "col: %s typeId: %#x size: %d scale: %d prec: %d flags: %d lcid: %#x",
|
||||
col.ColName, col.ti.TypeId, col.ti.Size, col.ti.Scale, col.ti.Prec,
|
||||
col.Flags, col.ti.Collation.LcidAndFlags)
|
||||
}
|
||||
}
|
||||
|
||||
return rows.Close()
|
||||
}
|
||||
|
||||
func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) {
|
||||
res.ti.Size = col.ti.Size
|
||||
res.ti.TypeId = col.ti.TypeId
|
||||
loc := getTimezone(b.cn)
|
||||
|
||||
switch valuer := val.(type) {
|
||||
case Money[shopspring.Decimal]:
|
||||
return b.makeParam(valuer.Decimal, col)
|
||||
case Money[shopspring.NullDecimal]:
|
||||
return b.makeParam(valuer.Decimal, col)
|
||||
case driver.Valuer:
|
||||
var e error
|
||||
val, e = driver.DefaultParameterConverter.ConvertValue(valuer)
|
||||
if e != nil {
|
||||
err = e
|
||||
return
|
||||
}
|
||||
if val != nil {
|
||||
return b.makeParam(val, col)
|
||||
}
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
res.ti.Size = 0
|
||||
return
|
||||
}
|
||||
|
||||
switch col.ti.TypeId {
|
||||
|
||||
case typeInt1, typeInt2, typeInt4, typeInt8, typeIntN:
|
||||
var intvalue int64
|
||||
|
||||
switch val := val.(type) {
|
||||
case int:
|
||||
intvalue = int64(val)
|
||||
case int32:
|
||||
intvalue = int64(val)
|
||||
case int64:
|
||||
intvalue = val
|
||||
case float32:
|
||||
intvalue = int64(val)
|
||||
case float64:
|
||||
intvalue = int64(val)
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for int column: %T", val)
|
||||
return
|
||||
}
|
||||
|
||||
res.buffer = make([]byte, res.ti.Size)
|
||||
if col.ti.Size == 1 {
|
||||
res.buffer[0] = byte(intvalue)
|
||||
} else if col.ti.Size == 2 {
|
||||
binary.LittleEndian.PutUint16(res.buffer, uint16(intvalue))
|
||||
} else if col.ti.Size == 4 {
|
||||
binary.LittleEndian.PutUint32(res.buffer, uint32(intvalue))
|
||||
} else if col.ti.Size == 8 {
|
||||
binary.LittleEndian.PutUint64(res.buffer, uint64(intvalue))
|
||||
}
|
||||
case typeFlt4, typeFlt8, typeFltN:
|
||||
var floatvalue float64
|
||||
|
||||
switch val := val.(type) {
|
||||
case float32:
|
||||
floatvalue = float64(val)
|
||||
case float64:
|
||||
floatvalue = val
|
||||
case int:
|
||||
floatvalue = float64(val)
|
||||
case int64:
|
||||
floatvalue = float64(val)
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for float column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
|
||||
if col.ti.Size == 4 {
|
||||
res.buffer = make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(res.buffer, math.Float32bits(float32(floatvalue)))
|
||||
} else if col.ti.Size == 8 {
|
||||
res.buffer = make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(floatvalue))
|
||||
}
|
||||
case typeNVarChar, typeNText, typeNChar:
|
||||
|
||||
switch val := val.(type) {
|
||||
case string:
|
||||
res.buffer = str2ucs2(val)
|
||||
case int64:
|
||||
res.buffer = []byte(strconv.FormatInt(val, 10))
|
||||
case int:
|
||||
res.buffer = []byte(strconv.FormatInt(int64(val), 10))
|
||||
case int8:
|
||||
res.buffer = []byte(strconv.FormatInt(int64(val), 10))
|
||||
case int32:
|
||||
res.buffer = []byte(strconv.FormatInt(int64(val), 10))
|
||||
case int16:
|
||||
res.buffer = []byte(strconv.FormatInt(int64(val), 10))
|
||||
case []byte:
|
||||
res.buffer = val
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for nvarchar column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
res.ti.Size = len(res.buffer)
|
||||
|
||||
case typeVarChar, typeBigVarChar, typeText, typeChar, typeBigChar:
|
||||
switch val := val.(type) {
|
||||
case string:
|
||||
res.buffer = []byte(val)
|
||||
case []byte:
|
||||
res.buffer = val
|
||||
case int:
|
||||
res.buffer = []byte(strconv.FormatInt(int64(val), 10))
|
||||
case int8:
|
||||
res.buffer = []byte(strconv.FormatInt(int64(val), 10))
|
||||
case int16:
|
||||
res.buffer = []byte(strconv.FormatInt(int64(val), 10))
|
||||
case int32:
|
||||
res.buffer = []byte(strconv.FormatInt(int64(val), 10))
|
||||
case int64:
|
||||
res.buffer = []byte(strconv.FormatInt(val, 10))
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for varchar column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
res.ti.Size = len(res.buffer)
|
||||
|
||||
case typeBit, typeBitN:
|
||||
if reflect.TypeOf(val).Kind() != reflect.Bool {
|
||||
err = fmt.Errorf("mssql: invalid type for bit column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
res.ti.TypeId = typeBitN
|
||||
res.ti.Size = 1
|
||||
res.buffer = make([]byte, 1)
|
||||
if val.(bool) {
|
||||
res.buffer[0] = 1
|
||||
}
|
||||
case typeDateTime2N:
|
||||
switch val := val.(type) {
|
||||
case time.Time:
|
||||
res.buffer = encodeDateTime2(val, int(col.ti.Scale))
|
||||
res.ti.Size = len(res.buffer)
|
||||
case string:
|
||||
var t time.Time
|
||||
if t, err = time.Parse(sqlDateTimeFormat, val); err != nil {
|
||||
return res, fmt.Errorf("bulk: unable to convert string to date: %v", err)
|
||||
}
|
||||
res.buffer = encodeDateTime2(t, int(col.ti.Scale))
|
||||
res.ti.Size = len(res.buffer)
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for datetime2 column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
case typeDateTimeOffsetN:
|
||||
switch val := val.(type) {
|
||||
case time.Time:
|
||||
res.buffer = encodeDateTimeOffset(val, int(col.ti.Scale))
|
||||
res.ti.Size = len(res.buffer)
|
||||
case string:
|
||||
var t time.Time
|
||||
if t, err = time.Parse(sqlDateTimeFormat, val); err != nil {
|
||||
return res, fmt.Errorf("bulk: unable to convert string to date: %v", err)
|
||||
}
|
||||
res.buffer = encodeDateTimeOffset(t, int(col.ti.Scale))
|
||||
res.ti.Size = len(res.buffer)
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for datetimeoffset column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
case typeDateN:
|
||||
switch val := val.(type) {
|
||||
case time.Time:
|
||||
res.buffer = encodeDate(val)
|
||||
res.ti.Size = len(res.buffer)
|
||||
case string:
|
||||
var t time.Time
|
||||
if t, err = time.ParseInLocation(sqlDateFormat, val, loc); err != nil {
|
||||
return res, fmt.Errorf("bulk: unable to convert string to date: %v", err)
|
||||
}
|
||||
res.buffer = encodeDate(t)
|
||||
res.ti.Size = len(res.buffer)
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for date column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
case typeDateTime, typeDateTimeN, typeDateTim4:
|
||||
var t time.Time
|
||||
switch val := val.(type) {
|
||||
case time.Time:
|
||||
t = val
|
||||
case string:
|
||||
if t, err = time.Parse(sqlDateTimeFormat, val); err != nil {
|
||||
return res, fmt.Errorf("bulk: unable to convert string to date: %v", err)
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for datetime column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
|
||||
if col.ti.Size == 4 {
|
||||
res.buffer = encodeDateTim4(t, loc)
|
||||
res.ti.Size = len(res.buffer)
|
||||
} else if col.ti.Size == 8 {
|
||||
res.buffer = encodeDateTime(t)
|
||||
res.ti.Size = len(res.buffer)
|
||||
} else {
|
||||
err = fmt.Errorf("mssql: invalid size of column %d", col.ti.Size)
|
||||
}
|
||||
case typeTimeN:
|
||||
var t time.Time
|
||||
switch val := val.(type) {
|
||||
case time.Time:
|
||||
res.buffer = encodeTime(val.Hour(), val.Minute(), val.Second(), val.Nanosecond(), int(col.ti.Scale))
|
||||
res.ti.Size = len(res.buffer)
|
||||
case string:
|
||||
if t, err = time.Parse(sqlTimeFormat, val); err != nil {
|
||||
return res, fmt.Errorf("bulk: unable to convert string to time: %v", err)
|
||||
}
|
||||
res.buffer = encodeTime(t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), int(col.ti.Scale))
|
||||
res.ti.Size = len(res.buffer)
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for time column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
case typeMoney, typeMoney4, typeMoneyN:
|
||||
switch v := val.(type) {
|
||||
case string:
|
||||
money, err := decimal.StringToDecimalScale(v, 4)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
buf := make([]byte, col.ti.Size)
|
||||
|
||||
integer0 := money.GetInteger(0)
|
||||
if col.ti.Size == 4 {
|
||||
if money.IsPositive() {
|
||||
binary.LittleEndian.PutUint32(buf, integer0)
|
||||
} else {
|
||||
binary.LittleEndian.PutUint32(buf, ^integer0+1)
|
||||
}
|
||||
} else {
|
||||
integer := (uint64(money.GetInteger(1)) << 32) | uint64(integer0)
|
||||
if !money.IsPositive() {
|
||||
integer = ^integer + 1
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint32(buf, uint32(integer>>32))
|
||||
binary.LittleEndian.PutUint32(buf[4:], uint32(integer))
|
||||
}
|
||||
|
||||
res.buffer = buf
|
||||
default:
|
||||
return res, fmt.Errorf("unknown value for money: %T %#v", v, v)
|
||||
}
|
||||
case typeDecimal, typeDecimalN, typeNumeric, typeNumericN:
|
||||
prec := col.ti.Prec
|
||||
scale := col.ti.Scale
|
||||
var dec decimal.Decimal
|
||||
switch v := val.(type) {
|
||||
case int:
|
||||
dec = decimal.Int64ToDecimalScale(int64(v), 0)
|
||||
case int8:
|
||||
dec = decimal.Int64ToDecimalScale(int64(v), 0)
|
||||
case int16:
|
||||
dec = decimal.Int64ToDecimalScale(int64(v), 0)
|
||||
case int32:
|
||||
dec = decimal.Int64ToDecimalScale(int64(v), 0)
|
||||
case int64:
|
||||
dec = decimal.Int64ToDecimalScale(int64(v), 0)
|
||||
case float32:
|
||||
dec, err = decimal.Float64ToDecimalScale(float64(v), scale)
|
||||
case float64:
|
||||
dec, err = decimal.Float64ToDecimalScale(float64(v), scale)
|
||||
case string:
|
||||
dec, err = decimal.StringToDecimalScale(v, scale)
|
||||
default:
|
||||
return res, fmt.Errorf("unknown value for decimal: %T %#v", v, v)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
dec.SetPrec(prec)
|
||||
|
||||
var length byte
|
||||
switch {
|
||||
case prec <= 9:
|
||||
length = 4
|
||||
case prec <= 19:
|
||||
length = 8
|
||||
case prec <= 28:
|
||||
length = 12
|
||||
default:
|
||||
length = 16
|
||||
}
|
||||
|
||||
buf := make([]byte, length+1)
|
||||
// first byte length written by typeInfo.writer
|
||||
res.ti.Size = int(length) + 1
|
||||
// second byte sign
|
||||
if !dec.IsPositive() {
|
||||
buf[0] = 0
|
||||
} else {
|
||||
buf[0] = 1
|
||||
}
|
||||
|
||||
ub := dec.UnscaledBytes()
|
||||
l := len(ub)
|
||||
if l > int(length) {
|
||||
err = fmt.Errorf("decimal out of range: %s", dec)
|
||||
return res, err
|
||||
}
|
||||
// reverse the bytes
|
||||
for i, j := 1, l-1; j >= 0; i, j = i+1, j-1 {
|
||||
buf[i] = ub[j]
|
||||
}
|
||||
res.buffer = buf
|
||||
case typeBigVarBin, typeBigBinary:
|
||||
switch val := val.(type) {
|
||||
case []byte:
|
||||
res.ti.Size = len(val)
|
||||
res.buffer = val
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for Binary column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
case typeGuid:
|
||||
switch val := val.(type) {
|
||||
case []byte:
|
||||
res.ti.Size = len(val)
|
||||
res.buffer = val
|
||||
default:
|
||||
err = fmt.Errorf("mssql: invalid type for Guid column: %T %s", val, val)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("mssql: type %x not implemented", col.ti.TypeId)
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (b *Bulk) dlogf(ctx context.Context, format string, v ...interface{}) {
|
||||
if b.Debug {
|
||||
b.cn.sess.LogF(ctx, msdsn.LogDebug, format, v...)
|
||||
}
|
||||
}
|
||||
93
vendor/github.com/microsoft/go-mssqldb/bulkcopy_sql.go
generated
vendored
Normal file
93
vendor/github.com/microsoft/go-mssqldb/bulkcopy_sql.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type copyin struct {
|
||||
cn *Conn
|
||||
bulkcopy *Bulk
|
||||
closed bool
|
||||
}
|
||||
|
||||
type serializableBulkConfig struct {
|
||||
TableName string
|
||||
ColumnsName []string
|
||||
Options BulkOptions
|
||||
}
|
||||
|
||||
func (d *Driver) OpenConnection(dsn string) (*Conn, error) {
|
||||
return d.open(context.Background(), dsn)
|
||||
}
|
||||
|
||||
func (c *Conn) prepareCopyIn(ctx context.Context, query string) (_ driver.Stmt, err error) {
|
||||
config_json := query[11:]
|
||||
|
||||
bulkconfig := serializableBulkConfig{}
|
||||
err = json.Unmarshal([]byte(config_json), &bulkconfig)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bulkcopy := c.CreateBulkContext(ctx, bulkconfig.TableName, bulkconfig.ColumnsName)
|
||||
bulkcopy.Options = bulkconfig.Options
|
||||
|
||||
ci := ©in{
|
||||
cn: c,
|
||||
bulkcopy: bulkcopy,
|
||||
}
|
||||
|
||||
return ci, nil
|
||||
}
|
||||
|
||||
func CopyIn(table string, options BulkOptions, columns ...string) string {
|
||||
bulkconfig := &serializableBulkConfig{TableName: table, Options: options, ColumnsName: columns}
|
||||
|
||||
config_json, err := json.Marshal(bulkconfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stmt := "INSERTBULK " + string(config_json)
|
||||
|
||||
return stmt
|
||||
}
|
||||
|
||||
func (ci *copyin) NumInput() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) {
|
||||
panic("should never be called")
|
||||
}
|
||||
|
||||
func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
|
||||
if ci.closed {
|
||||
return nil, errors.New("copyin query is closed")
|
||||
}
|
||||
|
||||
if len(v) == 0 {
|
||||
rowCount, err := ci.bulkcopy.Done()
|
||||
ci.closed = true
|
||||
return driver.RowsAffected(rowCount), err
|
||||
}
|
||||
|
||||
t := make([]interface{}, len(v))
|
||||
for i, val := range v {
|
||||
t[i] = val
|
||||
}
|
||||
|
||||
err = ci.bulkcopy.AddRow(t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return driver.RowsAffected(0), nil
|
||||
}
|
||||
|
||||
func (ci *copyin) Close() (err error) {
|
||||
return nil
|
||||
}
|
||||
40
vendor/github.com/microsoft/go-mssqldb/columnencryptionkey.go
generated
vendored
Normal file
40
vendor/github.com/microsoft/go-mssqldb/columnencryptionkey.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package mssql
|
||||
|
||||
const (
|
||||
CertificateStoreKeyProvider = "MSSQL_CERTIFICATE_STORE"
|
||||
CspKeyProvider = "MSSQL_CSP_PROVIDER"
|
||||
CngKeyProvider = "MSSQL_CNG_STORE"
|
||||
AzureKeyVaultKeyProvider = "AZURE_KEY_VAULT"
|
||||
JavaKeyProvider = "MSSQL_JAVA_KEYSTORE"
|
||||
KeyEncryptionAlgorithm = "RSA_OAEP"
|
||||
)
|
||||
|
||||
// cek ==> Column Encryption Key
|
||||
// Every row of an encrypted table has an associated list of keys used to decrypt its columns
|
||||
type cekTable struct {
|
||||
entries []cekTableEntry
|
||||
}
|
||||
|
||||
type encryptionKeyInfo struct {
|
||||
encryptedKey []byte
|
||||
databaseID int
|
||||
cekID int
|
||||
cekVersion int
|
||||
cekMdVersion []byte
|
||||
keyPath string
|
||||
keyStoreName string
|
||||
algorithmName string
|
||||
}
|
||||
|
||||
type cekTableEntry struct {
|
||||
databaseID int
|
||||
keyId int
|
||||
keyVersion int
|
||||
mdVersion []byte
|
||||
valueCount int
|
||||
cekValues []encryptionKeyInfo
|
||||
}
|
||||
|
||||
func newCekTable(size uint16) cekTable {
|
||||
return cekTable{entries: make([]cekTableEntry, size)}
|
||||
}
|
||||
306
vendor/github.com/microsoft/go-mssqldb/convert.go
generated
vendored
Normal file
306
vendor/github.com/microsoft/go-mssqldb/convert.go
generated
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
package mssql
|
||||
|
||||
import "errors"
|
||||
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Type conversions for Scan.
|
||||
|
||||
// This file was imported from database.sql.convert for go 1.10.3 with minor modifications to get
|
||||
// convertAssign function
|
||||
// This function is used internally by sql to convert values during call to Scan, we need same
|
||||
// logic to return values for OUTPUT parameters.
|
||||
// TODO: sql library should instead expose function defaultCheckNamedValue to be callable by drivers
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
|
||||
|
||||
// convertAssign copies to dest the value in src, converting it if possible.
|
||||
// An error is returned if the copy would result in loss of information.
|
||||
// dest should be a pointer type.
|
||||
func convertAssign(dest, src interface{}) error {
|
||||
// Common cases, without reflect.
|
||||
switch s := src.(type) {
|
||||
case string:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = []byte(s)
|
||||
return nil
|
||||
case *sql.RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = append((*d)[:0], s...)
|
||||
return nil
|
||||
}
|
||||
case []byte:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = string(s)
|
||||
return nil
|
||||
case *interface{}:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = cloneBytes(s)
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = cloneBytes(s)
|
||||
return nil
|
||||
case *sql.RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s
|
||||
return nil
|
||||
}
|
||||
case time.Time:
|
||||
switch d := dest.(type) {
|
||||
case *time.Time:
|
||||
*d = s
|
||||
return nil
|
||||
case *string:
|
||||
*d = s.Format(time.RFC3339Nano)
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = []byte(s.Format(time.RFC3339Nano))
|
||||
return nil
|
||||
case *sql.RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
|
||||
return nil
|
||||
}
|
||||
case nil:
|
||||
switch d := dest.(type) {
|
||||
case *interface{}:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
case *sql.RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var sv reflect.Value
|
||||
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
sv = reflect.ValueOf(src)
|
||||
switch sv.Kind() {
|
||||
case reflect.Bool,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64:
|
||||
*d = asString(src)
|
||||
return nil
|
||||
}
|
||||
case *[]byte:
|
||||
sv = reflect.ValueOf(src)
|
||||
if b, ok := asBytes(nil, sv); ok {
|
||||
*d = b
|
||||
return nil
|
||||
}
|
||||
case *sql.RawBytes:
|
||||
sv = reflect.ValueOf(src)
|
||||
if b, ok := asBytes([]byte(*d)[:0], sv); ok {
|
||||
*d = sql.RawBytes(b)
|
||||
return nil
|
||||
}
|
||||
case *bool:
|
||||
bv, err := driver.Bool.ConvertValue(src)
|
||||
if err == nil {
|
||||
*d = bv.(bool)
|
||||
}
|
||||
return err
|
||||
case *interface{}:
|
||||
*d = src
|
||||
return nil
|
||||
}
|
||||
|
||||
if scanner, ok := dest.(sql.Scanner); ok {
|
||||
return scanner.Scan(src)
|
||||
}
|
||||
|
||||
dpv := reflect.ValueOf(dest)
|
||||
if dpv.Kind() != reflect.Ptr {
|
||||
return errors.New("destination not a pointer")
|
||||
}
|
||||
if dpv.IsNil() {
|
||||
return errNilPtr
|
||||
}
|
||||
|
||||
if !sv.IsValid() {
|
||||
sv = reflect.ValueOf(src)
|
||||
}
|
||||
|
||||
dv := reflect.Indirect(dpv)
|
||||
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
|
||||
switch b := src.(type) {
|
||||
case []byte:
|
||||
dv.Set(reflect.ValueOf(cloneBytes(b)))
|
||||
default:
|
||||
dv.Set(sv)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
|
||||
dv.Set(sv.Convert(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// The following conversions use a string value as an intermediate representation
|
||||
// to convert between various numeric types.
|
||||
//
|
||||
// This also allows scanning into user defined types such as "type Int int64".
|
||||
// For symmetry, also check for string destination types.
|
||||
switch dv.Kind() {
|
||||
case reflect.Ptr:
|
||||
if src == nil {
|
||||
dv.Set(reflect.Zero(dv.Type()))
|
||||
return nil
|
||||
} else {
|
||||
dv.Set(reflect.New(dv.Type().Elem()))
|
||||
return convertAssign(dv.Interface(), src)
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
s := asString(src)
|
||||
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetInt(i64)
|
||||
return nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
s := asString(src)
|
||||
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetUint(u64)
|
||||
return nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
s := asString(src)
|
||||
f64, err := strconv.ParseFloat(s, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetFloat(f64)
|
||||
return nil
|
||||
case reflect.String:
|
||||
switch v := src.(type) {
|
||||
case string:
|
||||
dv.SetString(v)
|
||||
return nil
|
||||
case []byte:
|
||||
dv.SetString(string(v))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
|
||||
}
|
||||
|
||||
func strconvErr(err error) error {
|
||||
if ne, ok := err.(*strconv.NumError); ok {
|
||||
return ne.Err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func cloneBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
} else {
|
||||
c := make([]byte, len(b))
|
||||
copy(c, b)
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
func asString(src interface{}) string {
|
||||
switch v := src.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
}
|
||||
rv := reflect.ValueOf(src)
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(rv.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(rv.Uint(), 10)
|
||||
case reflect.Float64:
|
||||
return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
|
||||
case reflect.Float32:
|
||||
return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(rv.Bool())
|
||||
}
|
||||
return fmt.Sprintf("%v", src)
|
||||
}
|
||||
|
||||
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.AppendInt(buf, rv.Int(), 10), true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.AppendUint(buf, rv.Uint(), 10), true
|
||||
case reflect.Float32:
|
||||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
|
||||
case reflect.Float64:
|
||||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
|
||||
case reflect.Bool:
|
||||
return strconv.AppendBool(buf, rv.Bool()), true
|
||||
case reflect.String:
|
||||
s := rv.String()
|
||||
return append(buf, s...), true
|
||||
}
|
||||
return
|
||||
}
|
||||
16
vendor/github.com/microsoft/go-mssqldb/doc.go
generated
vendored
Normal file
16
vendor/github.com/microsoft/go-mssqldb/doc.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// package mssql implements the TDS protocol used to connect to MS SQL Server (sqlserver)
|
||||
// database servers.
|
||||
//
|
||||
// This package registers the driver:
|
||||
//
|
||||
// sqlserver: uses native "@" parameter placeholder names and does no pre-processing.
|
||||
//
|
||||
// If the ordinal position is used for query parameters, identifiers will be named
|
||||
// "@p1", "@p2", ... "@pN".
|
||||
//
|
||||
// Please refer to the README for the format of the DSN. There are multiple DSN
|
||||
// formats accepted: ADO style, ODBC style, and URL style. The following is an
|
||||
// example of a URL style DSN:
|
||||
//
|
||||
// sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30
|
||||
package mssql
|
||||
292
vendor/github.com/microsoft/go-mssqldb/encrypt.go
generated
vendored
Normal file
292
vendor/github.com/microsoft/go-mssqldb/encrypt.go
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/algorithms"
|
||||
"github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/encryption"
|
||||
"github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/keys"
|
||||
)
|
||||
|
||||
type ColumnEncryptionType int
|
||||
|
||||
var (
|
||||
ColumnEncryptionPlainText ColumnEncryptionType = 0
|
||||
ColumnEncryptionDeterministic ColumnEncryptionType = 1
|
||||
ColumnEncryptionRandomized ColumnEncryptionType = 2
|
||||
)
|
||||
|
||||
type cekData struct {
|
||||
ordinal int
|
||||
database_id int
|
||||
id int
|
||||
version int
|
||||
metadataVersion []byte
|
||||
encryptedValue []byte
|
||||
cmkStoreName string
|
||||
cmkPath string
|
||||
algorithm string
|
||||
//byEnclave bool
|
||||
//cmkSignature string
|
||||
decryptedValue []byte
|
||||
}
|
||||
|
||||
type parameterEncData struct {
|
||||
ordinal int
|
||||
name string
|
||||
algorithm int
|
||||
encType ColumnEncryptionType
|
||||
cekOrdinal int
|
||||
ruleVersion int
|
||||
}
|
||||
|
||||
type paramMapEntry struct {
|
||||
cek *cekData
|
||||
p *parameterEncData
|
||||
}
|
||||
|
||||
// when Always Encrypted is turned on, we have to ask the server for metadata about how to encrypt input parameters.
|
||||
// This function stores the relevant encryption parameters in a copy of the args so they can be
|
||||
// encrypted just before being sent to the server
|
||||
func (s *Stmt) encryptArgs(ctx context.Context, args []namedValue) (encryptedArgs []namedValue, err error) {
|
||||
q := Stmt{c: s.c,
|
||||
paramCount: s.paramCount,
|
||||
query: "sp_describe_parameter_encryption",
|
||||
skipEncryption: true,
|
||||
}
|
||||
oldouts := s.c.outs
|
||||
s.c.clearOuts()
|
||||
newArgs, err := s.prepareEncryptionQuery(isProc(s.query), s.query, args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// TODO: Consider not using recursion.
|
||||
rows, err := q.queryContext(ctx, newArgs)
|
||||
if err != nil {
|
||||
s.c.outs = oldouts
|
||||
return
|
||||
}
|
||||
cekInfo, paramsInfo, err := processDescribeParameterEncryption(rows)
|
||||
rows.Close()
|
||||
s.c.outs = oldouts
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(cekInfo) == 0 {
|
||||
return args, nil
|
||||
}
|
||||
err = s.decryptCek(ctx, cekInfo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
paramMap := make(map[string]paramMapEntry)
|
||||
for _, p := range paramsInfo {
|
||||
if p.encType == ColumnEncryptionPlainText {
|
||||
paramMap[p.name] = paramMapEntry{nil, p}
|
||||
} else {
|
||||
paramMap[p.name] = paramMapEntry{cekInfo[p.cekOrdinal-1], p}
|
||||
}
|
||||
}
|
||||
encryptedArgs = make([]namedValue, len(args))
|
||||
for i, a := range args {
|
||||
encryptedArgs[i] = a
|
||||
name := ""
|
||||
if len(a.Name) > 0 {
|
||||
name = "@" + a.Name
|
||||
} else {
|
||||
name = fmt.Sprintf("@p%d", a.Ordinal)
|
||||
}
|
||||
info := paramMap[name]
|
||||
|
||||
if info.p.encType == ColumnEncryptionPlainText || a.Value == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
encryptedArgs[i].encrypt = getEncryptor(info)
|
||||
}
|
||||
return encryptedArgs, nil
|
||||
}
|
||||
|
||||
// returns the arguments to sp_describe_parameter_encryption
|
||||
// sp_describe_parameter_encryption
|
||||
// [ @tsql = ] N'Transact-SQL_batch' ,
|
||||
// [ @params = ] N'parameters'
|
||||
// [ ;]
|
||||
func (s *Stmt) prepareEncryptionQuery(isProc bool, q string, args []namedValue) (newArgs []namedValue, err error) {
|
||||
newArgs = make([]namedValue, 2)
|
||||
if isProc {
|
||||
newArgs[0] = namedValue{Name: "tsql", Ordinal: 0, Value: buildStoredProcedureStatementForColumnEncryption(q, args)}
|
||||
} else {
|
||||
newArgs[0] = namedValue{Name: "tsql", Ordinal: 0, Value: q}
|
||||
}
|
||||
params, err := s.buildParametersForColumnEncryption(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
newArgs[1] = namedValue{Name: "params", Ordinal: 1, Value: params}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Stmt) buildParametersForColumnEncryption(args []namedValue) (parameters string, err error) {
|
||||
_, decls, err := s.makeRPCParams(args, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
parameters = strings.Join(decls, ", ")
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Stmt) decryptCek(ctx context.Context, cekInfo []*cekData) error {
|
||||
for _, info := range cekInfo {
|
||||
kp, ok := s.c.sess.aeSettings.keyProviders[info.cmkStoreName]
|
||||
if !ok {
|
||||
return fmt.Errorf("no provider found for key store %s", info.cmkStoreName)
|
||||
}
|
||||
dk, err := kp.GetDecryptedKey(ctx, info.cmkPath, info.encryptedValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.decryptedValue = dk
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEncryptor(info paramMapEntry) valueEncryptor {
|
||||
k := keys.NewAeadAes256CbcHmac256(info.cek.decryptedValue)
|
||||
alg := algorithms.NewAeadAes256CbcHmac256Algorithm(k, encryption.From(byte(info.p.encType)), byte(info.cek.version))
|
||||
// Metadata to append to an encrypted parameter. Doesn't include original typeinfo
|
||||
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/619c43b6-9495-4a58-9e49-a4950db245b3
|
||||
// ParamCipherInfo = TYPE_INFO
|
||||
// EncryptionAlgo (byte)
|
||||
// [AlgoName] (b_varchar) unused, no custom algorithm
|
||||
// EncryptionType (byte)
|
||||
// DatabaseId (ulong)
|
||||
// CekId (ulong)
|
||||
// CekVersion (ulong)
|
||||
// CekMDVersion (ulonglong) - really a byte array
|
||||
// NormVersion (byte)
|
||||
// algo+ enctype+ dbid+ keyid+ keyver+ normversion
|
||||
metadataLen := 1 + 1 + 4 + 4 + 4 + 1
|
||||
metadataLen += len(info.cek.metadataVersion)
|
||||
metadata := make([]byte, metadataLen)
|
||||
offset := 0
|
||||
// AEAD_AES_256_CBC_HMAC_SHA256
|
||||
metadata[offset] = byte(info.p.algorithm)
|
||||
offset++
|
||||
metadata[offset] = byte(info.p.encType)
|
||||
offset++
|
||||
binary.LittleEndian.PutUint32(metadata[offset:], uint32(info.cek.database_id))
|
||||
offset += 4
|
||||
binary.LittleEndian.PutUint32(metadata[offset:], uint32(info.cek.id))
|
||||
offset += 4
|
||||
binary.LittleEndian.PutUint32(metadata[offset:], uint32(info.cek.version))
|
||||
offset += 4
|
||||
copy(metadata[offset:], info.cek.metadataVersion)
|
||||
offset += len(info.cek.metadataVersion)
|
||||
metadata[offset] = byte(info.p.ruleVersion)
|
||||
return func(b []byte) ([]byte, []byte, error) {
|
||||
encryptedData, err := alg.Encrypt(b)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return encryptedData, metadata, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Based on the .Net implementation at https://github.com/dotnet/SqlClient/blob/2b31810ce69b88d707450e2059ee8fbde63f774f/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs#L6040
|
||||
func buildStoredProcedureStatementForColumnEncryption(sproc string, args []namedValue) string {
|
||||
b := new(strings.Builder)
|
||||
_, _ = b.WriteString("EXEC ")
|
||||
q := TSQLQuoter{}
|
||||
sproc = q.ID(sproc)
|
||||
|
||||
b.WriteString(sproc)
|
||||
|
||||
// Unlike ADO.Net, go-mssqldb doesn't support ReturnValue named parameters
|
||||
first := true
|
||||
for _, a := range args {
|
||||
if !first {
|
||||
b.WriteRune(',')
|
||||
}
|
||||
first = false
|
||||
b.WriteRune(' ')
|
||||
name := a.Name
|
||||
if len(name) == 0 {
|
||||
name = fmt.Sprintf("@p%d", a.Ordinal)
|
||||
}
|
||||
appendPrefixedParameterName(b, name)
|
||||
if len(a.Name) > 0 {
|
||||
b.WriteRune('=')
|
||||
appendPrefixedParameterName(b, a.Name)
|
||||
}
|
||||
if isOutputValue(a.Value) {
|
||||
b.WriteString(" OUTPUT")
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func appendPrefixedParameterName(b *strings.Builder, p string) {
|
||||
if len(p) > 0 {
|
||||
if p[0] != '@' {
|
||||
b.WriteRune('@')
|
||||
}
|
||||
b.WriteString(p)
|
||||
}
|
||||
}
|
||||
|
||||
func processDescribeParameterEncryption(rows driver.Rows) (cekInfo []*cekData, paramInfo []*parameterEncData, err error) {
|
||||
cekInfo = make([]*cekData, 0)
|
||||
values := make([]driver.Value, 9)
|
||||
qerr := rows.Next(values)
|
||||
for qerr == nil {
|
||||
cekInfo = append(cekInfo, &cekData{ordinal: int(values[0].(int64)),
|
||||
database_id: int(values[1].(int64)),
|
||||
id: int(values[2].(int64)),
|
||||
version: int(values[3].(int64)),
|
||||
metadataVersion: values[4].([]byte),
|
||||
encryptedValue: values[5].([]byte),
|
||||
cmkStoreName: values[6].(string),
|
||||
cmkPath: values[7].(string),
|
||||
algorithm: values[8].(string),
|
||||
})
|
||||
qerr = rows.Next(values)
|
||||
}
|
||||
if len(cekInfo) == 0 || qerr != io.EOF {
|
||||
if qerr != io.EOF {
|
||||
err = qerr
|
||||
}
|
||||
// No encryption needed
|
||||
return
|
||||
}
|
||||
r := rows.(driver.RowsNextResultSet)
|
||||
err = r.NextResultSet()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
paramInfo = make([]*parameterEncData, 0)
|
||||
qerr = rows.Next(values[:6])
|
||||
for qerr == nil {
|
||||
paramInfo = append(paramInfo, ¶meterEncData{ordinal: int(values[0].(int64)),
|
||||
name: values[1].(string),
|
||||
algorithm: int(values[2].(int64)),
|
||||
encType: ColumnEncryptionType(values[3].(int64)),
|
||||
cekOrdinal: int(values[4].(int64)),
|
||||
ruleVersion: int(values[5].(int64)),
|
||||
})
|
||||
qerr = rows.Next(values[:6])
|
||||
}
|
||||
if len(paramInfo) == 0 || qerr != io.EOF {
|
||||
if qerr != io.EOF {
|
||||
err = qerr
|
||||
} else {
|
||||
badStreamPanic(fmt.Errorf("no parameter encryption rows were returned from sp_describe_parameter_encryption"))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
121
vendor/github.com/microsoft/go-mssqldb/error.go
generated
vendored
Normal file
121
vendor/github.com/microsoft/go-mssqldb/error.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Error represents an SQL Server error. This
|
||||
// type includes methods for reading the contents
|
||||
// of the struct, which allows calling programs
|
||||
// to check for specific error conditions without
|
||||
// having to import this package directly.
|
||||
type Error struct {
|
||||
Number int32
|
||||
State uint8
|
||||
Class uint8
|
||||
Message string
|
||||
ServerName string
|
||||
ProcName string
|
||||
LineNo int32
|
||||
// All lists all errors that were received from first to last.
|
||||
// This includes the last one, which is described in the other members.
|
||||
All []Error
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
return "mssql: " + e.Message
|
||||
}
|
||||
|
||||
func (e Error) String() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// SQLErrorNumber returns the SQL Server error number.
|
||||
func (e Error) SQLErrorNumber() int32 {
|
||||
return e.Number
|
||||
}
|
||||
|
||||
func (e Error) SQLErrorState() uint8 {
|
||||
return e.State
|
||||
}
|
||||
|
||||
func (e Error) SQLErrorClass() uint8 {
|
||||
return e.Class
|
||||
}
|
||||
|
||||
func (e Error) SQLErrorMessage() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func (e Error) SQLErrorServerName() string {
|
||||
return e.ServerName
|
||||
}
|
||||
|
||||
func (e Error) SQLErrorProcName() string {
|
||||
return e.ProcName
|
||||
}
|
||||
|
||||
func (e Error) SQLErrorLineNo() int32 {
|
||||
return e.LineNo
|
||||
}
|
||||
|
||||
type StreamError struct {
|
||||
InnerError error
|
||||
}
|
||||
|
||||
func (e StreamError) Error() string {
|
||||
return "Invalid TDS stream: " + e.InnerError.Error()
|
||||
}
|
||||
|
||||
func badStreamPanic(err error) {
|
||||
panic(StreamError{InnerError: err})
|
||||
}
|
||||
|
||||
func badStreamPanicf(format string, v ...interface{}) {
|
||||
panic(fmt.Errorf(format, v...))
|
||||
}
|
||||
|
||||
// ServerError is returned when the server got a fatal error
|
||||
// that aborts the process and severs the connection.
|
||||
//
|
||||
// To get the errors returned before the process was aborted,
|
||||
// unwrap this error or call errors.As with a pointer to an
|
||||
// mssql.Error variable.
|
||||
type ServerError struct {
|
||||
sqlError Error
|
||||
}
|
||||
|
||||
func (e ServerError) Error() string {
|
||||
return "SQL Server had internal error"
|
||||
}
|
||||
|
||||
func (e ServerError) Unwrap() error {
|
||||
return e.sqlError
|
||||
}
|
||||
|
||||
// RetryableError is returned when an error was caused by a bad
|
||||
// connection at the start of a query and can be safely retried
|
||||
// using database/sql's automatic retry logic.
|
||||
//
|
||||
// In many cases database/sql's retry logic will transparently
|
||||
// handle this error, the retried call will return successfully,
|
||||
// and you won't even see this error. However, you may see this
|
||||
// error if the retry logic cannot successfully handle the error.
|
||||
// In that case you can get the underlying error by calling this
|
||||
// error's UnWrap function.
|
||||
type RetryableError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (r RetryableError) Error() string {
|
||||
return r.err.Error()
|
||||
}
|
||||
|
||||
func (r RetryableError) Unwrap() error {
|
||||
return r.err
|
||||
}
|
||||
|
||||
func (r RetryableError) Is(err error) bool {
|
||||
return err == driver.ErrBadConn
|
||||
}
|
||||
81
vendor/github.com/microsoft/go-mssqldb/fedauth.go
generated
vendored
Normal file
81
vendor/github.com/microsoft/go-mssqldb/fedauth.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/microsoft/go-mssqldb/msdsn"
|
||||
)
|
||||
|
||||
// Federated authentication library affects the login data structure and message sequence.
|
||||
const (
|
||||
// FedAuthLibraryLiveIDCompactToken specifies the Microsoft Live ID Compact Token authentication scheme
|
||||
FedAuthLibraryLiveIDCompactToken = 0x00
|
||||
|
||||
// FedAuthLibrarySecurityToken specifies a token-based authentication where the token is available
|
||||
// without additional information provided during the login sequence.
|
||||
FedAuthLibrarySecurityToken = 0x01
|
||||
|
||||
// FedAuthLibraryADAL specifies a token-based authentication where a token is obtained during the
|
||||
// login sequence using the server SPN and STS URL provided by the server during login.
|
||||
FedAuthLibraryADAL = 0x02
|
||||
|
||||
// FedAuthLibraryReserved is used to indicate that no federated authentication scheme applies.
|
||||
FedAuthLibraryReserved = 0x7F
|
||||
)
|
||||
|
||||
// Federated authentication ADAL workflow affects the mechanism used to authenticate.
|
||||
const (
|
||||
// FedAuthADALWorkflowPassword uses a username/password to obtain a token from Active Directory
|
||||
FedAuthADALWorkflowPassword = 0x01
|
||||
|
||||
// fedAuthADALWorkflowPassword uses the Windows identity to obtain a token from Active Directory
|
||||
FedAuthADALWorkflowIntegrated = 0x02
|
||||
|
||||
// FedAuthADALWorkflowMSI uses the managed identity service to obtain a token
|
||||
FedAuthADALWorkflowMSI = 0x03
|
||||
|
||||
// FedAuthADALWorkflowNone does not need to obtain token
|
||||
FedAuthADALWorkflowNone = 0x04
|
||||
)
|
||||
|
||||
// newSecurityTokenConnector creates a new connector from a Config and a token provider.
|
||||
// When invoked, token provider implementations should contact the security token
|
||||
// service specified and obtain the appropriate token, or return an error
|
||||
// to indicate why a token is not available.
|
||||
// The returned connector may be used with sql.OpenDB.
|
||||
func NewSecurityTokenConnector(config msdsn.Config, tokenProvider func(ctx context.Context) (string, error)) (*Connector, error) {
|
||||
if tokenProvider == nil {
|
||||
return nil, errors.New("mssql: tokenProvider cannot be nil")
|
||||
}
|
||||
|
||||
conn := NewConnectorConfig(config)
|
||||
conn.fedAuthRequired = true
|
||||
conn.fedAuthLibrary = FedAuthLibrarySecurityToken
|
||||
conn.securityTokenProvider = tokenProvider
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// newADALTokenConnector creates a new connector from a Config and a Active Directory token provider.
|
||||
// Token provider implementations are called during federated
|
||||
// authentication login sequences where the server provides a service
|
||||
// principal name and security token service endpoint that should be used
|
||||
// to obtain the token. Implementations should contact the security token
|
||||
// service specified and obtain the appropriate token, or return an error
|
||||
// to indicate why a token is not available.
|
||||
//
|
||||
// The returned connector may be used with sql.OpenDB.
|
||||
func NewActiveDirectoryTokenConnector(config msdsn.Config, adalWorkflow byte, tokenProvider func(ctx context.Context, serverSPN, stsURL string) (string, error)) (*Connector, error) {
|
||||
if tokenProvider == nil {
|
||||
return nil, errors.New("mssql: tokenProvider cannot be nil")
|
||||
}
|
||||
|
||||
conn := NewConnectorConfig(config)
|
||||
conn.fedAuthRequired = true
|
||||
conn.fedAuthLibrary = FedAuthLibraryADAL
|
||||
conn.fedAuthADALWorkflow = adalWorkflow
|
||||
conn.adalTokenProvider = tokenProvider
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
73
vendor/github.com/microsoft/go-mssqldb/integratedauth/auth.go
generated
vendored
Normal file
73
vendor/github.com/microsoft/go-mssqldb/integratedauth/auth.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package integratedauth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/microsoft/go-mssqldb/msdsn"
|
||||
)
|
||||
|
||||
var (
|
||||
providers map[string]Provider
|
||||
DefaultProviderName string
|
||||
|
||||
ErrProviderCannotBeNil = errors.New("provider cannot be nil")
|
||||
ErrProviderNameMustBePopulated = errors.New("provider name must be populated")
|
||||
)
|
||||
|
||||
func init() {
|
||||
providers = make(map[string]Provider)
|
||||
}
|
||||
|
||||
// GetIntegratedAuthenticator calls the authProvider specified in the 'authenticator' connection string parameter, if supplied.
|
||||
// Otherwise fails back to the DefaultProviderName implementation for the platform.
|
||||
func GetIntegratedAuthenticator(config msdsn.Config) (IntegratedAuthenticator, error) {
|
||||
authenticatorName, ok := config.Parameters["authenticator"]
|
||||
if !ok {
|
||||
provider, err := getProvider(DefaultProviderName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p, err := provider.GetIntegratedAuthenticator(config)
|
||||
// we ignore the error in this case to force a fallback to sqlserver authentication.
|
||||
// this preserves the original behaviour
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
provider, err := getProvider(authenticatorName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return provider.GetIntegratedAuthenticator(config)
|
||||
}
|
||||
|
||||
func getProvider(name string) (Provider, error) {
|
||||
provider, ok := providers[name]
|
||||
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("provider %v not found", name)
|
||||
}
|
||||
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
// SetIntegratedAuthenticationProvider stores a named authentication provider. It should be called before any connections are created.
|
||||
func SetIntegratedAuthenticationProvider(providerName string, p Provider) error {
|
||||
if p == nil {
|
||||
return ErrProviderCannotBeNil
|
||||
}
|
||||
|
||||
if providerName == "" {
|
||||
return ErrProviderNameMustBePopulated
|
||||
}
|
||||
|
||||
providers[providerName] = p
|
||||
|
||||
return nil
|
||||
}
|
||||
25
vendor/github.com/microsoft/go-mssqldb/integratedauth/integratedauthenticator.go
generated
vendored
Normal file
25
vendor/github.com/microsoft/go-mssqldb/integratedauth/integratedauthenticator.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package integratedauth
|
||||
|
||||
import (
|
||||
"github.com/microsoft/go-mssqldb/msdsn"
|
||||
)
|
||||
|
||||
// Provider returns an SSPI compatible authentication provider
|
||||
type Provider interface {
|
||||
// GetIntegratedAuthenticator is responsible for returning an instance of the required IntegratedAuthenticator interface
|
||||
GetIntegratedAuthenticator(config msdsn.Config) (IntegratedAuthenticator, error)
|
||||
}
|
||||
|
||||
// IntegratedAuthenticator is the interface for SSPI Login Authentication providers
|
||||
type IntegratedAuthenticator interface {
|
||||
InitialBytes() ([]byte, error)
|
||||
NextBytes([]byte) ([]byte, error)
|
||||
Free()
|
||||
}
|
||||
|
||||
// ProviderFunc is an adapter to convert a GetIntegratedAuthenticator func into a Provider
|
||||
type ProviderFunc func(config msdsn.Config) (IntegratedAuthenticator, error)
|
||||
|
||||
func (f ProviderFunc) GetIntegratedAuthenticator(config msdsn.Config) (IntegratedAuthenticator, error) {
|
||||
return f(config)
|
||||
}
|
||||
396
vendor/github.com/microsoft/go-mssqldb/integratedauth/ntlm/ntlm.go
generated
vendored
Normal file
396
vendor/github.com/microsoft/go-mssqldb/integratedauth/ntlm/ntlm.go
generated
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
package ntlm
|
||||
|
||||
import (
|
||||
"crypto/des"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf16"
|
||||
|
||||
"github.com/microsoft/go-mssqldb/integratedauth"
|
||||
"github.com/microsoft/go-mssqldb/msdsn"
|
||||
|
||||
//lint:ignore SA1019 MD4 is used by legacy NTLM
|
||||
"golang.org/x/crypto/md4"
|
||||
)
|
||||
|
||||
const (
|
||||
_NEGOTIATE_MESSAGE = 1
|
||||
_CHALLENGE_MESSAGE = 2
|
||||
_AUTHENTICATE_MESSAGE = 3
|
||||
)
|
||||
|
||||
const (
|
||||
_NEGOTIATE_UNICODE = 0x00000001
|
||||
_NEGOTIATE_OEM = 0x00000002
|
||||
_NEGOTIATE_TARGET = 0x00000004
|
||||
_NEGOTIATE_SIGN = 0x00000010
|
||||
_NEGOTIATE_SEAL = 0x00000020
|
||||
_NEGOTIATE_DATAGRAM = 0x00000040
|
||||
_NEGOTIATE_LMKEY = 0x00000080
|
||||
_NEGOTIATE_NTLM = 0x00000200
|
||||
_NEGOTIATE_ANONYMOUS = 0x00000800
|
||||
_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000
|
||||
_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000
|
||||
_NEGOTIATE_ALWAYS_SIGN = 0x00008000
|
||||
_NEGOTIATE_TARGET_TYPE_DOMAIN = 0x00010000
|
||||
_NEGOTIATE_TARGET_TYPE_SERVER = 0x00020000
|
||||
_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000
|
||||
_NEGOTIATE_IDENTIFY = 0x00100000
|
||||
_REQUEST_NON_NT_SESSION_KEY = 0x00400000
|
||||
_NEGOTIATE_TARGET_INFO = 0x00800000
|
||||
_NEGOTIATE_VERSION = 0x02000000
|
||||
_NEGOTIATE_128 = 0x20000000
|
||||
_NEGOTIATE_KEY_EXCH = 0x40000000
|
||||
_NEGOTIATE_56 = 0x80000000
|
||||
)
|
||||
|
||||
const _NEGOTIATE_FLAGS = _NEGOTIATE_UNICODE |
|
||||
_NEGOTIATE_NTLM |
|
||||
_NEGOTIATE_OEM_DOMAIN_SUPPLIED |
|
||||
_NEGOTIATE_OEM_WORKSTATION_SUPPLIED |
|
||||
_NEGOTIATE_ALWAYS_SIGN |
|
||||
_NEGOTIATE_EXTENDED_SESSIONSECURITY
|
||||
|
||||
type Auth struct {
|
||||
Domain string
|
||||
UserName string
|
||||
Password string
|
||||
Workstation string
|
||||
}
|
||||
|
||||
// getAuth returns an authentication handle Auth to provide authentication content
|
||||
// to mssql.connect
|
||||
func getAuth(config msdsn.Config) (integratedauth.IntegratedAuthenticator, error) {
|
||||
if !strings.ContainsRune(config.User, '\\') {
|
||||
return nil, fmt.Errorf("ntlm : invalid username %v", config.User)
|
||||
}
|
||||
domainUser := strings.SplitN(config.User, "\\", 2)
|
||||
return &Auth{
|
||||
Domain: domainUser[0],
|
||||
UserName: domainUser[1],
|
||||
Password: config.Password,
|
||||
Workstation: config.Workstation,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func utf16le(val string) []byte {
|
||||
var v []byte
|
||||
for _, r := range val {
|
||||
if utf16.IsSurrogate(r) {
|
||||
r1, r2 := utf16.EncodeRune(r)
|
||||
v = append(v, byte(r1), byte(r1>>8))
|
||||
v = append(v, byte(r2), byte(r2>>8))
|
||||
} else {
|
||||
v = append(v, byte(r), byte(r>>8))
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (auth *Auth) InitialBytes() ([]byte, error) {
|
||||
domain_len := len(auth.Domain)
|
||||
workstation_len := len(auth.Workstation)
|
||||
msg := make([]byte, 40+domain_len+workstation_len)
|
||||
copy(msg, []byte("NTLMSSP\x00"))
|
||||
binary.LittleEndian.PutUint32(msg[8:], _NEGOTIATE_MESSAGE)
|
||||
binary.LittleEndian.PutUint32(msg[12:], _NEGOTIATE_FLAGS)
|
||||
// Domain Name Fields
|
||||
binary.LittleEndian.PutUint16(msg[16:], uint16(domain_len))
|
||||
binary.LittleEndian.PutUint16(msg[18:], uint16(domain_len))
|
||||
binary.LittleEndian.PutUint32(msg[20:], 40)
|
||||
// Workstation Fields
|
||||
binary.LittleEndian.PutUint16(msg[24:], uint16(workstation_len))
|
||||
binary.LittleEndian.PutUint16(msg[26:], uint16(workstation_len))
|
||||
binary.LittleEndian.PutUint32(msg[28:], uint32(40+domain_len))
|
||||
// Version
|
||||
binary.LittleEndian.PutUint32(msg[32:], 0)
|
||||
binary.LittleEndian.PutUint32(msg[36:], 0)
|
||||
// Payload
|
||||
copy(msg[40:], auth.Domain)
|
||||
copy(msg[40+domain_len:], auth.Workstation)
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
var errorNTLM = errors.New("NTLM protocol error")
|
||||
|
||||
func createDesKey(bytes, material []byte) {
|
||||
material[0] = bytes[0]
|
||||
material[1] = (byte)(bytes[0]<<7 | (bytes[1]&0xff)>>1)
|
||||
material[2] = (byte)(bytes[1]<<6 | (bytes[2]&0xff)>>2)
|
||||
material[3] = (byte)(bytes[2]<<5 | (bytes[3]&0xff)>>3)
|
||||
material[4] = (byte)(bytes[3]<<4 | (bytes[4]&0xff)>>4)
|
||||
material[5] = (byte)(bytes[4]<<3 | (bytes[5]&0xff)>>5)
|
||||
material[6] = (byte)(bytes[5]<<2 | (bytes[6]&0xff)>>6)
|
||||
material[7] = (byte)(bytes[6] << 1)
|
||||
}
|
||||
|
||||
func encryptDes(key []byte, cleartext []byte, ciphertext []byte) {
|
||||
var desKey [8]byte
|
||||
createDesKey(key, desKey[:])
|
||||
cipher, err := des.NewCipher(desKey[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cipher.Encrypt(ciphertext, cleartext)
|
||||
}
|
||||
|
||||
func response(challenge [8]byte, hash [21]byte) (ret [24]byte) {
|
||||
encryptDes(hash[:7], challenge[:], ret[:8])
|
||||
encryptDes(hash[7:14], challenge[:], ret[8:16])
|
||||
encryptDes(hash[14:], challenge[:], ret[16:])
|
||||
return
|
||||
}
|
||||
|
||||
func lmHash(password string) (hash [21]byte) {
|
||||
var lmpass [14]byte
|
||||
copy(lmpass[:14], []byte(strings.ToUpper(password)))
|
||||
magic := []byte("KGS!@#$%")
|
||||
encryptDes(lmpass[:7], magic, hash[:8])
|
||||
encryptDes(lmpass[7:], magic, hash[8:])
|
||||
return
|
||||
}
|
||||
|
||||
func lmResponse(challenge [8]byte, password string) [24]byte {
|
||||
hash := lmHash(password)
|
||||
return response(challenge, hash)
|
||||
}
|
||||
|
||||
func ntlmHash(password string) (hash [21]byte) {
|
||||
h := md4.New()
|
||||
h.Write(utf16le(password))
|
||||
h.Sum(hash[:0])
|
||||
return
|
||||
}
|
||||
|
||||
func ntResponse(challenge [8]byte, password string) [24]byte {
|
||||
hash := ntlmHash(password)
|
||||
return response(challenge, hash)
|
||||
}
|
||||
|
||||
func clientChallenge() (nonce [8]byte) {
|
||||
_, err := rand.Read(nonce[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ntlmSessionResponse(clientNonce [8]byte, serverChallenge [8]byte, password string) [24]byte {
|
||||
var sessionHash [16]byte
|
||||
h := md5.New()
|
||||
h.Write(serverChallenge[:])
|
||||
h.Write(clientNonce[:])
|
||||
h.Sum(sessionHash[:0])
|
||||
var hash [8]byte
|
||||
copy(hash[:], sessionHash[:8])
|
||||
passwordHash := ntlmHash(password)
|
||||
return response(hash, passwordHash)
|
||||
}
|
||||
|
||||
func ntlmHashNoPadding(val string) []byte {
|
||||
hash := make([]byte, 16)
|
||||
h := md4.New()
|
||||
h.Write(utf16le(val))
|
||||
h.Sum(hash[:0])
|
||||
|
||||
return hash
|
||||
}
|
||||
|
||||
func hmacMD5(passwordHash, data []byte) []byte {
|
||||
hmacEntity := hmac.New(md5.New, passwordHash)
|
||||
hmacEntity.Write(data)
|
||||
|
||||
return hmacEntity.Sum(nil)
|
||||
}
|
||||
|
||||
func getNTLMv2AndLMv2ResponsePayloads(userDomain, username, password string, challenge, nonce [8]byte, targetInfoFields []byte, timestamp time.Time) (ntlmV2Payload, lmV2Payload []byte) {
|
||||
// NTLMv2 response payload: http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
|
||||
|
||||
ntlmHash := ntlmHashNoPadding(password)
|
||||
usernameAndTargetBytes := utf16le(strings.ToUpper(username) + userDomain)
|
||||
ntlmV2Hash := hmacMD5(ntlmHash, usernameAndTargetBytes)
|
||||
targetInfoLength := len(targetInfoFields)
|
||||
blob := make([]byte, 32+targetInfoLength)
|
||||
binary.BigEndian.PutUint32(blob[:4], 0x01010000)
|
||||
binary.BigEndian.PutUint32(blob[4:8], 0x00000000)
|
||||
binary.BigEndian.PutUint64(blob[8:16], uint64(timestamp.UnixNano()))
|
||||
copy(blob[16:24], nonce[:])
|
||||
binary.BigEndian.PutUint32(blob[24:28], 0x00000000)
|
||||
copy(blob[28:], targetInfoFields)
|
||||
binary.BigEndian.PutUint32(blob[28+targetInfoLength:], 0x00000000)
|
||||
challengeLength := len(challenge)
|
||||
blobLength := len(blob)
|
||||
challengeAndBlob := make([]byte, challengeLength+blobLength)
|
||||
copy(challengeAndBlob[:challengeLength], challenge[:])
|
||||
copy(challengeAndBlob[challengeLength:], blob)
|
||||
hashedChallenge := hmacMD5(ntlmV2Hash, challengeAndBlob)
|
||||
ntlmV2Payload = append(hashedChallenge, blob...)
|
||||
|
||||
// LMv2 response payload: http://davenport.sourceforge.net/ntlm.html#theLmv2Response
|
||||
ntlmV2hash := hmacMD5(ntlmHash, usernameAndTargetBytes)
|
||||
challengeAndNonce := make([]byte, 16)
|
||||
copy(challengeAndNonce[:8], challenge[:])
|
||||
copy(challengeAndNonce[8:], nonce[:])
|
||||
hashedChallenge = hmacMD5(ntlmV2hash, challengeAndNonce)
|
||||
lmV2Payload = append(hashedChallenge, nonce[:]...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func negotiateExtendedSessionSecurity(flags uint32, message []byte, challenge [8]byte, username, password, userDom string) (lm, nt []byte, err error) {
|
||||
nonce := clientChallenge()
|
||||
|
||||
// Official specification: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/b38c36ed-2804-4868-a9ff-8dd3182128e4
|
||||
// Unofficial walk through referenced by https://www.freetds.org/userguide/domains.htm: http://davenport.sourceforge.net/ntlm.html
|
||||
if (flags & _NEGOTIATE_TARGET_INFO) != 0 {
|
||||
targetInfoFields, err := getNTLMv2TargetInfoFields(message)
|
||||
if err != nil {
|
||||
return lm, nt, err
|
||||
}
|
||||
|
||||
nt, lm = getNTLMv2AndLMv2ResponsePayloads(userDom, username, password, challenge, nonce, targetInfoFields, time.Now())
|
||||
|
||||
return lm, nt, nil
|
||||
}
|
||||
|
||||
var lm_bytes [24]byte
|
||||
copy(lm_bytes[:8], nonce[:])
|
||||
lm = lm_bytes[:]
|
||||
nt_bytes := ntlmSessionResponse(nonce, challenge, password)
|
||||
nt = nt_bytes[:]
|
||||
|
||||
return lm, nt, nil
|
||||
}
|
||||
|
||||
func getNTLMv2TargetInfoFields(type2Message []byte) (info []byte, err error) {
|
||||
type2MessageError := "mssql: while parsing NTLMv2 type 2 message, length %d too small for offset %d"
|
||||
type2MessageLength := len(type2Message)
|
||||
if type2MessageLength < 20 {
|
||||
return nil, fmt.Errorf(type2MessageError, type2MessageLength, 20)
|
||||
}
|
||||
|
||||
targetNameAllocated := binary.LittleEndian.Uint16(type2Message[14:16])
|
||||
targetNameOffset := binary.LittleEndian.Uint32(type2Message[16:20])
|
||||
endOfOffset := int(targetNameOffset + uint32(targetNameAllocated))
|
||||
if type2MessageLength < endOfOffset {
|
||||
return nil, fmt.Errorf(type2MessageError, type2MessageLength, endOfOffset)
|
||||
}
|
||||
|
||||
targetInformationAllocated := binary.LittleEndian.Uint16(type2Message[42:44])
|
||||
targetInformationDataOffset := binary.LittleEndian.Uint32(type2Message[44:48])
|
||||
endOfOffset = int(targetInformationDataOffset + uint32(targetInformationAllocated))
|
||||
if type2MessageLength < endOfOffset {
|
||||
return nil, fmt.Errorf(type2MessageError, type2MessageLength, endOfOffset)
|
||||
}
|
||||
|
||||
targetInformationBytes := make([]byte, targetInformationAllocated)
|
||||
copy(targetInformationBytes, type2Message[targetInformationDataOffset:targetInformationDataOffset+uint32(targetInformationAllocated)])
|
||||
|
||||
return targetInformationBytes, nil
|
||||
}
|
||||
|
||||
func buildNTLMResponsePayload(lm, nt []byte, flags uint32, domain, workstation, username string) ([]byte, error) {
|
||||
lm_len := len(lm)
|
||||
nt_len := len(nt)
|
||||
domain16 := utf16le(domain)
|
||||
domain_len := len(domain16)
|
||||
user16 := utf16le(username)
|
||||
user_len := len(user16)
|
||||
workstation16 := utf16le(workstation)
|
||||
workstation_len := len(workstation16)
|
||||
msg := make([]byte, 88+lm_len+nt_len+domain_len+user_len+workstation_len)
|
||||
copy(msg, []byte("NTLMSSP\x00"))
|
||||
binary.LittleEndian.PutUint32(msg[8:], _AUTHENTICATE_MESSAGE)
|
||||
|
||||
// Lm Challenge Response Fields
|
||||
binary.LittleEndian.PutUint16(msg[12:], uint16(lm_len))
|
||||
binary.LittleEndian.PutUint16(msg[14:], uint16(lm_len))
|
||||
binary.LittleEndian.PutUint32(msg[16:], 88)
|
||||
|
||||
// Nt Challenge Response Fields
|
||||
binary.LittleEndian.PutUint16(msg[20:], uint16(nt_len))
|
||||
binary.LittleEndian.PutUint16(msg[22:], uint16(nt_len))
|
||||
binary.LittleEndian.PutUint32(msg[24:], uint32(88+lm_len))
|
||||
|
||||
// Domain Name Fields
|
||||
binary.LittleEndian.PutUint16(msg[28:], uint16(domain_len))
|
||||
binary.LittleEndian.PutUint16(msg[30:], uint16(domain_len))
|
||||
binary.LittleEndian.PutUint32(msg[32:], uint32(88+lm_len+nt_len))
|
||||
|
||||
// User Name Fields
|
||||
binary.LittleEndian.PutUint16(msg[36:], uint16(user_len))
|
||||
binary.LittleEndian.PutUint16(msg[38:], uint16(user_len))
|
||||
binary.LittleEndian.PutUint32(msg[40:], uint32(88+lm_len+nt_len+domain_len))
|
||||
|
||||
// Workstation Fields
|
||||
binary.LittleEndian.PutUint16(msg[44:], uint16(workstation_len))
|
||||
binary.LittleEndian.PutUint16(msg[46:], uint16(workstation_len))
|
||||
binary.LittleEndian.PutUint32(msg[48:], uint32(88+lm_len+nt_len+domain_len+user_len))
|
||||
|
||||
// Encrypted Random Session Key Fields
|
||||
binary.LittleEndian.PutUint16(msg[52:], 0)
|
||||
binary.LittleEndian.PutUint16(msg[54:], 0)
|
||||
binary.LittleEndian.PutUint32(msg[56:], uint32(88+lm_len+nt_len+domain_len+user_len+workstation_len))
|
||||
|
||||
// Negotiate Flags
|
||||
binary.LittleEndian.PutUint32(msg[60:], flags)
|
||||
|
||||
// Version
|
||||
binary.LittleEndian.PutUint32(msg[64:], 0)
|
||||
binary.LittleEndian.PutUint32(msg[68:], 0)
|
||||
|
||||
// MIC
|
||||
binary.LittleEndian.PutUint32(msg[72:], 0)
|
||||
binary.LittleEndian.PutUint32(msg[76:], 0)
|
||||
binary.LittleEndian.PutUint32(msg[88:], 0)
|
||||
binary.LittleEndian.PutUint32(msg[84:], 0)
|
||||
|
||||
// Payload
|
||||
copy(msg[88:], lm)
|
||||
copy(msg[88+lm_len:], nt)
|
||||
copy(msg[88+lm_len+nt_len:], domain16)
|
||||
copy(msg[88+lm_len+nt_len+domain_len:], user16)
|
||||
copy(msg[88+lm_len+nt_len+domain_len+user_len:], workstation16)
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
func (auth *Auth) NextBytes(bytes []byte) ([]byte, error) {
|
||||
signature := string(bytes[0:8])
|
||||
if signature != "NTLMSSP\x00" {
|
||||
return nil, errorNTLM
|
||||
}
|
||||
|
||||
messageTypeIndicator := binary.LittleEndian.Uint32(bytes[8:12])
|
||||
if messageTypeIndicator != _CHALLENGE_MESSAGE {
|
||||
return nil, errorNTLM
|
||||
}
|
||||
|
||||
var challenge [8]byte
|
||||
copy(challenge[:], bytes[24:32])
|
||||
flags := binary.LittleEndian.Uint32(bytes[20:24])
|
||||
if (flags & _NEGOTIATE_EXTENDED_SESSIONSECURITY) != 0 {
|
||||
lm, nt, err := negotiateExtendedSessionSecurity(flags, bytes, challenge, auth.UserName, auth.Password, auth.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buildNTLMResponsePayload(lm, nt, flags, auth.Domain, auth.Workstation, auth.UserName)
|
||||
}
|
||||
|
||||
lm_bytes := lmResponse(challenge, auth.Password)
|
||||
lm := lm_bytes[:]
|
||||
nt_bytes := ntResponse(challenge, auth.Password)
|
||||
nt := nt_bytes[:]
|
||||
|
||||
return buildNTLMResponsePayload(lm, nt, flags, auth.Domain, auth.Workstation, auth.UserName)
|
||||
}
|
||||
|
||||
func (auth *Auth) Free() {
|
||||
}
|
||||
15
vendor/github.com/microsoft/go-mssqldb/integratedauth/ntlm/provider.go
generated
vendored
Normal file
15
vendor/github.com/microsoft/go-mssqldb/integratedauth/ntlm/provider.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package ntlm
|
||||
|
||||
import (
|
||||
"github.com/microsoft/go-mssqldb/integratedauth"
|
||||
)
|
||||
|
||||
// AuthProvider handles NTLM SSPI Windows Authentication
|
||||
var AuthProvider integratedauth.Provider = integratedauth.ProviderFunc(getAuth)
|
||||
|
||||
func init() {
|
||||
err := integratedauth.SetIntegratedAuthenticationProvider("ntlm", AuthProvider)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
15
vendor/github.com/microsoft/go-mssqldb/integratedauth/winsspi/provider.go
generated
vendored
Normal file
15
vendor/github.com/microsoft/go-mssqldb/integratedauth/winsspi/provider.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// +build windows
|
||||
|
||||
package winsspi
|
||||
|
||||
import "github.com/microsoft/go-mssqldb/integratedauth"
|
||||
|
||||
// AuthProvider handles SSPI Windows Authentication via secur32.dll functions
|
||||
var AuthProvider integratedauth.Provider = integratedauth.ProviderFunc(getAuth)
|
||||
|
||||
func init() {
|
||||
err := integratedauth.SetIntegratedAuthenticationProvider("winsspi", AuthProvider)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
273
vendor/github.com/microsoft/go-mssqldb/integratedauth/winsspi/winsspi.go
generated
vendored
Normal file
273
vendor/github.com/microsoft/go-mssqldb/integratedauth/winsspi/winsspi.go
generated
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
// +build windows
|
||||
|
||||
package winsspi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/microsoft/go-mssqldb/integratedauth"
|
||||
"github.com/microsoft/go-mssqldb/msdsn"
|
||||
)
|
||||
|
||||
var (
|
||||
secur32_dll = syscall.NewLazyDLL("secur32.dll")
|
||||
initSecurityInterface = secur32_dll.NewProc("InitSecurityInterfaceW")
|
||||
sec_fn *SecurityFunctionTable
|
||||
)
|
||||
|
||||
func init() {
|
||||
ptr, _, _ := initSecurityInterface.Call()
|
||||
sec_fn = (*SecurityFunctionTable)(unsafe.Pointer(ptr))
|
||||
}
|
||||
|
||||
const (
|
||||
SEC_E_OK = 0
|
||||
SECPKG_CRED_OUTBOUND = 2
|
||||
SEC_WINNT_AUTH_IDENTITY_UNICODE = 2
|
||||
ISC_REQ_DELEGATE = 0x00000001
|
||||
ISC_REQ_REPLAY_DETECT = 0x00000004
|
||||
ISC_REQ_SEQUENCE_DETECT = 0x00000008
|
||||
ISC_REQ_CONFIDENTIALITY = 0x00000010
|
||||
ISC_REQ_CONNECTION = 0x00000800
|
||||
SECURITY_NETWORK_DREP = 0
|
||||
SEC_I_CONTINUE_NEEDED = 0x00090312
|
||||
SEC_I_COMPLETE_NEEDED = 0x00090313
|
||||
SEC_I_COMPLETE_AND_CONTINUE = 0x00090314
|
||||
SECBUFFER_VERSION = 0
|
||||
SECBUFFER_TOKEN = 2
|
||||
NTLMBUF_LEN = 12000
|
||||
)
|
||||
|
||||
const ISC_REQ = ISC_REQ_CONFIDENTIALITY |
|
||||
ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_SEQUENCE_DETECT |
|
||||
ISC_REQ_CONNECTION |
|
||||
ISC_REQ_DELEGATE
|
||||
|
||||
type SecurityFunctionTable struct {
|
||||
dwVersion uint32
|
||||
EnumerateSecurityPackages uintptr
|
||||
QueryCredentialsAttributes uintptr
|
||||
AcquireCredentialsHandle uintptr
|
||||
FreeCredentialsHandle uintptr
|
||||
Reserved2 uintptr
|
||||
InitializeSecurityContext uintptr
|
||||
AcceptSecurityContext uintptr
|
||||
CompleteAuthToken uintptr
|
||||
DeleteSecurityContext uintptr
|
||||
ApplyControlToken uintptr
|
||||
QueryContextAttributes uintptr
|
||||
ImpersonateSecurityContext uintptr
|
||||
RevertSecurityContext uintptr
|
||||
MakeSignature uintptr
|
||||
VerifySignature uintptr
|
||||
FreeContextBuffer uintptr
|
||||
QuerySecurityPackageInfo uintptr
|
||||
Reserved3 uintptr
|
||||
Reserved4 uintptr
|
||||
Reserved5 uintptr
|
||||
Reserved6 uintptr
|
||||
Reserved7 uintptr
|
||||
Reserved8 uintptr
|
||||
QuerySecurityContextToken uintptr
|
||||
EncryptMessage uintptr
|
||||
DecryptMessage uintptr
|
||||
}
|
||||
|
||||
type SEC_WINNT_AUTH_IDENTITY struct {
|
||||
User *uint16
|
||||
UserLength uint32
|
||||
Domain *uint16
|
||||
DomainLength uint32
|
||||
Password *uint16
|
||||
PasswordLength uint32
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
type TimeStamp struct {
|
||||
LowPart uint32
|
||||
HighPart int32
|
||||
}
|
||||
|
||||
type SecHandle struct {
|
||||
dwLower uintptr
|
||||
dwUpper uintptr
|
||||
}
|
||||
|
||||
type SecBuffer struct {
|
||||
cbBuffer uint32
|
||||
BufferType uint32
|
||||
pvBuffer *byte
|
||||
}
|
||||
|
||||
type SecBufferDesc struct {
|
||||
ulVersion uint32
|
||||
cBuffers uint32
|
||||
pBuffers *SecBuffer
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
Domain string
|
||||
UserName string
|
||||
Password string
|
||||
Service string
|
||||
cred SecHandle
|
||||
ctxt SecHandle
|
||||
}
|
||||
|
||||
// getAuth returns an authentication handle Auth to provide authentication content
|
||||
// to mssql.connect
|
||||
func getAuth(config msdsn.Config) (integratedauth.IntegratedAuthenticator, error) {
|
||||
if config.User == "" {
|
||||
return &Auth{Service: config.ServerSPN}, nil
|
||||
}
|
||||
if !strings.ContainsRune(config.User, '\\') {
|
||||
return nil, fmt.Errorf("winsspi : invalid username %v", config.User)
|
||||
}
|
||||
domainUser := strings.SplitN(config.User, "\\", 2)
|
||||
return &Auth{
|
||||
Domain: domainUser[0],
|
||||
UserName: domainUser[1],
|
||||
Password: config.Password,
|
||||
Service: config.ServerSPN,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (auth *Auth) InitialBytes() ([]byte, error) {
|
||||
var identity *SEC_WINNT_AUTH_IDENTITY
|
||||
if auth.UserName != "" {
|
||||
identity = &SEC_WINNT_AUTH_IDENTITY{
|
||||
Flags: SEC_WINNT_AUTH_IDENTITY_UNICODE,
|
||||
Password: syscall.StringToUTF16Ptr(auth.Password),
|
||||
PasswordLength: uint32(len(auth.Password)),
|
||||
Domain: syscall.StringToUTF16Ptr(auth.Domain),
|
||||
DomainLength: uint32(len(auth.Domain)),
|
||||
User: syscall.StringToUTF16Ptr(auth.UserName),
|
||||
UserLength: uint32(len(auth.UserName)),
|
||||
}
|
||||
}
|
||||
var ts TimeStamp
|
||||
sec_ok, _, _ := syscall.Syscall9(sec_fn.AcquireCredentialsHandle,
|
||||
9,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Negotiate"))),
|
||||
SECPKG_CRED_OUTBOUND,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(identity)),
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&auth.cred)),
|
||||
uintptr(unsafe.Pointer(&ts)))
|
||||
if sec_ok != SEC_E_OK {
|
||||
return nil, fmt.Errorf("AcquireCredentialsHandle failed %x", sec_ok)
|
||||
}
|
||||
|
||||
var buf SecBuffer
|
||||
var desc SecBufferDesc
|
||||
desc.ulVersion = SECBUFFER_VERSION
|
||||
desc.cBuffers = 1
|
||||
desc.pBuffers = &buf
|
||||
|
||||
outbuf := make([]byte, NTLMBUF_LEN)
|
||||
buf.cbBuffer = NTLMBUF_LEN
|
||||
buf.BufferType = SECBUFFER_TOKEN
|
||||
buf.pvBuffer = &outbuf[0]
|
||||
|
||||
var attrs uint32
|
||||
sec_ok, _, _ = syscall.Syscall12(sec_fn.InitializeSecurityContext,
|
||||
12,
|
||||
uintptr(unsafe.Pointer(&auth.cred)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))),
|
||||
ISC_REQ,
|
||||
0,
|
||||
SECURITY_NETWORK_DREP,
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&auth.ctxt)),
|
||||
uintptr(unsafe.Pointer(&desc)),
|
||||
uintptr(unsafe.Pointer(&attrs)),
|
||||
uintptr(unsafe.Pointer(&ts)))
|
||||
if sec_ok == SEC_I_COMPLETE_AND_CONTINUE ||
|
||||
sec_ok == SEC_I_COMPLETE_NEEDED {
|
||||
syscall.Syscall6(sec_fn.CompleteAuthToken,
|
||||
2,
|
||||
uintptr(unsafe.Pointer(&auth.ctxt)),
|
||||
uintptr(unsafe.Pointer(&desc)),
|
||||
0, 0, 0, 0)
|
||||
} else if sec_ok != SEC_E_OK &&
|
||||
sec_ok != SEC_I_CONTINUE_NEEDED {
|
||||
syscall.Syscall6(sec_fn.FreeCredentialsHandle,
|
||||
1,
|
||||
uintptr(unsafe.Pointer(&auth.cred)),
|
||||
0, 0, 0, 0, 0)
|
||||
return nil, fmt.Errorf("InitialBytes InitializeSecurityContext failed %x", sec_ok)
|
||||
}
|
||||
return outbuf[:buf.cbBuffer], nil
|
||||
}
|
||||
|
||||
func (auth *Auth) NextBytes(bytes []byte) ([]byte, error) {
|
||||
var in_buf, out_buf SecBuffer
|
||||
var in_desc, out_desc SecBufferDesc
|
||||
|
||||
in_desc.ulVersion = SECBUFFER_VERSION
|
||||
in_desc.cBuffers = 1
|
||||
in_desc.pBuffers = &in_buf
|
||||
|
||||
out_desc.ulVersion = SECBUFFER_VERSION
|
||||
out_desc.cBuffers = 1
|
||||
out_desc.pBuffers = &out_buf
|
||||
|
||||
in_buf.BufferType = SECBUFFER_TOKEN
|
||||
in_buf.pvBuffer = &bytes[0]
|
||||
in_buf.cbBuffer = uint32(len(bytes))
|
||||
|
||||
outbuf := make([]byte, NTLMBUF_LEN)
|
||||
out_buf.BufferType = SECBUFFER_TOKEN
|
||||
out_buf.pvBuffer = &outbuf[0]
|
||||
out_buf.cbBuffer = NTLMBUF_LEN
|
||||
|
||||
var attrs uint32
|
||||
var ts TimeStamp
|
||||
sec_ok, _, _ := syscall.Syscall12(sec_fn.InitializeSecurityContext,
|
||||
12,
|
||||
uintptr(unsafe.Pointer(&auth.cred)),
|
||||
uintptr(unsafe.Pointer(&auth.ctxt)),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))),
|
||||
ISC_REQ,
|
||||
0,
|
||||
SECURITY_NETWORK_DREP,
|
||||
uintptr(unsafe.Pointer(&in_desc)),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&auth.ctxt)),
|
||||
uintptr(unsafe.Pointer(&out_desc)),
|
||||
uintptr(unsafe.Pointer(&attrs)),
|
||||
uintptr(unsafe.Pointer(&ts)))
|
||||
if sec_ok == SEC_I_COMPLETE_AND_CONTINUE ||
|
||||
sec_ok == SEC_I_COMPLETE_NEEDED {
|
||||
syscall.Syscall6(sec_fn.CompleteAuthToken,
|
||||
2,
|
||||
uintptr(unsafe.Pointer(&auth.ctxt)),
|
||||
uintptr(unsafe.Pointer(&out_desc)),
|
||||
0, 0, 0, 0)
|
||||
} else if sec_ok != SEC_E_OK &&
|
||||
sec_ok != SEC_I_CONTINUE_NEEDED {
|
||||
return nil, fmt.Errorf("NextBytes InitializeSecurityContext failed %x", sec_ok)
|
||||
}
|
||||
|
||||
return outbuf[:out_buf.cbBuffer], nil
|
||||
}
|
||||
|
||||
func (auth *Auth) Free() {
|
||||
syscall.Syscall6(sec_fn.DeleteSecurityContext,
|
||||
1,
|
||||
uintptr(unsafe.Pointer(&auth.ctxt)),
|
||||
0, 0, 0, 0, 0)
|
||||
syscall.Syscall6(sec_fn.FreeCredentialsHandle,
|
||||
1,
|
||||
uintptr(unsafe.Pointer(&auth.cred)),
|
||||
0, 0, 0, 0, 0)
|
||||
}
|
||||
119
vendor/github.com/microsoft/go-mssqldb/internal/cp/charset.go
generated
vendored
Normal file
119
vendor/github.com/microsoft/go-mssqldb/internal/cp/charset.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
package cp
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type charsetMap struct {
|
||||
sb [256]rune // single byte runes, -1 for a double byte character lead byte
|
||||
db map[int]rune // double byte runes
|
||||
}
|
||||
|
||||
func collation2charset(col Collation) *charsetMap {
|
||||
// http://msdn.microsoft.com/en-us/library/ms144250.aspx
|
||||
// http://msdn.microsoft.com/en-us/library/ms144250(v=sql.105).aspx
|
||||
switch col.SortId {
|
||||
case 30, 31, 32, 33, 34:
|
||||
return getcp437()
|
||||
case 40, 41, 42, 44, 49, 55, 56, 57, 58, 59, 60, 61:
|
||||
return getcp850()
|
||||
case 50, 51, 52, 53, 54, 71, 72, 73, 74, 75:
|
||||
return getcp1252()
|
||||
case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96:
|
||||
return getcp1250()
|
||||
case 104, 105, 106, 107, 108:
|
||||
return getcp1251()
|
||||
case 112, 113, 114, 121, 124:
|
||||
return getcp1253()
|
||||
case 128, 129, 130:
|
||||
return getcp1254()
|
||||
case 136, 137, 138:
|
||||
return getcp1255()
|
||||
case 144, 145, 146:
|
||||
return getcp1256()
|
||||
case 152, 153, 154, 155, 156, 157, 158, 159, 160:
|
||||
return getcp1257()
|
||||
case 183, 184, 185, 186:
|
||||
return getcp1252()
|
||||
case 192, 193:
|
||||
return getcp932()
|
||||
case 194, 195:
|
||||
return getcp949()
|
||||
case 196, 197:
|
||||
return getcp950()
|
||||
case 198, 199:
|
||||
return getcp936()
|
||||
case 200:
|
||||
return getcp932()
|
||||
case 201:
|
||||
return getcp949()
|
||||
case 202:
|
||||
return getcp950()
|
||||
case 203:
|
||||
return getcp936()
|
||||
case 204, 205, 206:
|
||||
return getcp874()
|
||||
case 210, 211, 212, 213, 214, 215, 216, 217:
|
||||
return getcp1252()
|
||||
}
|
||||
// http://technet.microsoft.com/en-us/library/aa176553(v=sql.80).aspx
|
||||
switch col.getLcid() {
|
||||
case 0x001e, 0x041e:
|
||||
return getcp874()
|
||||
case 0x0411, 0x10411, 0x40411:
|
||||
return getcp932()
|
||||
case 0x0804, 0x1004, 0x20804:
|
||||
return getcp936()
|
||||
case 0x0012, 0x0412:
|
||||
return getcp949()
|
||||
case 0x0404, 0x1404, 0x0c04, 0x7c04, 0x30404, 0x21404:
|
||||
return getcp950()
|
||||
case 0x041c, 0x041a, 0x0405, 0x040e, 0x104e, 0x0415, 0x0418, 0x041b, 0x0424, 0x1040e, 0x0442, 0x081A, 0x141A:
|
||||
return getcp1250()
|
||||
case 0x0423, 0x0402, 0x042f, 0x0419, 0x0c1a, 0x0422, 0x043f, 0x0444, 0x082c, 0x046D, 0x0485, 0x201A:
|
||||
return getcp1251()
|
||||
case 0x0408:
|
||||
return getcp1253()
|
||||
case 0x041f, 0x042c, 0x0443:
|
||||
return getcp1254()
|
||||
case 0x040d:
|
||||
return getcp1255()
|
||||
case 0x0401, 0x0801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x0429, 0x0420, 0x0480, 0x048C:
|
||||
return getcp1256()
|
||||
case 0x0425, 0x0426, 0x0427, 0x0827:
|
||||
return getcp1257()
|
||||
case 0x042a:
|
||||
return getcp1258()
|
||||
case 0x0439, 0x045a, 0x0465, 0x043A, 0x0445, 0x044D, 0x0451, 0x0453, 0x0454, 0x0461, 0x0463, 0x0481:
|
||||
return nil
|
||||
}
|
||||
return getcp1252()
|
||||
}
|
||||
|
||||
func CharsetToUTF8(col Collation, s []byte) string {
|
||||
cm := collation2charset(col)
|
||||
if cm == nil {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
buf := strings.Builder{}
|
||||
buf.Grow(len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
ch := cm.sb[s[i]]
|
||||
if ch == -1 {
|
||||
if i+1 == len(s) {
|
||||
ch = 0xfffd
|
||||
} else {
|
||||
n := int(s[i+1]) + (int(s[i]) << 8)
|
||||
i++
|
||||
var ok bool
|
||||
ch, ok = cm.db[n]
|
||||
if !ok {
|
||||
ch = 0xfffd
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
20
vendor/github.com/microsoft/go-mssqldb/internal/cp/collation.go
generated
vendored
Normal file
20
vendor/github.com/microsoft/go-mssqldb/internal/cp/collation.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package cp
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/dd340437.aspx
|
||||
|
||||
type Collation struct {
|
||||
LcidAndFlags uint32
|
||||
SortId uint8
|
||||
}
|
||||
|
||||
func (c Collation) getLcid() uint32 {
|
||||
return c.LcidAndFlags & 0x000fffff
|
||||
}
|
||||
|
||||
func (c Collation) getFlags() uint32 {
|
||||
return (c.LcidAndFlags & 0x0ff00000) >> 20
|
||||
}
|
||||
|
||||
func (c Collation) getVersion() uint32 {
|
||||
return (c.LcidAndFlags & 0xf0000000) >> 28
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1250.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1250.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1250 *charsetMap = nil
|
||||
cp1250Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1250() *charsetMap {
|
||||
cp1250Once.Do(func() {
|
||||
cp1250 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2030, //PER MILLE SIGN
|
||||
0x0160, //LATIN CAPITAL LETTER S WITH CARON
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0x015A, //LATIN CAPITAL LETTER S WITH ACUTE
|
||||
0x0164, //LATIN CAPITAL LETTER T WITH CARON
|
||||
0x017D, //LATIN CAPITAL LETTER Z WITH CARON
|
||||
0x0179, //LATIN CAPITAL LETTER Z WITH ACUTE
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0x0161, //LATIN SMALL LETTER S WITH CARON
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0x015B, //LATIN SMALL LETTER S WITH ACUTE
|
||||
0x0165, //LATIN SMALL LETTER T WITH CARON
|
||||
0x017E, //LATIN SMALL LETTER Z WITH CARON
|
||||
0x017A, //LATIN SMALL LETTER Z WITH ACUTE
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x02C7, //CARON
|
||||
0x02D8, //BREVE
|
||||
0x0141, //LATIN CAPITAL LETTER L WITH STROKE
|
||||
0x00A4, //CURRENCY SIGN
|
||||
0x0104, //LATIN CAPITAL LETTER A WITH OGONEK
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x00A8, //DIAERESIS
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0x015E, //LATIN CAPITAL LETTER S WITH CEDILLA
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x017B, //LATIN CAPITAL LETTER Z WITH DOT ABOVE
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x02DB, //OGONEK
|
||||
0x0142, //LATIN SMALL LETTER L WITH STROKE
|
||||
0x00B4, //ACUTE ACCENT
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x00B8, //CEDILLA
|
||||
0x0105, //LATIN SMALL LETTER A WITH OGONEK
|
||||
0x015F, //LATIN SMALL LETTER S WITH CEDILLA
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x013D, //LATIN CAPITAL LETTER L WITH CARON
|
||||
0x02DD, //DOUBLE ACUTE ACCENT
|
||||
0x013E, //LATIN SMALL LETTER L WITH CARON
|
||||
0x017C, //LATIN SMALL LETTER Z WITH DOT ABOVE
|
||||
0x0154, //LATIN CAPITAL LETTER R WITH ACUTE
|
||||
0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE
|
||||
0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX
|
||||
0x0102, //LATIN CAPITAL LETTER A WITH BREVE
|
||||
0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
0x0139, //LATIN CAPITAL LETTER L WITH ACUTE
|
||||
0x0106, //LATIN CAPITAL LETTER C WITH ACUTE
|
||||
0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
0x010C, //LATIN CAPITAL LETTER C WITH CARON
|
||||
0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0x0118, //LATIN CAPITAL LETTER E WITH OGONEK
|
||||
0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS
|
||||
0x011A, //LATIN CAPITAL LETTER E WITH CARON
|
||||
0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE
|
||||
0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX
|
||||
0x010E, //LATIN CAPITAL LETTER D WITH CARON
|
||||
0x0110, //LATIN CAPITAL LETTER D WITH STROKE
|
||||
0x0143, //LATIN CAPITAL LETTER N WITH ACUTE
|
||||
0x0147, //LATIN CAPITAL LETTER N WITH CARON
|
||||
0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE
|
||||
0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX
|
||||
0x0150, //LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
|
||||
0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
0x00D7, //MULTIPLICATION SIGN
|
||||
0x0158, //LATIN CAPITAL LETTER R WITH CARON
|
||||
0x016E, //LATIN CAPITAL LETTER U WITH RING ABOVE
|
||||
0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE
|
||||
0x0170, //LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
|
||||
0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
0x00DD, //LATIN CAPITAL LETTER Y WITH ACUTE
|
||||
0x0162, //LATIN CAPITAL LETTER T WITH CEDILLA
|
||||
0x00DF, //LATIN SMALL LETTER SHARP S
|
||||
0x0155, //LATIN SMALL LETTER R WITH ACUTE
|
||||
0x00E1, //LATIN SMALL LETTER A WITH ACUTE
|
||||
0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
0x0103, //LATIN SMALL LETTER A WITH BREVE
|
||||
0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS
|
||||
0x013A, //LATIN SMALL LETTER L WITH ACUTE
|
||||
0x0107, //LATIN SMALL LETTER C WITH ACUTE
|
||||
0x00E7, //LATIN SMALL LETTER C WITH CEDILLA
|
||||
0x010D, //LATIN SMALL LETTER C WITH CARON
|
||||
0x00E9, //LATIN SMALL LETTER E WITH ACUTE
|
||||
0x0119, //LATIN SMALL LETTER E WITH OGONEK
|
||||
0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0x011B, //LATIN SMALL LETTER E WITH CARON
|
||||
0x00ED, //LATIN SMALL LETTER I WITH ACUTE
|
||||
0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
0x010F, //LATIN SMALL LETTER D WITH CARON
|
||||
0x0111, //LATIN SMALL LETTER D WITH STROKE
|
||||
0x0144, //LATIN SMALL LETTER N WITH ACUTE
|
||||
0x0148, //LATIN SMALL LETTER N WITH CARON
|
||||
0x00F3, //LATIN SMALL LETTER O WITH ACUTE
|
||||
0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
0x0151, //LATIN SMALL LETTER O WITH DOUBLE ACUTE
|
||||
0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0x00F7, //DIVISION SIGN
|
||||
0x0159, //LATIN SMALL LETTER R WITH CARON
|
||||
0x016F, //LATIN SMALL LETTER U WITH RING ABOVE
|
||||
0x00FA, //LATIN SMALL LETTER U WITH ACUTE
|
||||
0x0171, //LATIN SMALL LETTER U WITH DOUBLE ACUTE
|
||||
0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x00FD, //LATIN SMALL LETTER Y WITH ACUTE
|
||||
0x0163, //LATIN SMALL LETTER T WITH CEDILLA
|
||||
0x02D9, //DOT ABOVE
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1250
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1251.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1251.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1251 *charsetMap = nil
|
||||
cp1251Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1251() *charsetMap {
|
||||
cp1251Once.Do(func() {
|
||||
cp1251 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x0402, //CYRILLIC CAPITAL LETTER DJE
|
||||
0x0403, //CYRILLIC CAPITAL LETTER GJE
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0x0453, //CYRILLIC SMALL LETTER GJE
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0x20AC, //EURO SIGN
|
||||
0x2030, //PER MILLE SIGN
|
||||
0x0409, //CYRILLIC CAPITAL LETTER LJE
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0x040A, //CYRILLIC CAPITAL LETTER NJE
|
||||
0x040C, //CYRILLIC CAPITAL LETTER KJE
|
||||
0x040B, //CYRILLIC CAPITAL LETTER TSHE
|
||||
0x040F, //CYRILLIC CAPITAL LETTER DZHE
|
||||
0x0452, //CYRILLIC SMALL LETTER DJE
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0x0459, //CYRILLIC SMALL LETTER LJE
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0x045A, //CYRILLIC SMALL LETTER NJE
|
||||
0x045C, //CYRILLIC SMALL LETTER KJE
|
||||
0x045B, //CYRILLIC SMALL LETTER TSHE
|
||||
0x045F, //CYRILLIC SMALL LETTER DZHE
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x040E, //CYRILLIC CAPITAL LETTER SHORT U
|
||||
0x045E, //CYRILLIC SMALL LETTER SHORT U
|
||||
0x0408, //CYRILLIC CAPITAL LETTER JE
|
||||
0x00A4, //CURRENCY SIGN
|
||||
0x0490, //CYRILLIC CAPITAL LETTER GHE WITH UPTURN
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x0401, //CYRILLIC CAPITAL LETTER IO
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0x0404, //CYRILLIC CAPITAL LETTER UKRAINIAN IE
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x0407, //CYRILLIC CAPITAL LETTER YI
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x0406, //CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
|
||||
0x0456, //CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
|
||||
0x0491, //CYRILLIC SMALL LETTER GHE WITH UPTURN
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x0451, //CYRILLIC SMALL LETTER IO
|
||||
0x2116, //NUMERO SIGN
|
||||
0x0454, //CYRILLIC SMALL LETTER UKRAINIAN IE
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x0458, //CYRILLIC SMALL LETTER JE
|
||||
0x0405, //CYRILLIC CAPITAL LETTER DZE
|
||||
0x0455, //CYRILLIC SMALL LETTER DZE
|
||||
0x0457, //CYRILLIC SMALL LETTER YI
|
||||
0x0410, //CYRILLIC CAPITAL LETTER A
|
||||
0x0411, //CYRILLIC CAPITAL LETTER BE
|
||||
0x0412, //CYRILLIC CAPITAL LETTER VE
|
||||
0x0413, //CYRILLIC CAPITAL LETTER GHE
|
||||
0x0414, //CYRILLIC CAPITAL LETTER DE
|
||||
0x0415, //CYRILLIC CAPITAL LETTER IE
|
||||
0x0416, //CYRILLIC CAPITAL LETTER ZHE
|
||||
0x0417, //CYRILLIC CAPITAL LETTER ZE
|
||||
0x0418, //CYRILLIC CAPITAL LETTER I
|
||||
0x0419, //CYRILLIC CAPITAL LETTER SHORT I
|
||||
0x041A, //CYRILLIC CAPITAL LETTER KA
|
||||
0x041B, //CYRILLIC CAPITAL LETTER EL
|
||||
0x041C, //CYRILLIC CAPITAL LETTER EM
|
||||
0x041D, //CYRILLIC CAPITAL LETTER EN
|
||||
0x041E, //CYRILLIC CAPITAL LETTER O
|
||||
0x041F, //CYRILLIC CAPITAL LETTER PE
|
||||
0x0420, //CYRILLIC CAPITAL LETTER ER
|
||||
0x0421, //CYRILLIC CAPITAL LETTER ES
|
||||
0x0422, //CYRILLIC CAPITAL LETTER TE
|
||||
0x0423, //CYRILLIC CAPITAL LETTER U
|
||||
0x0424, //CYRILLIC CAPITAL LETTER EF
|
||||
0x0425, //CYRILLIC CAPITAL LETTER HA
|
||||
0x0426, //CYRILLIC CAPITAL LETTER TSE
|
||||
0x0427, //CYRILLIC CAPITAL LETTER CHE
|
||||
0x0428, //CYRILLIC CAPITAL LETTER SHA
|
||||
0x0429, //CYRILLIC CAPITAL LETTER SHCHA
|
||||
0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN
|
||||
0x042B, //CYRILLIC CAPITAL LETTER YERU
|
||||
0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN
|
||||
0x042D, //CYRILLIC CAPITAL LETTER E
|
||||
0x042E, //CYRILLIC CAPITAL LETTER YU
|
||||
0x042F, //CYRILLIC CAPITAL LETTER YA
|
||||
0x0430, //CYRILLIC SMALL LETTER A
|
||||
0x0431, //CYRILLIC SMALL LETTER BE
|
||||
0x0432, //CYRILLIC SMALL LETTER VE
|
||||
0x0433, //CYRILLIC SMALL LETTER GHE
|
||||
0x0434, //CYRILLIC SMALL LETTER DE
|
||||
0x0435, //CYRILLIC SMALL LETTER IE
|
||||
0x0436, //CYRILLIC SMALL LETTER ZHE
|
||||
0x0437, //CYRILLIC SMALL LETTER ZE
|
||||
0x0438, //CYRILLIC SMALL LETTER I
|
||||
0x0439, //CYRILLIC SMALL LETTER SHORT I
|
||||
0x043A, //CYRILLIC SMALL LETTER KA
|
||||
0x043B, //CYRILLIC SMALL LETTER EL
|
||||
0x043C, //CYRILLIC SMALL LETTER EM
|
||||
0x043D, //CYRILLIC SMALL LETTER EN
|
||||
0x043E, //CYRILLIC SMALL LETTER O
|
||||
0x043F, //CYRILLIC SMALL LETTER PE
|
||||
0x0440, //CYRILLIC SMALL LETTER ER
|
||||
0x0441, //CYRILLIC SMALL LETTER ES
|
||||
0x0442, //CYRILLIC SMALL LETTER TE
|
||||
0x0443, //CYRILLIC SMALL LETTER U
|
||||
0x0444, //CYRILLIC SMALL LETTER EF
|
||||
0x0445, //CYRILLIC SMALL LETTER HA
|
||||
0x0446, //CYRILLIC SMALL LETTER TSE
|
||||
0x0447, //CYRILLIC SMALL LETTER CHE
|
||||
0x0448, //CYRILLIC SMALL LETTER SHA
|
||||
0x0449, //CYRILLIC SMALL LETTER SHCHA
|
||||
0x044A, //CYRILLIC SMALL LETTER HARD SIGN
|
||||
0x044B, //CYRILLIC SMALL LETTER YERU
|
||||
0x044C, //CYRILLIC SMALL LETTER SOFT SIGN
|
||||
0x044D, //CYRILLIC SMALL LETTER E
|
||||
0x044E, //CYRILLIC SMALL LETTER YU
|
||||
0x044F, //CYRILLIC SMALL LETTER YA
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1251
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1252.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1252.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1252 *charsetMap = nil
|
||||
cp1252Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1252() *charsetMap {
|
||||
cp1252Once.Do(func() {
|
||||
cp1252 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0x0192, //LATIN SMALL LETTER F WITH HOOK
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||
0x2030, //PER MILLE SIGN
|
||||
0x0160, //LATIN CAPITAL LETTER S WITH CARON
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0x0152, //LATIN CAPITAL LIGATURE OE
|
||||
0xFFFD, //UNDEFINED
|
||||
0x017D, //LATIN CAPITAL LETTER Z WITH CARON
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0x02DC, //SMALL TILDE
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0x0161, //LATIN SMALL LETTER S WITH CARON
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0x0153, //LATIN SMALL LIGATURE OE
|
||||
0xFFFD, //UNDEFINED
|
||||
0x017E, //LATIN SMALL LETTER Z WITH CARON
|
||||
0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x00A1, //INVERTED EXCLAMATION MARK
|
||||
0x00A2, //CENT SIGN
|
||||
0x00A3, //POUND SIGN
|
||||
0x00A4, //CURRENCY SIGN
|
||||
0x00A5, //YEN SIGN
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x00A8, //DIAERESIS
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0x00AA, //FEMININE ORDINAL INDICATOR
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x00AF, //MACRON
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x00B2, //SUPERSCRIPT TWO
|
||||
0x00B3, //SUPERSCRIPT THREE
|
||||
0x00B4, //ACUTE ACCENT
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x00B8, //CEDILLA
|
||||
0x00B9, //SUPERSCRIPT ONE
|
||||
0x00BA, //MASCULINE ORDINAL INDICATOR
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00BC, //VULGAR FRACTION ONE QUARTER
|
||||
0x00BD, //VULGAR FRACTION ONE HALF
|
||||
0x00BE, //VULGAR FRACTION THREE QUARTERS
|
||||
0x00BF, //INVERTED QUESTION MARK
|
||||
0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE
|
||||
0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE
|
||||
0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX
|
||||
0x00C3, //LATIN CAPITAL LETTER A WITH TILDE
|
||||
0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
0x00C6, //LATIN CAPITAL LETTER AE
|
||||
0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE
|
||||
0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX
|
||||
0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS
|
||||
0x00CC, //LATIN CAPITAL LETTER I WITH GRAVE
|
||||
0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE
|
||||
0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX
|
||||
0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS
|
||||
0x00D0, //LATIN CAPITAL LETTER ETH
|
||||
0x00D1, //LATIN CAPITAL LETTER N WITH TILDE
|
||||
0x00D2, //LATIN CAPITAL LETTER O WITH GRAVE
|
||||
0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE
|
||||
0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX
|
||||
0x00D5, //LATIN CAPITAL LETTER O WITH TILDE
|
||||
0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
0x00D7, //MULTIPLICATION SIGN
|
||||
0x00D8, //LATIN CAPITAL LETTER O WITH STROKE
|
||||
0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE
|
||||
0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE
|
||||
0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX
|
||||
0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
0x00DD, //LATIN CAPITAL LETTER Y WITH ACUTE
|
||||
0x00DE, //LATIN CAPITAL LETTER THORN
|
||||
0x00DF, //LATIN SMALL LETTER SHARP S
|
||||
0x00E0, //LATIN SMALL LETTER A WITH GRAVE
|
||||
0x00E1, //LATIN SMALL LETTER A WITH ACUTE
|
||||
0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
0x00E3, //LATIN SMALL LETTER A WITH TILDE
|
||||
0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS
|
||||
0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE
|
||||
0x00E6, //LATIN SMALL LETTER AE
|
||||
0x00E7, //LATIN SMALL LETTER C WITH CEDILLA
|
||||
0x00E8, //LATIN SMALL LETTER E WITH GRAVE
|
||||
0x00E9, //LATIN SMALL LETTER E WITH ACUTE
|
||||
0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0x00EC, //LATIN SMALL LETTER I WITH GRAVE
|
||||
0x00ED, //LATIN SMALL LETTER I WITH ACUTE
|
||||
0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS
|
||||
0x00F0, //LATIN SMALL LETTER ETH
|
||||
0x00F1, //LATIN SMALL LETTER N WITH TILDE
|
||||
0x00F2, //LATIN SMALL LETTER O WITH GRAVE
|
||||
0x00F3, //LATIN SMALL LETTER O WITH ACUTE
|
||||
0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
0x00F5, //LATIN SMALL LETTER O WITH TILDE
|
||||
0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0x00F7, //DIVISION SIGN
|
||||
0x00F8, //LATIN SMALL LETTER O WITH STROKE
|
||||
0x00F9, //LATIN SMALL LETTER U WITH GRAVE
|
||||
0x00FA, //LATIN SMALL LETTER U WITH ACUTE
|
||||
0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x00FD, //LATIN SMALL LETTER Y WITH ACUTE
|
||||
0x00FE, //LATIN SMALL LETTER THORN
|
||||
0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1252
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1253.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1253.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1253 *charsetMap = nil
|
||||
cp1253Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1253() *charsetMap {
|
||||
cp1253Once.Do(func() {
|
||||
cp1253 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0x0192, //LATIN SMALL LETTER F WITH HOOK
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2030, //PER MILLE SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x0385, //GREEK DIALYTIKA TONOS
|
||||
0x0386, //GREEK CAPITAL LETTER ALPHA WITH TONOS
|
||||
0x00A3, //POUND SIGN
|
||||
0x00A4, //CURRENCY SIGN
|
||||
0x00A5, //YEN SIGN
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x00A8, //DIAERESIS
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x2015, //HORIZONTAL BAR
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x00B2, //SUPERSCRIPT TWO
|
||||
0x00B3, //SUPERSCRIPT THREE
|
||||
0x0384, //GREEK TONOS
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x0388, //GREEK CAPITAL LETTER EPSILON WITH TONOS
|
||||
0x0389, //GREEK CAPITAL LETTER ETA WITH TONOS
|
||||
0x038A, //GREEK CAPITAL LETTER IOTA WITH TONOS
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x038C, //GREEK CAPITAL LETTER OMICRON WITH TONOS
|
||||
0x00BD, //VULGAR FRACTION ONE HALF
|
||||
0x038E, //GREEK CAPITAL LETTER UPSILON WITH TONOS
|
||||
0x038F, //GREEK CAPITAL LETTER OMEGA WITH TONOS
|
||||
0x0390, //GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
|
||||
0x0391, //GREEK CAPITAL LETTER ALPHA
|
||||
0x0392, //GREEK CAPITAL LETTER BETA
|
||||
0x0393, //GREEK CAPITAL LETTER GAMMA
|
||||
0x0394, //GREEK CAPITAL LETTER DELTA
|
||||
0x0395, //GREEK CAPITAL LETTER EPSILON
|
||||
0x0396, //GREEK CAPITAL LETTER ZETA
|
||||
0x0397, //GREEK CAPITAL LETTER ETA
|
||||
0x0398, //GREEK CAPITAL LETTER THETA
|
||||
0x0399, //GREEK CAPITAL LETTER IOTA
|
||||
0x039A, //GREEK CAPITAL LETTER KAPPA
|
||||
0x039B, //GREEK CAPITAL LETTER LAMDA
|
||||
0x039C, //GREEK CAPITAL LETTER MU
|
||||
0x039D, //GREEK CAPITAL LETTER NU
|
||||
0x039E, //GREEK CAPITAL LETTER XI
|
||||
0x039F, //GREEK CAPITAL LETTER OMICRON
|
||||
0x03A0, //GREEK CAPITAL LETTER PI
|
||||
0x03A1, //GREEK CAPITAL LETTER RHO
|
||||
0xFFFD, //UNDEFINED
|
||||
0x03A3, //GREEK CAPITAL LETTER SIGMA
|
||||
0x03A4, //GREEK CAPITAL LETTER TAU
|
||||
0x03A5, //GREEK CAPITAL LETTER UPSILON
|
||||
0x03A6, //GREEK CAPITAL LETTER PHI
|
||||
0x03A7, //GREEK CAPITAL LETTER CHI
|
||||
0x03A8, //GREEK CAPITAL LETTER PSI
|
||||
0x03A9, //GREEK CAPITAL LETTER OMEGA
|
||||
0x03AA, //GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
|
||||
0x03AB, //GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
|
||||
0x03AC, //GREEK SMALL LETTER ALPHA WITH TONOS
|
||||
0x03AD, //GREEK SMALL LETTER EPSILON WITH TONOS
|
||||
0x03AE, //GREEK SMALL LETTER ETA WITH TONOS
|
||||
0x03AF, //GREEK SMALL LETTER IOTA WITH TONOS
|
||||
0x03B0, //GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
|
||||
0x03B1, //GREEK SMALL LETTER ALPHA
|
||||
0x03B2, //GREEK SMALL LETTER BETA
|
||||
0x03B3, //GREEK SMALL LETTER GAMMA
|
||||
0x03B4, //GREEK SMALL LETTER DELTA
|
||||
0x03B5, //GREEK SMALL LETTER EPSILON
|
||||
0x03B6, //GREEK SMALL LETTER ZETA
|
||||
0x03B7, //GREEK SMALL LETTER ETA
|
||||
0x03B8, //GREEK SMALL LETTER THETA
|
||||
0x03B9, //GREEK SMALL LETTER IOTA
|
||||
0x03BA, //GREEK SMALL LETTER KAPPA
|
||||
0x03BB, //GREEK SMALL LETTER LAMDA
|
||||
0x03BC, //GREEK SMALL LETTER MU
|
||||
0x03BD, //GREEK SMALL LETTER NU
|
||||
0x03BE, //GREEK SMALL LETTER XI
|
||||
0x03BF, //GREEK SMALL LETTER OMICRON
|
||||
0x03C0, //GREEK SMALL LETTER PI
|
||||
0x03C1, //GREEK SMALL LETTER RHO
|
||||
0x03C2, //GREEK SMALL LETTER FINAL SIGMA
|
||||
0x03C3, //GREEK SMALL LETTER SIGMA
|
||||
0x03C4, //GREEK SMALL LETTER TAU
|
||||
0x03C5, //GREEK SMALL LETTER UPSILON
|
||||
0x03C6, //GREEK SMALL LETTER PHI
|
||||
0x03C7, //GREEK SMALL LETTER CHI
|
||||
0x03C8, //GREEK SMALL LETTER PSI
|
||||
0x03C9, //GREEK SMALL LETTER OMEGA
|
||||
0x03CA, //GREEK SMALL LETTER IOTA WITH DIALYTIKA
|
||||
0x03CB, //GREEK SMALL LETTER UPSILON WITH DIALYTIKA
|
||||
0x03CC, //GREEK SMALL LETTER OMICRON WITH TONOS
|
||||
0x03CD, //GREEK SMALL LETTER UPSILON WITH TONOS
|
||||
0x03CE, //GREEK SMALL LETTER OMEGA WITH TONOS
|
||||
0xFFFD, //UNDEFINED
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1253
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1254.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1254.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1254 *charsetMap = nil
|
||||
cp1254Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1254() *charsetMap {
|
||||
cp1254Once.Do(func() {
|
||||
cp1254 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0x0192, //LATIN SMALL LETTER F WITH HOOK
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||
0x2030, //PER MILLE SIGN
|
||||
0x0160, //LATIN CAPITAL LETTER S WITH CARON
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0x0152, //LATIN CAPITAL LIGATURE OE
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0x02DC, //SMALL TILDE
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0x0161, //LATIN SMALL LETTER S WITH CARON
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0x0153, //LATIN SMALL LIGATURE OE
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x00A1, //INVERTED EXCLAMATION MARK
|
||||
0x00A2, //CENT SIGN
|
||||
0x00A3, //POUND SIGN
|
||||
0x00A4, //CURRENCY SIGN
|
||||
0x00A5, //YEN SIGN
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x00A8, //DIAERESIS
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0x00AA, //FEMININE ORDINAL INDICATOR
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x00AF, //MACRON
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x00B2, //SUPERSCRIPT TWO
|
||||
0x00B3, //SUPERSCRIPT THREE
|
||||
0x00B4, //ACUTE ACCENT
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x00B8, //CEDILLA
|
||||
0x00B9, //SUPERSCRIPT ONE
|
||||
0x00BA, //MASCULINE ORDINAL INDICATOR
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00BC, //VULGAR FRACTION ONE QUARTER
|
||||
0x00BD, //VULGAR FRACTION ONE HALF
|
||||
0x00BE, //VULGAR FRACTION THREE QUARTERS
|
||||
0x00BF, //INVERTED QUESTION MARK
|
||||
0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE
|
||||
0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE
|
||||
0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX
|
||||
0x00C3, //LATIN CAPITAL LETTER A WITH TILDE
|
||||
0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
0x00C6, //LATIN CAPITAL LETTER AE
|
||||
0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE
|
||||
0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX
|
||||
0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS
|
||||
0x00CC, //LATIN CAPITAL LETTER I WITH GRAVE
|
||||
0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE
|
||||
0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX
|
||||
0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS
|
||||
0x011E, //LATIN CAPITAL LETTER G WITH BREVE
|
||||
0x00D1, //LATIN CAPITAL LETTER N WITH TILDE
|
||||
0x00D2, //LATIN CAPITAL LETTER O WITH GRAVE
|
||||
0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE
|
||||
0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX
|
||||
0x00D5, //LATIN CAPITAL LETTER O WITH TILDE
|
||||
0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
0x00D7, //MULTIPLICATION SIGN
|
||||
0x00D8, //LATIN CAPITAL LETTER O WITH STROKE
|
||||
0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE
|
||||
0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE
|
||||
0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX
|
||||
0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
0x0130, //LATIN CAPITAL LETTER I WITH DOT ABOVE
|
||||
0x015E, //LATIN CAPITAL LETTER S WITH CEDILLA
|
||||
0x00DF, //LATIN SMALL LETTER SHARP S
|
||||
0x00E0, //LATIN SMALL LETTER A WITH GRAVE
|
||||
0x00E1, //LATIN SMALL LETTER A WITH ACUTE
|
||||
0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
0x00E3, //LATIN SMALL LETTER A WITH TILDE
|
||||
0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS
|
||||
0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE
|
||||
0x00E6, //LATIN SMALL LETTER AE
|
||||
0x00E7, //LATIN SMALL LETTER C WITH CEDILLA
|
||||
0x00E8, //LATIN SMALL LETTER E WITH GRAVE
|
||||
0x00E9, //LATIN SMALL LETTER E WITH ACUTE
|
||||
0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0x00EC, //LATIN SMALL LETTER I WITH GRAVE
|
||||
0x00ED, //LATIN SMALL LETTER I WITH ACUTE
|
||||
0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS
|
||||
0x011F, //LATIN SMALL LETTER G WITH BREVE
|
||||
0x00F1, //LATIN SMALL LETTER N WITH TILDE
|
||||
0x00F2, //LATIN SMALL LETTER O WITH GRAVE
|
||||
0x00F3, //LATIN SMALL LETTER O WITH ACUTE
|
||||
0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
0x00F5, //LATIN SMALL LETTER O WITH TILDE
|
||||
0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0x00F7, //DIVISION SIGN
|
||||
0x00F8, //LATIN SMALL LETTER O WITH STROKE
|
||||
0x00F9, //LATIN SMALL LETTER U WITH GRAVE
|
||||
0x00FA, //LATIN SMALL LETTER U WITH ACUTE
|
||||
0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x0131, //LATIN SMALL LETTER DOTLESS I
|
||||
0x015F, //LATIN SMALL LETTER S WITH CEDILLA
|
||||
0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1254
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1255.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1255.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1255 *charsetMap = nil
|
||||
cp1255Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1255() *charsetMap {
|
||||
cp1255Once.Do(func() {
|
||||
cp1255 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0x0192, //LATIN SMALL LETTER F WITH HOOK
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||
0x2030, //PER MILLE SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0x02DC, //SMALL TILDE
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x00A1, //INVERTED EXCLAMATION MARK
|
||||
0x00A2, //CENT SIGN
|
||||
0x00A3, //POUND SIGN
|
||||
0x20AA, //NEW SHEQEL SIGN
|
||||
0x00A5, //YEN SIGN
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x00A8, //DIAERESIS
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0x00D7, //MULTIPLICATION SIGN
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x00AF, //MACRON
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x00B2, //SUPERSCRIPT TWO
|
||||
0x00B3, //SUPERSCRIPT THREE
|
||||
0x00B4, //ACUTE ACCENT
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x00B8, //CEDILLA
|
||||
0x00B9, //SUPERSCRIPT ONE
|
||||
0x00F7, //DIVISION SIGN
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00BC, //VULGAR FRACTION ONE QUARTER
|
||||
0x00BD, //VULGAR FRACTION ONE HALF
|
||||
0x00BE, //VULGAR FRACTION THREE QUARTERS
|
||||
0x00BF, //INVERTED QUESTION MARK
|
||||
0x05B0, //HEBREW POINT SHEVA
|
||||
0x05B1, //HEBREW POINT HATAF SEGOL
|
||||
0x05B2, //HEBREW POINT HATAF PATAH
|
||||
0x05B3, //HEBREW POINT HATAF QAMATS
|
||||
0x05B4, //HEBREW POINT HIRIQ
|
||||
0x05B5, //HEBREW POINT TSERE
|
||||
0x05B6, //HEBREW POINT SEGOL
|
||||
0x05B7, //HEBREW POINT PATAH
|
||||
0x05B8, //HEBREW POINT QAMATS
|
||||
0x05B9, //HEBREW POINT HOLAM
|
||||
0xFFFD, //UNDEFINED
|
||||
0x05BB, //HEBREW POINT QUBUTS
|
||||
0x05BC, //HEBREW POINT DAGESH OR MAPIQ
|
||||
0x05BD, //HEBREW POINT METEG
|
||||
0x05BE, //HEBREW PUNCTUATION MAQAF
|
||||
0x05BF, //HEBREW POINT RAFE
|
||||
0x05C0, //HEBREW PUNCTUATION PASEQ
|
||||
0x05C1, //HEBREW POINT SHIN DOT
|
||||
0x05C2, //HEBREW POINT SIN DOT
|
||||
0x05C3, //HEBREW PUNCTUATION SOF PASUQ
|
||||
0x05F0, //HEBREW LIGATURE YIDDISH DOUBLE VAV
|
||||
0x05F1, //HEBREW LIGATURE YIDDISH VAV YOD
|
||||
0x05F2, //HEBREW LIGATURE YIDDISH DOUBLE YOD
|
||||
0x05F3, //HEBREW PUNCTUATION GERESH
|
||||
0x05F4, //HEBREW PUNCTUATION GERSHAYIM
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x05D0, //HEBREW LETTER ALEF
|
||||
0x05D1, //HEBREW LETTER BET
|
||||
0x05D2, //HEBREW LETTER GIMEL
|
||||
0x05D3, //HEBREW LETTER DALET
|
||||
0x05D4, //HEBREW LETTER HE
|
||||
0x05D5, //HEBREW LETTER VAV
|
||||
0x05D6, //HEBREW LETTER ZAYIN
|
||||
0x05D7, //HEBREW LETTER HET
|
||||
0x05D8, //HEBREW LETTER TET
|
||||
0x05D9, //HEBREW LETTER YOD
|
||||
0x05DA, //HEBREW LETTER FINAL KAF
|
||||
0x05DB, //HEBREW LETTER KAF
|
||||
0x05DC, //HEBREW LETTER LAMED
|
||||
0x05DD, //HEBREW LETTER FINAL MEM
|
||||
0x05DE, //HEBREW LETTER MEM
|
||||
0x05DF, //HEBREW LETTER FINAL NUN
|
||||
0x05E0, //HEBREW LETTER NUN
|
||||
0x05E1, //HEBREW LETTER SAMEKH
|
||||
0x05E2, //HEBREW LETTER AYIN
|
||||
0x05E3, //HEBREW LETTER FINAL PE
|
||||
0x05E4, //HEBREW LETTER PE
|
||||
0x05E5, //HEBREW LETTER FINAL TSADI
|
||||
0x05E6, //HEBREW LETTER TSADI
|
||||
0x05E7, //HEBREW LETTER QOF
|
||||
0x05E8, //HEBREW LETTER RESH
|
||||
0x05E9, //HEBREW LETTER SHIN
|
||||
0x05EA, //HEBREW LETTER TAV
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x200E, //LEFT-TO-RIGHT MARK
|
||||
0x200F, //RIGHT-TO-LEFT MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1255
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1256.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1256.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1256 *charsetMap = nil
|
||||
cp1256Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1256() *charsetMap {
|
||||
cp1256Once.Do(func() {
|
||||
cp1256 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0x067E, //ARABIC LETTER PEH
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0x0192, //LATIN SMALL LETTER F WITH HOOK
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||
0x2030, //PER MILLE SIGN
|
||||
0x0679, //ARABIC LETTER TTEH
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0x0152, //LATIN CAPITAL LIGATURE OE
|
||||
0x0686, //ARABIC LETTER TCHEH
|
||||
0x0698, //ARABIC LETTER JEH
|
||||
0x0688, //ARABIC LETTER DDAL
|
||||
0x06AF, //ARABIC LETTER GAF
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0x06A9, //ARABIC LETTER KEHEH
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0x0691, //ARABIC LETTER RREH
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0x0153, //LATIN SMALL LIGATURE OE
|
||||
0x200C, //ZERO WIDTH NON-JOINER
|
||||
0x200D, //ZERO WIDTH JOINER
|
||||
0x06BA, //ARABIC LETTER NOON GHUNNA
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x060C, //ARABIC COMMA
|
||||
0x00A2, //CENT SIGN
|
||||
0x00A3, //POUND SIGN
|
||||
0x00A4, //CURRENCY SIGN
|
||||
0x00A5, //YEN SIGN
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x00A8, //DIAERESIS
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0x06BE, //ARABIC LETTER HEH DOACHASHMEE
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x00AF, //MACRON
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x00B2, //SUPERSCRIPT TWO
|
||||
0x00B3, //SUPERSCRIPT THREE
|
||||
0x00B4, //ACUTE ACCENT
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x00B8, //CEDILLA
|
||||
0x00B9, //SUPERSCRIPT ONE
|
||||
0x061B, //ARABIC SEMICOLON
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00BC, //VULGAR FRACTION ONE QUARTER
|
||||
0x00BD, //VULGAR FRACTION ONE HALF
|
||||
0x00BE, //VULGAR FRACTION THREE QUARTERS
|
||||
0x061F, //ARABIC QUESTION MARK
|
||||
0x06C1, //ARABIC LETTER HEH GOAL
|
||||
0x0621, //ARABIC LETTER HAMZA
|
||||
0x0622, //ARABIC LETTER ALEF WITH MADDA ABOVE
|
||||
0x0623, //ARABIC LETTER ALEF WITH HAMZA ABOVE
|
||||
0x0624, //ARABIC LETTER WAW WITH HAMZA ABOVE
|
||||
0x0625, //ARABIC LETTER ALEF WITH HAMZA BELOW
|
||||
0x0626, //ARABIC LETTER YEH WITH HAMZA ABOVE
|
||||
0x0627, //ARABIC LETTER ALEF
|
||||
0x0628, //ARABIC LETTER BEH
|
||||
0x0629, //ARABIC LETTER TEH MARBUTA
|
||||
0x062A, //ARABIC LETTER TEH
|
||||
0x062B, //ARABIC LETTER THEH
|
||||
0x062C, //ARABIC LETTER JEEM
|
||||
0x062D, //ARABIC LETTER HAH
|
||||
0x062E, //ARABIC LETTER KHAH
|
||||
0x062F, //ARABIC LETTER DAL
|
||||
0x0630, //ARABIC LETTER THAL
|
||||
0x0631, //ARABIC LETTER REH
|
||||
0x0632, //ARABIC LETTER ZAIN
|
||||
0x0633, //ARABIC LETTER SEEN
|
||||
0x0634, //ARABIC LETTER SHEEN
|
||||
0x0635, //ARABIC LETTER SAD
|
||||
0x0636, //ARABIC LETTER DAD
|
||||
0x00D7, //MULTIPLICATION SIGN
|
||||
0x0637, //ARABIC LETTER TAH
|
||||
0x0638, //ARABIC LETTER ZAH
|
||||
0x0639, //ARABIC LETTER AIN
|
||||
0x063A, //ARABIC LETTER GHAIN
|
||||
0x0640, //ARABIC TATWEEL
|
||||
0x0641, //ARABIC LETTER FEH
|
||||
0x0642, //ARABIC LETTER QAF
|
||||
0x0643, //ARABIC LETTER KAF
|
||||
0x00E0, //LATIN SMALL LETTER A WITH GRAVE
|
||||
0x0644, //ARABIC LETTER LAM
|
||||
0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
0x0645, //ARABIC LETTER MEEM
|
||||
0x0646, //ARABIC LETTER NOON
|
||||
0x0647, //ARABIC LETTER HEH
|
||||
0x0648, //ARABIC LETTER WAW
|
||||
0x00E7, //LATIN SMALL LETTER C WITH CEDILLA
|
||||
0x00E8, //LATIN SMALL LETTER E WITH GRAVE
|
||||
0x00E9, //LATIN SMALL LETTER E WITH ACUTE
|
||||
0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0x0649, //ARABIC LETTER ALEF MAKSURA
|
||||
0x064A, //ARABIC LETTER YEH
|
||||
0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS
|
||||
0x064B, //ARABIC FATHATAN
|
||||
0x064C, //ARABIC DAMMATAN
|
||||
0x064D, //ARABIC KASRATAN
|
||||
0x064E, //ARABIC FATHA
|
||||
0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
0x064F, //ARABIC DAMMA
|
||||
0x0650, //ARABIC KASRA
|
||||
0x00F7, //DIVISION SIGN
|
||||
0x0651, //ARABIC SHADDA
|
||||
0x00F9, //LATIN SMALL LETTER U WITH GRAVE
|
||||
0x0652, //ARABIC SUKUN
|
||||
0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x200E, //LEFT-TO-RIGHT MARK
|
||||
0x200F, //RIGHT-TO-LEFT MARK
|
||||
0x06D2, //ARABIC LETTER YEH BARREE
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1256
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1257.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1257.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1257 *charsetMap = nil
|
||||
cp1257Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1257() *charsetMap {
|
||||
cp1257Once.Do(func() {
|
||||
cp1257 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2030, //PER MILLE SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00A8, //DIAERESIS
|
||||
0x02C7, //CARON
|
||||
0x00B8, //CEDILLA
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00AF, //MACRON
|
||||
0x02DB, //OGONEK
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00A2, //CENT SIGN
|
||||
0x00A3, //POUND SIGN
|
||||
0x00A4, //CURRENCY SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x00D8, //LATIN CAPITAL LETTER O WITH STROKE
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0x0156, //LATIN CAPITAL LETTER R WITH CEDILLA
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x00C6, //LATIN CAPITAL LETTER AE
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x00B2, //SUPERSCRIPT TWO
|
||||
0x00B3, //SUPERSCRIPT THREE
|
||||
0x00B4, //ACUTE ACCENT
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x00F8, //LATIN SMALL LETTER O WITH STROKE
|
||||
0x00B9, //SUPERSCRIPT ONE
|
||||
0x0157, //LATIN SMALL LETTER R WITH CEDILLA
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00BC, //VULGAR FRACTION ONE QUARTER
|
||||
0x00BD, //VULGAR FRACTION ONE HALF
|
||||
0x00BE, //VULGAR FRACTION THREE QUARTERS
|
||||
0x00E6, //LATIN SMALL LETTER AE
|
||||
0x0104, //LATIN CAPITAL LETTER A WITH OGONEK
|
||||
0x012E, //LATIN CAPITAL LETTER I WITH OGONEK
|
||||
0x0100, //LATIN CAPITAL LETTER A WITH MACRON
|
||||
0x0106, //LATIN CAPITAL LETTER C WITH ACUTE
|
||||
0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
0x0118, //LATIN CAPITAL LETTER E WITH OGONEK
|
||||
0x0112, //LATIN CAPITAL LETTER E WITH MACRON
|
||||
0x010C, //LATIN CAPITAL LETTER C WITH CARON
|
||||
0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0x0179, //LATIN CAPITAL LETTER Z WITH ACUTE
|
||||
0x0116, //LATIN CAPITAL LETTER E WITH DOT ABOVE
|
||||
0x0122, //LATIN CAPITAL LETTER G WITH CEDILLA
|
||||
0x0136, //LATIN CAPITAL LETTER K WITH CEDILLA
|
||||
0x012A, //LATIN CAPITAL LETTER I WITH MACRON
|
||||
0x013B, //LATIN CAPITAL LETTER L WITH CEDILLA
|
||||
0x0160, //LATIN CAPITAL LETTER S WITH CARON
|
||||
0x0143, //LATIN CAPITAL LETTER N WITH ACUTE
|
||||
0x0145, //LATIN CAPITAL LETTER N WITH CEDILLA
|
||||
0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE
|
||||
0x014C, //LATIN CAPITAL LETTER O WITH MACRON
|
||||
0x00D5, //LATIN CAPITAL LETTER O WITH TILDE
|
||||
0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
0x00D7, //MULTIPLICATION SIGN
|
||||
0x0172, //LATIN CAPITAL LETTER U WITH OGONEK
|
||||
0x0141, //LATIN CAPITAL LETTER L WITH STROKE
|
||||
0x015A, //LATIN CAPITAL LETTER S WITH ACUTE
|
||||
0x016A, //LATIN CAPITAL LETTER U WITH MACRON
|
||||
0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
0x017B, //LATIN CAPITAL LETTER Z WITH DOT ABOVE
|
||||
0x017D, //LATIN CAPITAL LETTER Z WITH CARON
|
||||
0x00DF, //LATIN SMALL LETTER SHARP S
|
||||
0x0105, //LATIN SMALL LETTER A WITH OGONEK
|
||||
0x012F, //LATIN SMALL LETTER I WITH OGONEK
|
||||
0x0101, //LATIN SMALL LETTER A WITH MACRON
|
||||
0x0107, //LATIN SMALL LETTER C WITH ACUTE
|
||||
0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS
|
||||
0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE
|
||||
0x0119, //LATIN SMALL LETTER E WITH OGONEK
|
||||
0x0113, //LATIN SMALL LETTER E WITH MACRON
|
||||
0x010D, //LATIN SMALL LETTER C WITH CARON
|
||||
0x00E9, //LATIN SMALL LETTER E WITH ACUTE
|
||||
0x017A, //LATIN SMALL LETTER Z WITH ACUTE
|
||||
0x0117, //LATIN SMALL LETTER E WITH DOT ABOVE
|
||||
0x0123, //LATIN SMALL LETTER G WITH CEDILLA
|
||||
0x0137, //LATIN SMALL LETTER K WITH CEDILLA
|
||||
0x012B, //LATIN SMALL LETTER I WITH MACRON
|
||||
0x013C, //LATIN SMALL LETTER L WITH CEDILLA
|
||||
0x0161, //LATIN SMALL LETTER S WITH CARON
|
||||
0x0144, //LATIN SMALL LETTER N WITH ACUTE
|
||||
0x0146, //LATIN SMALL LETTER N WITH CEDILLA
|
||||
0x00F3, //LATIN SMALL LETTER O WITH ACUTE
|
||||
0x014D, //LATIN SMALL LETTER O WITH MACRON
|
||||
0x00F5, //LATIN SMALL LETTER O WITH TILDE
|
||||
0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0x00F7, //DIVISION SIGN
|
||||
0x0173, //LATIN SMALL LETTER U WITH OGONEK
|
||||
0x0142, //LATIN SMALL LETTER L WITH STROKE
|
||||
0x015B, //LATIN SMALL LETTER S WITH ACUTE
|
||||
0x016B, //LATIN SMALL LETTER U WITH MACRON
|
||||
0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x017C, //LATIN SMALL LETTER Z WITH DOT ABOVE
|
||||
0x017E, //LATIN SMALL LETTER Z WITH CARON
|
||||
0x02D9, //DOT ABOVE
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1257
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1258.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp1258.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp1258 *charsetMap = nil
|
||||
cp1258Once sync.Once
|
||||
)
|
||||
|
||||
func getcp1258() *charsetMap {
|
||||
cp1258Once.Do(func() {
|
||||
cp1258 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x201A, //SINGLE LOW-9 QUOTATION MARK
|
||||
0x0192, //LATIN SMALL LETTER F WITH HOOK
|
||||
0x201E, //DOUBLE LOW-9 QUOTATION MARK
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0x2020, //DAGGER
|
||||
0x2021, //DOUBLE DAGGER
|
||||
0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||
0x2030, //PER MILLE SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
0x0152, //LATIN CAPITAL LIGATURE OE
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0x02DC, //SMALL TILDE
|
||||
0x2122, //TRADE MARK SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0x0153, //LATIN SMALL LIGATURE OE
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x00A1, //INVERTED EXCLAMATION MARK
|
||||
0x00A2, //CENT SIGN
|
||||
0x00A3, //POUND SIGN
|
||||
0x00A4, //CURRENCY SIGN
|
||||
0x00A5, //YEN SIGN
|
||||
0x00A6, //BROKEN BAR
|
||||
0x00A7, //SECTION SIGN
|
||||
0x00A8, //DIAERESIS
|
||||
0x00A9, //COPYRIGHT SIGN
|
||||
0x00AA, //FEMININE ORDINAL INDICATOR
|
||||
0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00AC, //NOT SIGN
|
||||
0x00AD, //SOFT HYPHEN
|
||||
0x00AE, //REGISTERED SIGN
|
||||
0x00AF, //MACRON
|
||||
0x00B0, //DEGREE SIGN
|
||||
0x00B1, //PLUS-MINUS SIGN
|
||||
0x00B2, //SUPERSCRIPT TWO
|
||||
0x00B3, //SUPERSCRIPT THREE
|
||||
0x00B4, //ACUTE ACCENT
|
||||
0x00B5, //MICRO SIGN
|
||||
0x00B6, //PILCROW SIGN
|
||||
0x00B7, //MIDDLE DOT
|
||||
0x00B8, //CEDILLA
|
||||
0x00B9, //SUPERSCRIPT ONE
|
||||
0x00BA, //MASCULINE ORDINAL INDICATOR
|
||||
0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00BC, //VULGAR FRACTION ONE QUARTER
|
||||
0x00BD, //VULGAR FRACTION ONE HALF
|
||||
0x00BE, //VULGAR FRACTION THREE QUARTERS
|
||||
0x00BF, //INVERTED QUESTION MARK
|
||||
0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE
|
||||
0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE
|
||||
0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX
|
||||
0x0102, //LATIN CAPITAL LETTER A WITH BREVE
|
||||
0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
0x00C6, //LATIN CAPITAL LETTER AE
|
||||
0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE
|
||||
0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX
|
||||
0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS
|
||||
0x0300, //COMBINING GRAVE ACCENT
|
||||
0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE
|
||||
0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX
|
||||
0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS
|
||||
0x0110, //LATIN CAPITAL LETTER D WITH STROKE
|
||||
0x00D1, //LATIN CAPITAL LETTER N WITH TILDE
|
||||
0x0309, //COMBINING HOOK ABOVE
|
||||
0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE
|
||||
0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX
|
||||
0x01A0, //LATIN CAPITAL LETTER O WITH HORN
|
||||
0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
0x00D7, //MULTIPLICATION SIGN
|
||||
0x00D8, //LATIN CAPITAL LETTER O WITH STROKE
|
||||
0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE
|
||||
0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE
|
||||
0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX
|
||||
0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
0x01AF, //LATIN CAPITAL LETTER U WITH HORN
|
||||
0x0303, //COMBINING TILDE
|
||||
0x00DF, //LATIN SMALL LETTER SHARP S
|
||||
0x00E0, //LATIN SMALL LETTER A WITH GRAVE
|
||||
0x00E1, //LATIN SMALL LETTER A WITH ACUTE
|
||||
0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
0x0103, //LATIN SMALL LETTER A WITH BREVE
|
||||
0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS
|
||||
0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE
|
||||
0x00E6, //LATIN SMALL LETTER AE
|
||||
0x00E7, //LATIN SMALL LETTER C WITH CEDILLA
|
||||
0x00E8, //LATIN SMALL LETTER E WITH GRAVE
|
||||
0x00E9, //LATIN SMALL LETTER E WITH ACUTE
|
||||
0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0x0301, //COMBINING ACUTE ACCENT
|
||||
0x00ED, //LATIN SMALL LETTER I WITH ACUTE
|
||||
0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS
|
||||
0x0111, //LATIN SMALL LETTER D WITH STROKE
|
||||
0x00F1, //LATIN SMALL LETTER N WITH TILDE
|
||||
0x0323, //COMBINING DOT BELOW
|
||||
0x00F3, //LATIN SMALL LETTER O WITH ACUTE
|
||||
0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
0x01A1, //LATIN SMALL LETTER O WITH HORN
|
||||
0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0x00F7, //DIVISION SIGN
|
||||
0x00F8, //LATIN SMALL LETTER O WITH STROKE
|
||||
0x00F9, //LATIN SMALL LETTER U WITH GRAVE
|
||||
0x00FA, //LATIN SMALL LETTER U WITH ACUTE
|
||||
0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x01B0, //LATIN SMALL LETTER U WITH HORN
|
||||
0x20AB, //DONG SIGN
|
||||
0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp1258
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp437.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp437.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp437 *charsetMap = nil
|
||||
cp437Once sync.Once
|
||||
)
|
||||
|
||||
func getcp437() *charsetMap {
|
||||
cp437Once.Do(func() {
|
||||
cp437 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000a, //LINE FEED
|
||||
0x000b, //VERTICAL TABULATION
|
||||
0x000c, //FORM FEED
|
||||
0x000d, //CARRIAGE RETURN
|
||||
0x000e, //SHIFT OUT
|
||||
0x000f, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001a, //SUBSTITUTE
|
||||
0x001b, //ESCAPE
|
||||
0x001c, //FILE SEPARATOR
|
||||
0x001d, //GROUP SEPARATOR
|
||||
0x001e, //RECORD SEPARATOR
|
||||
0x001f, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002a, //ASTERISK
|
||||
0x002b, //PLUS SIGN
|
||||
0x002c, //COMMA
|
||||
0x002d, //HYPHEN-MINUS
|
||||
0x002e, //FULL STOP
|
||||
0x002f, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003a, //COLON
|
||||
0x003b, //SEMICOLON
|
||||
0x003c, //LESS-THAN SIGN
|
||||
0x003d, //EQUALS SIGN
|
||||
0x003e, //GREATER-THAN SIGN
|
||||
0x003f, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004a, //LATIN CAPITAL LETTER J
|
||||
0x004b, //LATIN CAPITAL LETTER K
|
||||
0x004c, //LATIN CAPITAL LETTER L
|
||||
0x004d, //LATIN CAPITAL LETTER M
|
||||
0x004e, //LATIN CAPITAL LETTER N
|
||||
0x004f, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005a, //LATIN CAPITAL LETTER Z
|
||||
0x005b, //LEFT SQUARE BRACKET
|
||||
0x005c, //REVERSE SOLIDUS
|
||||
0x005d, //RIGHT SQUARE BRACKET
|
||||
0x005e, //CIRCUMFLEX ACCENT
|
||||
0x005f, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006a, //LATIN SMALL LETTER J
|
||||
0x006b, //LATIN SMALL LETTER K
|
||||
0x006c, //LATIN SMALL LETTER L
|
||||
0x006d, //LATIN SMALL LETTER M
|
||||
0x006e, //LATIN SMALL LETTER N
|
||||
0x006f, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007a, //LATIN SMALL LETTER Z
|
||||
0x007b, //LEFT CURLY BRACKET
|
||||
0x007c, //VERTICAL LINE
|
||||
0x007d, //RIGHT CURLY BRACKET
|
||||
0x007e, //TILDE
|
||||
0x007f, //DELETE
|
||||
0x00c7, //LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
0x00fc, //LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x00e9, //LATIN SMALL LETTER E WITH ACUTE
|
||||
0x00e2, //LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
0x00e4, //LATIN SMALL LETTER A WITH DIAERESIS
|
||||
0x00e0, //LATIN SMALL LETTER A WITH GRAVE
|
||||
0x00e5, //LATIN SMALL LETTER A WITH RING ABOVE
|
||||
0x00e7, //LATIN SMALL LETTER C WITH CEDILLA
|
||||
0x00ea, //LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
0x00eb, //LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0x00e8, //LATIN SMALL LETTER E WITH GRAVE
|
||||
0x00ef, //LATIN SMALL LETTER I WITH DIAERESIS
|
||||
0x00ee, //LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
0x00ec, //LATIN SMALL LETTER I WITH GRAVE
|
||||
0x00c4, //LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
0x00c5, //LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
0x00c9, //LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0x00e6, //LATIN SMALL LIGATURE AE
|
||||
0x00c6, //LATIN CAPITAL LIGATURE AE
|
||||
0x00f4, //LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
0x00f6, //LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0x00f2, //LATIN SMALL LETTER O WITH GRAVE
|
||||
0x00fb, //LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
0x00f9, //LATIN SMALL LETTER U WITH GRAVE
|
||||
0x00ff, //LATIN SMALL LETTER Y WITH DIAERESIS
|
||||
0x00d6, //LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
0x00dc, //LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
0x00a2, //CENT SIGN
|
||||
0x00a3, //POUND SIGN
|
||||
0x00a5, //YEN SIGN
|
||||
0x20a7, //PESETA SIGN
|
||||
0x0192, //LATIN SMALL LETTER F WITH HOOK
|
||||
0x00e1, //LATIN SMALL LETTER A WITH ACUTE
|
||||
0x00ed, //LATIN SMALL LETTER I WITH ACUTE
|
||||
0x00f3, //LATIN SMALL LETTER O WITH ACUTE
|
||||
0x00fa, //LATIN SMALL LETTER U WITH ACUTE
|
||||
0x00f1, //LATIN SMALL LETTER N WITH TILDE
|
||||
0x00d1, //LATIN CAPITAL LETTER N WITH TILDE
|
||||
0x00aa, //FEMININE ORDINAL INDICATOR
|
||||
0x00ba, //MASCULINE ORDINAL INDICATOR
|
||||
0x00bf, //INVERTED QUESTION MARK
|
||||
0x2310, //REVERSED NOT SIGN
|
||||
0x00ac, //NOT SIGN
|
||||
0x00bd, //VULGAR FRACTION ONE HALF
|
||||
0x00bc, //VULGAR FRACTION ONE QUARTER
|
||||
0x00a1, //INVERTED EXCLAMATION MARK
|
||||
0x00ab, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00bb, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x2591, //LIGHT SHADE
|
||||
0x2592, //MEDIUM SHADE
|
||||
0x2593, //DARK SHADE
|
||||
0x2502, //BOX DRAWINGS LIGHT VERTICAL
|
||||
0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT
|
||||
0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
|
||||
0x2562, //BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
|
||||
0x2556, //BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
|
||||
0x2555, //BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
|
||||
0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT
|
||||
0x2551, //BOX DRAWINGS DOUBLE VERTICAL
|
||||
0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT
|
||||
0x255d, //BOX DRAWINGS DOUBLE UP AND LEFT
|
||||
0x255c, //BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
|
||||
0x255b, //BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
|
||||
0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT
|
||||
0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL
|
||||
0x252c, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
|
||||
0x251c, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
0x2500, //BOX DRAWINGS LIGHT HORIZONTAL
|
||||
0x253c, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
|
||||
0x255e, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
|
||||
0x255f, //BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
|
||||
0x255a, //BOX DRAWINGS DOUBLE UP AND RIGHT
|
||||
0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT
|
||||
0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL
|
||||
0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
|
||||
0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
|
||||
0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL
|
||||
0x256c, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
|
||||
0x2567, //BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
|
||||
0x2568, //BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
|
||||
0x2564, //BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
|
||||
0x2565, //BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
|
||||
0x2559, //BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
|
||||
0x2558, //BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
|
||||
0x2552, //BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
|
||||
0x2553, //BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
|
||||
0x256b, //BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
|
||||
0x256a, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
|
||||
0x2518, //BOX DRAWINGS LIGHT UP AND LEFT
|
||||
0x250c, //BOX DRAWINGS LIGHT DOWN AND RIGHT
|
||||
0x2588, //FULL BLOCK
|
||||
0x2584, //LOWER HALF BLOCK
|
||||
0x258c, //LEFT HALF BLOCK
|
||||
0x2590, //RIGHT HALF BLOCK
|
||||
0x2580, //UPPER HALF BLOCK
|
||||
0x03b1, //GREEK SMALL LETTER ALPHA
|
||||
0x00df, //LATIN SMALL LETTER SHARP S
|
||||
0x0393, //GREEK CAPITAL LETTER GAMMA
|
||||
0x03c0, //GREEK SMALL LETTER PI
|
||||
0x03a3, //GREEK CAPITAL LETTER SIGMA
|
||||
0x03c3, //GREEK SMALL LETTER SIGMA
|
||||
0x00b5, //MICRO SIGN
|
||||
0x03c4, //GREEK SMALL LETTER TAU
|
||||
0x03a6, //GREEK CAPITAL LETTER PHI
|
||||
0x0398, //GREEK CAPITAL LETTER THETA
|
||||
0x03a9, //GREEK CAPITAL LETTER OMEGA
|
||||
0x03b4, //GREEK SMALL LETTER DELTA
|
||||
0x221e, //INFINITY
|
||||
0x03c6, //GREEK SMALL LETTER PHI
|
||||
0x03b5, //GREEK SMALL LETTER EPSILON
|
||||
0x2229, //INTERSECTION
|
||||
0x2261, //IDENTICAL TO
|
||||
0x00b1, //PLUS-MINUS SIGN
|
||||
0x2265, //GREATER-THAN OR EQUAL TO
|
||||
0x2264, //LESS-THAN OR EQUAL TO
|
||||
0x2320, //TOP HALF INTEGRAL
|
||||
0x2321, //BOTTOM HALF INTEGRAL
|
||||
0x00f7, //DIVISION SIGN
|
||||
0x2248, //ALMOST EQUAL TO
|
||||
0x00b0, //DEGREE SIGN
|
||||
0x2219, //BULLET OPERATOR
|
||||
0x00b7, //MIDDLE DOT
|
||||
0x221a, //SQUARE ROOT
|
||||
0x207f, //SUPERSCRIPT LATIN SMALL LETTER N
|
||||
0x00b2, //SUPERSCRIPT TWO
|
||||
0x25a0, //BLACK SQUARE
|
||||
0x00a0, //NO-BREAK SPACE
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp437
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp850.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp850.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp850 *charsetMap = nil
|
||||
cp850Once sync.Once
|
||||
)
|
||||
|
||||
func getcp850() *charsetMap {
|
||||
cp850Once.Do(func() {
|
||||
cp850 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000a, //LINE FEED
|
||||
0x000b, //VERTICAL TABULATION
|
||||
0x000c, //FORM FEED
|
||||
0x000d, //CARRIAGE RETURN
|
||||
0x000e, //SHIFT OUT
|
||||
0x000f, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001a, //SUBSTITUTE
|
||||
0x001b, //ESCAPE
|
||||
0x001c, //FILE SEPARATOR
|
||||
0x001d, //GROUP SEPARATOR
|
||||
0x001e, //RECORD SEPARATOR
|
||||
0x001f, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002a, //ASTERISK
|
||||
0x002b, //PLUS SIGN
|
||||
0x002c, //COMMA
|
||||
0x002d, //HYPHEN-MINUS
|
||||
0x002e, //FULL STOP
|
||||
0x002f, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003a, //COLON
|
||||
0x003b, //SEMICOLON
|
||||
0x003c, //LESS-THAN SIGN
|
||||
0x003d, //EQUALS SIGN
|
||||
0x003e, //GREATER-THAN SIGN
|
||||
0x003f, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004a, //LATIN CAPITAL LETTER J
|
||||
0x004b, //LATIN CAPITAL LETTER K
|
||||
0x004c, //LATIN CAPITAL LETTER L
|
||||
0x004d, //LATIN CAPITAL LETTER M
|
||||
0x004e, //LATIN CAPITAL LETTER N
|
||||
0x004f, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005a, //LATIN CAPITAL LETTER Z
|
||||
0x005b, //LEFT SQUARE BRACKET
|
||||
0x005c, //REVERSE SOLIDUS
|
||||
0x005d, //RIGHT SQUARE BRACKET
|
||||
0x005e, //CIRCUMFLEX ACCENT
|
||||
0x005f, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006a, //LATIN SMALL LETTER J
|
||||
0x006b, //LATIN SMALL LETTER K
|
||||
0x006c, //LATIN SMALL LETTER L
|
||||
0x006d, //LATIN SMALL LETTER M
|
||||
0x006e, //LATIN SMALL LETTER N
|
||||
0x006f, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007a, //LATIN SMALL LETTER Z
|
||||
0x007b, //LEFT CURLY BRACKET
|
||||
0x007c, //VERTICAL LINE
|
||||
0x007d, //RIGHT CURLY BRACKET
|
||||
0x007e, //TILDE
|
||||
0x007f, //DELETE
|
||||
0x00c7, //LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
0x00fc, //LATIN SMALL LETTER U WITH DIAERESIS
|
||||
0x00e9, //LATIN SMALL LETTER E WITH ACUTE
|
||||
0x00e2, //LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
0x00e4, //LATIN SMALL LETTER A WITH DIAERESIS
|
||||
0x00e0, //LATIN SMALL LETTER A WITH GRAVE
|
||||
0x00e5, //LATIN SMALL LETTER A WITH RING ABOVE
|
||||
0x00e7, //LATIN SMALL LETTER C WITH CEDILLA
|
||||
0x00ea, //LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
0x00eb, //LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0x00e8, //LATIN SMALL LETTER E WITH GRAVE
|
||||
0x00ef, //LATIN SMALL LETTER I WITH DIAERESIS
|
||||
0x00ee, //LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
0x00ec, //LATIN SMALL LETTER I WITH GRAVE
|
||||
0x00c4, //LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
0x00c5, //LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
0x00c9, //LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0x00e6, //LATIN SMALL LIGATURE AE
|
||||
0x00c6, //LATIN CAPITAL LIGATURE AE
|
||||
0x00f4, //LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
0x00f6, //LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0x00f2, //LATIN SMALL LETTER O WITH GRAVE
|
||||
0x00fb, //LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
0x00f9, //LATIN SMALL LETTER U WITH GRAVE
|
||||
0x00ff, //LATIN SMALL LETTER Y WITH DIAERESIS
|
||||
0x00d6, //LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
0x00dc, //LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
0x00f8, //LATIN SMALL LETTER O WITH STROKE
|
||||
0x00a3, //POUND SIGN
|
||||
0x00d8, //LATIN CAPITAL LETTER O WITH STROKE
|
||||
0x00d7, //MULTIPLICATION SIGN
|
||||
0x0192, //LATIN SMALL LETTER F WITH HOOK
|
||||
0x00e1, //LATIN SMALL LETTER A WITH ACUTE
|
||||
0x00ed, //LATIN SMALL LETTER I WITH ACUTE
|
||||
0x00f3, //LATIN SMALL LETTER O WITH ACUTE
|
||||
0x00fa, //LATIN SMALL LETTER U WITH ACUTE
|
||||
0x00f1, //LATIN SMALL LETTER N WITH TILDE
|
||||
0x00d1, //LATIN CAPITAL LETTER N WITH TILDE
|
||||
0x00aa, //FEMININE ORDINAL INDICATOR
|
||||
0x00ba, //MASCULINE ORDINAL INDICATOR
|
||||
0x00bf, //INVERTED QUESTION MARK
|
||||
0x00ae, //REGISTERED SIGN
|
||||
0x00ac, //NOT SIGN
|
||||
0x00bd, //VULGAR FRACTION ONE HALF
|
||||
0x00bc, //VULGAR FRACTION ONE QUARTER
|
||||
0x00a1, //INVERTED EXCLAMATION MARK
|
||||
0x00ab, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x00bb, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
0x2591, //LIGHT SHADE
|
||||
0x2592, //MEDIUM SHADE
|
||||
0x2593, //DARK SHADE
|
||||
0x2502, //BOX DRAWINGS LIGHT VERTICAL
|
||||
0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT
|
||||
0x00c1, //LATIN CAPITAL LETTER A WITH ACUTE
|
||||
0x00c2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX
|
||||
0x00c0, //LATIN CAPITAL LETTER A WITH GRAVE
|
||||
0x00a9, //COPYRIGHT SIGN
|
||||
0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT
|
||||
0x2551, //BOX DRAWINGS DOUBLE VERTICAL
|
||||
0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT
|
||||
0x255d, //BOX DRAWINGS DOUBLE UP AND LEFT
|
||||
0x00a2, //CENT SIGN
|
||||
0x00a5, //YEN SIGN
|
||||
0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT
|
||||
0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL
|
||||
0x252c, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
|
||||
0x251c, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
0x2500, //BOX DRAWINGS LIGHT HORIZONTAL
|
||||
0x253c, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
|
||||
0x00e3, //LATIN SMALL LETTER A WITH TILDE
|
||||
0x00c3, //LATIN CAPITAL LETTER A WITH TILDE
|
||||
0x255a, //BOX DRAWINGS DOUBLE UP AND RIGHT
|
||||
0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT
|
||||
0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL
|
||||
0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
|
||||
0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
|
||||
0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL
|
||||
0x256c, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
|
||||
0x00a4, //CURRENCY SIGN
|
||||
0x00f0, //LATIN SMALL LETTER ETH
|
||||
0x00d0, //LATIN CAPITAL LETTER ETH
|
||||
0x00ca, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX
|
||||
0x00cb, //LATIN CAPITAL LETTER E WITH DIAERESIS
|
||||
0x00c8, //LATIN CAPITAL LETTER E WITH GRAVE
|
||||
0x0131, //LATIN SMALL LETTER DOTLESS I
|
||||
0x00cd, //LATIN CAPITAL LETTER I WITH ACUTE
|
||||
0x00ce, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX
|
||||
0x00cf, //LATIN CAPITAL LETTER I WITH DIAERESIS
|
||||
0x2518, //BOX DRAWINGS LIGHT UP AND LEFT
|
||||
0x250c, //BOX DRAWINGS LIGHT DOWN AND RIGHT
|
||||
0x2588, //FULL BLOCK
|
||||
0x2584, //LOWER HALF BLOCK
|
||||
0x00a6, //BROKEN BAR
|
||||
0x00cc, //LATIN CAPITAL LETTER I WITH GRAVE
|
||||
0x2580, //UPPER HALF BLOCK
|
||||
0x00d3, //LATIN CAPITAL LETTER O WITH ACUTE
|
||||
0x00df, //LATIN SMALL LETTER SHARP S
|
||||
0x00d4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX
|
||||
0x00d2, //LATIN CAPITAL LETTER O WITH GRAVE
|
||||
0x00f5, //LATIN SMALL LETTER O WITH TILDE
|
||||
0x00d5, //LATIN CAPITAL LETTER O WITH TILDE
|
||||
0x00b5, //MICRO SIGN
|
||||
0x00fe, //LATIN SMALL LETTER THORN
|
||||
0x00de, //LATIN CAPITAL LETTER THORN
|
||||
0x00da, //LATIN CAPITAL LETTER U WITH ACUTE
|
||||
0x00db, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX
|
||||
0x00d9, //LATIN CAPITAL LETTER U WITH GRAVE
|
||||
0x00fd, //LATIN SMALL LETTER Y WITH ACUTE
|
||||
0x00dd, //LATIN CAPITAL LETTER Y WITH ACUTE
|
||||
0x00af, //MACRON
|
||||
0x00b4, //ACUTE ACCENT
|
||||
0x00ad, //SOFT HYPHEN
|
||||
0x00b1, //PLUS-MINUS SIGN
|
||||
0x2017, //DOUBLE LOW LINE
|
||||
0x00be, //VULGAR FRACTION THREE QUARTERS
|
||||
0x00b6, //PILCROW SIGN
|
||||
0x00a7, //SECTION SIGN
|
||||
0x00f7, //DIVISION SIGN
|
||||
0x00b8, //CEDILLA
|
||||
0x00b0, //DEGREE SIGN
|
||||
0x00a8, //DIAERESIS
|
||||
0x00b7, //MIDDLE DOT
|
||||
0x00b9, //SUPERSCRIPT ONE
|
||||
0x00b3, //SUPERSCRIPT THREE
|
||||
0x00b2, //SUPERSCRIPT TWO
|
||||
0x25a0, //BLACK SQUARE
|
||||
0x00a0, //NO-BREAK SPACE
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp850
|
||||
}
|
||||
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp874.go
generated
vendored
Normal file
274
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp874.go
generated
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
package cp
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
cp874 *charsetMap = nil
|
||||
cp874Once sync.Once
|
||||
)
|
||||
|
||||
func getcp874() *charsetMap {
|
||||
cp874Once.Do(func() {
|
||||
cp874 = &charsetMap{
|
||||
sb: [256]rune{
|
||||
0x0000, //NULL
|
||||
0x0001, //START OF HEADING
|
||||
0x0002, //START OF TEXT
|
||||
0x0003, //END OF TEXT
|
||||
0x0004, //END OF TRANSMISSION
|
||||
0x0005, //ENQUIRY
|
||||
0x0006, //ACKNOWLEDGE
|
||||
0x0007, //BELL
|
||||
0x0008, //BACKSPACE
|
||||
0x0009, //HORIZONTAL TABULATION
|
||||
0x000A, //LINE FEED
|
||||
0x000B, //VERTICAL TABULATION
|
||||
0x000C, //FORM FEED
|
||||
0x000D, //CARRIAGE RETURN
|
||||
0x000E, //SHIFT OUT
|
||||
0x000F, //SHIFT IN
|
||||
0x0010, //DATA LINK ESCAPE
|
||||
0x0011, //DEVICE CONTROL ONE
|
||||
0x0012, //DEVICE CONTROL TWO
|
||||
0x0013, //DEVICE CONTROL THREE
|
||||
0x0014, //DEVICE CONTROL FOUR
|
||||
0x0015, //NEGATIVE ACKNOWLEDGE
|
||||
0x0016, //SYNCHRONOUS IDLE
|
||||
0x0017, //END OF TRANSMISSION BLOCK
|
||||
0x0018, //CANCEL
|
||||
0x0019, //END OF MEDIUM
|
||||
0x001A, //SUBSTITUTE
|
||||
0x001B, //ESCAPE
|
||||
0x001C, //FILE SEPARATOR
|
||||
0x001D, //GROUP SEPARATOR
|
||||
0x001E, //RECORD SEPARATOR
|
||||
0x001F, //UNIT SEPARATOR
|
||||
0x0020, //SPACE
|
||||
0x0021, //EXCLAMATION MARK
|
||||
0x0022, //QUOTATION MARK
|
||||
0x0023, //NUMBER SIGN
|
||||
0x0024, //DOLLAR SIGN
|
||||
0x0025, //PERCENT SIGN
|
||||
0x0026, //AMPERSAND
|
||||
0x0027, //APOSTROPHE
|
||||
0x0028, //LEFT PARENTHESIS
|
||||
0x0029, //RIGHT PARENTHESIS
|
||||
0x002A, //ASTERISK
|
||||
0x002B, //PLUS SIGN
|
||||
0x002C, //COMMA
|
||||
0x002D, //HYPHEN-MINUS
|
||||
0x002E, //FULL STOP
|
||||
0x002F, //SOLIDUS
|
||||
0x0030, //DIGIT ZERO
|
||||
0x0031, //DIGIT ONE
|
||||
0x0032, //DIGIT TWO
|
||||
0x0033, //DIGIT THREE
|
||||
0x0034, //DIGIT FOUR
|
||||
0x0035, //DIGIT FIVE
|
||||
0x0036, //DIGIT SIX
|
||||
0x0037, //DIGIT SEVEN
|
||||
0x0038, //DIGIT EIGHT
|
||||
0x0039, //DIGIT NINE
|
||||
0x003A, //COLON
|
||||
0x003B, //SEMICOLON
|
||||
0x003C, //LESS-THAN SIGN
|
||||
0x003D, //EQUALS SIGN
|
||||
0x003E, //GREATER-THAN SIGN
|
||||
0x003F, //QUESTION MARK
|
||||
0x0040, //COMMERCIAL AT
|
||||
0x0041, //LATIN CAPITAL LETTER A
|
||||
0x0042, //LATIN CAPITAL LETTER B
|
||||
0x0043, //LATIN CAPITAL LETTER C
|
||||
0x0044, //LATIN CAPITAL LETTER D
|
||||
0x0045, //LATIN CAPITAL LETTER E
|
||||
0x0046, //LATIN CAPITAL LETTER F
|
||||
0x0047, //LATIN CAPITAL LETTER G
|
||||
0x0048, //LATIN CAPITAL LETTER H
|
||||
0x0049, //LATIN CAPITAL LETTER I
|
||||
0x004A, //LATIN CAPITAL LETTER J
|
||||
0x004B, //LATIN CAPITAL LETTER K
|
||||
0x004C, //LATIN CAPITAL LETTER L
|
||||
0x004D, //LATIN CAPITAL LETTER M
|
||||
0x004E, //LATIN CAPITAL LETTER N
|
||||
0x004F, //LATIN CAPITAL LETTER O
|
||||
0x0050, //LATIN CAPITAL LETTER P
|
||||
0x0051, //LATIN CAPITAL LETTER Q
|
||||
0x0052, //LATIN CAPITAL LETTER R
|
||||
0x0053, //LATIN CAPITAL LETTER S
|
||||
0x0054, //LATIN CAPITAL LETTER T
|
||||
0x0055, //LATIN CAPITAL LETTER U
|
||||
0x0056, //LATIN CAPITAL LETTER V
|
||||
0x0057, //LATIN CAPITAL LETTER W
|
||||
0x0058, //LATIN CAPITAL LETTER X
|
||||
0x0059, //LATIN CAPITAL LETTER Y
|
||||
0x005A, //LATIN CAPITAL LETTER Z
|
||||
0x005B, //LEFT SQUARE BRACKET
|
||||
0x005C, //REVERSE SOLIDUS
|
||||
0x005D, //RIGHT SQUARE BRACKET
|
||||
0x005E, //CIRCUMFLEX ACCENT
|
||||
0x005F, //LOW LINE
|
||||
0x0060, //GRAVE ACCENT
|
||||
0x0061, //LATIN SMALL LETTER A
|
||||
0x0062, //LATIN SMALL LETTER B
|
||||
0x0063, //LATIN SMALL LETTER C
|
||||
0x0064, //LATIN SMALL LETTER D
|
||||
0x0065, //LATIN SMALL LETTER E
|
||||
0x0066, //LATIN SMALL LETTER F
|
||||
0x0067, //LATIN SMALL LETTER G
|
||||
0x0068, //LATIN SMALL LETTER H
|
||||
0x0069, //LATIN SMALL LETTER I
|
||||
0x006A, //LATIN SMALL LETTER J
|
||||
0x006B, //LATIN SMALL LETTER K
|
||||
0x006C, //LATIN SMALL LETTER L
|
||||
0x006D, //LATIN SMALL LETTER M
|
||||
0x006E, //LATIN SMALL LETTER N
|
||||
0x006F, //LATIN SMALL LETTER O
|
||||
0x0070, //LATIN SMALL LETTER P
|
||||
0x0071, //LATIN SMALL LETTER Q
|
||||
0x0072, //LATIN SMALL LETTER R
|
||||
0x0073, //LATIN SMALL LETTER S
|
||||
0x0074, //LATIN SMALL LETTER T
|
||||
0x0075, //LATIN SMALL LETTER U
|
||||
0x0076, //LATIN SMALL LETTER V
|
||||
0x0077, //LATIN SMALL LETTER W
|
||||
0x0078, //LATIN SMALL LETTER X
|
||||
0x0079, //LATIN SMALL LETTER Y
|
||||
0x007A, //LATIN SMALL LETTER Z
|
||||
0x007B, //LEFT CURLY BRACKET
|
||||
0x007C, //VERTICAL LINE
|
||||
0x007D, //RIGHT CURLY BRACKET
|
||||
0x007E, //TILDE
|
||||
0x007F, //DELETE
|
||||
0x20AC, //EURO SIGN
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2026, //HORIZONTAL ELLIPSIS
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x2018, //LEFT SINGLE QUOTATION MARK
|
||||
0x2019, //RIGHT SINGLE QUOTATION MARK
|
||||
0x201C, //LEFT DOUBLE QUOTATION MARK
|
||||
0x201D, //RIGHT DOUBLE QUOTATION MARK
|
||||
0x2022, //BULLET
|
||||
0x2013, //EN DASH
|
||||
0x2014, //EM DASH
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x00A0, //NO-BREAK SPACE
|
||||
0x0E01, //THAI CHARACTER KO KAI
|
||||
0x0E02, //THAI CHARACTER KHO KHAI
|
||||
0x0E03, //THAI CHARACTER KHO KHUAT
|
||||
0x0E04, //THAI CHARACTER KHO KHWAI
|
||||
0x0E05, //THAI CHARACTER KHO KHON
|
||||
0x0E06, //THAI CHARACTER KHO RAKHANG
|
||||
0x0E07, //THAI CHARACTER NGO NGU
|
||||
0x0E08, //THAI CHARACTER CHO CHAN
|
||||
0x0E09, //THAI CHARACTER CHO CHING
|
||||
0x0E0A, //THAI CHARACTER CHO CHANG
|
||||
0x0E0B, //THAI CHARACTER SO SO
|
||||
0x0E0C, //THAI CHARACTER CHO CHOE
|
||||
0x0E0D, //THAI CHARACTER YO YING
|
||||
0x0E0E, //THAI CHARACTER DO CHADA
|
||||
0x0E0F, //THAI CHARACTER TO PATAK
|
||||
0x0E10, //THAI CHARACTER THO THAN
|
||||
0x0E11, //THAI CHARACTER THO NANGMONTHO
|
||||
0x0E12, //THAI CHARACTER THO PHUTHAO
|
||||
0x0E13, //THAI CHARACTER NO NEN
|
||||
0x0E14, //THAI CHARACTER DO DEK
|
||||
0x0E15, //THAI CHARACTER TO TAO
|
||||
0x0E16, //THAI CHARACTER THO THUNG
|
||||
0x0E17, //THAI CHARACTER THO THAHAN
|
||||
0x0E18, //THAI CHARACTER THO THONG
|
||||
0x0E19, //THAI CHARACTER NO NU
|
||||
0x0E1A, //THAI CHARACTER BO BAIMAI
|
||||
0x0E1B, //THAI CHARACTER PO PLA
|
||||
0x0E1C, //THAI CHARACTER PHO PHUNG
|
||||
0x0E1D, //THAI CHARACTER FO FA
|
||||
0x0E1E, //THAI CHARACTER PHO PHAN
|
||||
0x0E1F, //THAI CHARACTER FO FAN
|
||||
0x0E20, //THAI CHARACTER PHO SAMPHAO
|
||||
0x0E21, //THAI CHARACTER MO MA
|
||||
0x0E22, //THAI CHARACTER YO YAK
|
||||
0x0E23, //THAI CHARACTER RO RUA
|
||||
0x0E24, //THAI CHARACTER RU
|
||||
0x0E25, //THAI CHARACTER LO LING
|
||||
0x0E26, //THAI CHARACTER LU
|
||||
0x0E27, //THAI CHARACTER WO WAEN
|
||||
0x0E28, //THAI CHARACTER SO SALA
|
||||
0x0E29, //THAI CHARACTER SO RUSI
|
||||
0x0E2A, //THAI CHARACTER SO SUA
|
||||
0x0E2B, //THAI CHARACTER HO HIP
|
||||
0x0E2C, //THAI CHARACTER LO CHULA
|
||||
0x0E2D, //THAI CHARACTER O ANG
|
||||
0x0E2E, //THAI CHARACTER HO NOKHUK
|
||||
0x0E2F, //THAI CHARACTER PAIYANNOI
|
||||
0x0E30, //THAI CHARACTER SARA A
|
||||
0x0E31, //THAI CHARACTER MAI HAN-AKAT
|
||||
0x0E32, //THAI CHARACTER SARA AA
|
||||
0x0E33, //THAI CHARACTER SARA AM
|
||||
0x0E34, //THAI CHARACTER SARA I
|
||||
0x0E35, //THAI CHARACTER SARA II
|
||||
0x0E36, //THAI CHARACTER SARA UE
|
||||
0x0E37, //THAI CHARACTER SARA UEE
|
||||
0x0E38, //THAI CHARACTER SARA U
|
||||
0x0E39, //THAI CHARACTER SARA UU
|
||||
0x0E3A, //THAI CHARACTER PHINTHU
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0x0E3F, //THAI CURRENCY SYMBOL BAHT
|
||||
0x0E40, //THAI CHARACTER SARA E
|
||||
0x0E41, //THAI CHARACTER SARA AE
|
||||
0x0E42, //THAI CHARACTER SARA O
|
||||
0x0E43, //THAI CHARACTER SARA AI MAIMUAN
|
||||
0x0E44, //THAI CHARACTER SARA AI MAIMALAI
|
||||
0x0E45, //THAI CHARACTER LAKKHANGYAO
|
||||
0x0E46, //THAI CHARACTER MAIYAMOK
|
||||
0x0E47, //THAI CHARACTER MAITAIKHU
|
||||
0x0E48, //THAI CHARACTER MAI EK
|
||||
0x0E49, //THAI CHARACTER MAI THO
|
||||
0x0E4A, //THAI CHARACTER MAI TRI
|
||||
0x0E4B, //THAI CHARACTER MAI CHATTAWA
|
||||
0x0E4C, //THAI CHARACTER THANTHAKHAT
|
||||
0x0E4D, //THAI CHARACTER NIKHAHIT
|
||||
0x0E4E, //THAI CHARACTER YAMAKKAN
|
||||
0x0E4F, //THAI CHARACTER FONGMAN
|
||||
0x0E50, //THAI DIGIT ZERO
|
||||
0x0E51, //THAI DIGIT ONE
|
||||
0x0E52, //THAI DIGIT TWO
|
||||
0x0E53, //THAI DIGIT THREE
|
||||
0x0E54, //THAI DIGIT FOUR
|
||||
0x0E55, //THAI DIGIT FIVE
|
||||
0x0E56, //THAI DIGIT SIX
|
||||
0x0E57, //THAI DIGIT SEVEN
|
||||
0x0E58, //THAI DIGIT EIGHT
|
||||
0x0E59, //THAI DIGIT NINE
|
||||
0x0E5A, //THAI CHARACTER ANGKHANKHU
|
||||
0x0E5B, //THAI CHARACTER KHOMUT
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
0xFFFD, //UNDEFINED
|
||||
},
|
||||
}
|
||||
})
|
||||
return cp874
|
||||
}
|
||||
8000
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp932.go
generated
vendored
Normal file
8000
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp932.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22067
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp936.go
generated
vendored
Normal file
22067
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp936.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
17324
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp949.go
generated
vendored
Normal file
17324
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp949.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
13779
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp950.go
generated
vendored
Normal file
13779
vendor/github.com/microsoft/go-mssqldb/internal/cp/cp950.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
257
vendor/github.com/microsoft/go-mssqldb/internal/decimal/decimal.go
generated
vendored
Normal file
257
vendor/github.com/microsoft/go-mssqldb/internal/decimal/decimal.go
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
package decimal
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Decimal represents decimal type in the Microsoft Open Specifications: http://msdn.microsoft.com/en-us/library/ee780893.aspx
|
||||
type Decimal struct {
|
||||
integer [4]uint32 // Little-endian
|
||||
positive bool
|
||||
prec uint8
|
||||
scale uint8
|
||||
}
|
||||
|
||||
var (
|
||||
scaletblflt64 [39]float64
|
||||
int10 big.Int
|
||||
int1e5 big.Int
|
||||
)
|
||||
|
||||
func init() {
|
||||
var acc float64 = 1
|
||||
for i := 0; i <= 38; i++ {
|
||||
scaletblflt64[i] = acc
|
||||
acc *= 10
|
||||
}
|
||||
|
||||
int10.SetInt64(10)
|
||||
int1e5.SetInt64(1e5)
|
||||
}
|
||||
|
||||
const autoScale = 100
|
||||
|
||||
// GetInteger gets the ind'th element of the integer array
|
||||
func (d *Decimal) GetInteger(ind uint8) uint32 {
|
||||
return d.integer[ind]
|
||||
}
|
||||
|
||||
// SetInteger sets the ind'th element in the integer array
|
||||
func (d *Decimal) SetInteger(integer uint32, ind uint8) {
|
||||
d.integer[ind] = integer
|
||||
}
|
||||
|
||||
// SetPositive sets the positive member
|
||||
func (d *Decimal) SetPositive(positive bool) {
|
||||
d.positive = positive
|
||||
}
|
||||
|
||||
// SetPrec sets the prec member
|
||||
func (d *Decimal) SetPrec(prec uint8) {
|
||||
d.prec = prec
|
||||
}
|
||||
|
||||
// SetScale sets the scale member
|
||||
func (d *Decimal) SetScale(scale uint8) {
|
||||
d.scale = scale
|
||||
}
|
||||
|
||||
// IsPositive returns true if the Decimal is positive
|
||||
func (d *Decimal) IsPositive() bool {
|
||||
return d.positive
|
||||
}
|
||||
|
||||
// ToFloat64 converts decimal to a float64
|
||||
func (d Decimal) ToFloat64() float64 {
|
||||
val := float64(0)
|
||||
for i := 3; i >= 0; i-- {
|
||||
val *= 0x100000000
|
||||
val += float64(d.integer[i])
|
||||
}
|
||||
if !d.positive {
|
||||
val = -val
|
||||
}
|
||||
if d.scale != 0 {
|
||||
val /= scaletblflt64[d.scale]
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// BigInt converts decimal to a bigint
|
||||
func (d Decimal) BigInt() big.Int {
|
||||
bytes := make([]byte, 16)
|
||||
binary.BigEndian.PutUint32(bytes[0:4], d.integer[3])
|
||||
binary.BigEndian.PutUint32(bytes[4:8], d.integer[2])
|
||||
binary.BigEndian.PutUint32(bytes[8:12], d.integer[1])
|
||||
binary.BigEndian.PutUint32(bytes[12:16], d.integer[0])
|
||||
var x big.Int
|
||||
x.SetBytes(bytes)
|
||||
if !d.positive {
|
||||
x.Neg(&x)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Bytes converts decimal to a scaled byte slice
|
||||
func (d Decimal) Bytes() []byte {
|
||||
x := d.BigInt()
|
||||
return ScaleBytes(x.String(), d.scale)
|
||||
}
|
||||
|
||||
// UnscaledBytes converts decimal to a unscaled byte slice
|
||||
func (d Decimal) UnscaledBytes() []byte {
|
||||
x := d.BigInt()
|
||||
return x.Bytes()
|
||||
}
|
||||
|
||||
// String converts decimal to a string
|
||||
func (d Decimal) String() string {
|
||||
return string(d.Bytes())
|
||||
}
|
||||
|
||||
// Float64ToDecimal converts float64 to decimal
|
||||
func Float64ToDecimal(f float64) (Decimal, error) {
|
||||
return Float64ToDecimalScale(f, autoScale)
|
||||
}
|
||||
|
||||
// Float64ToDecimalScale converts float64 to decimal; user can specify the scale
|
||||
func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) {
|
||||
var dec Decimal
|
||||
if math.IsNaN(f) {
|
||||
return dec, errors.New("NaN")
|
||||
}
|
||||
if math.IsInf(f, 0) {
|
||||
return dec, errors.New("Infinity can't be converted to decimal")
|
||||
}
|
||||
dec.positive = f >= 0
|
||||
if !dec.positive {
|
||||
f = math.Abs(f)
|
||||
}
|
||||
if f > 3.402823669209385e+38 {
|
||||
return dec, errors.New("Float value is out of range")
|
||||
}
|
||||
dec.prec = 20
|
||||
var integer float64
|
||||
for dec.scale = 0; dec.scale <= scale; dec.scale++ {
|
||||
integer = f * scaletblflt64[dec.scale]
|
||||
_, frac := math.Modf(integer)
|
||||
if frac == 0 && scale == autoScale {
|
||||
break
|
||||
}
|
||||
}
|
||||
for i := 0; i < 4; i++ {
|
||||
mod := math.Mod(integer, 0x100000000)
|
||||
integer -= mod
|
||||
integer /= 0x100000000
|
||||
dec.integer[i] = uint32(mod)
|
||||
if mod-math.Trunc(mod) >= 0.5 {
|
||||
dec.integer[i] = uint32(mod) + 1
|
||||
}
|
||||
}
|
||||
return dec, nil
|
||||
}
|
||||
|
||||
// Int64ToDecimalScale converts float64 to decimal; user can specify the scale
|
||||
func Int64ToDecimalScale(v int64, scale uint8) Decimal {
|
||||
positive := v >= 0
|
||||
if !positive {
|
||||
if v == math.MinInt64 {
|
||||
// Special case - can't negate
|
||||
return Decimal{
|
||||
integer: [4]uint32{0, 0x80000000, 0, 0},
|
||||
positive: false,
|
||||
prec: 20,
|
||||
scale: 0,
|
||||
}
|
||||
}
|
||||
v = -v
|
||||
}
|
||||
return Decimal{
|
||||
integer: [4]uint32{uint32(v), uint32(v >> 32), 0, 0},
|
||||
positive: positive,
|
||||
prec: 20,
|
||||
scale: scale,
|
||||
}
|
||||
}
|
||||
|
||||
// StringToDecimalScale converts string to decimal
|
||||
func StringToDecimalScale(v string, outScale uint8) (Decimal, error) {
|
||||
var r big.Int
|
||||
var unscaled string
|
||||
var inScale int
|
||||
|
||||
point := strings.LastIndexByte(v, '.')
|
||||
if point == -1 {
|
||||
inScale = 0
|
||||
unscaled = v
|
||||
} else {
|
||||
inScale = len(v) - point - 1
|
||||
unscaled = v[:point] + v[point+1:]
|
||||
}
|
||||
if inScale > math.MaxUint8 {
|
||||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: scale too large", v)
|
||||
}
|
||||
|
||||
_, ok := r.SetString(unscaled, 10)
|
||||
if !ok {
|
||||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number", v)
|
||||
}
|
||||
|
||||
if inScale > int(outScale) {
|
||||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: scale %d is larger than the scale %d of the target column", v, inScale, outScale)
|
||||
}
|
||||
for inScale < int(outScale) {
|
||||
if int(outScale)-inScale >= 5 {
|
||||
r.Mul(&r, &int1e5)
|
||||
inScale += 5
|
||||
} else {
|
||||
r.Mul(&r, &int10)
|
||||
inScale++
|
||||
}
|
||||
}
|
||||
|
||||
bytes := r.Bytes()
|
||||
if len(bytes) > 16 {
|
||||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: precision too large", v)
|
||||
}
|
||||
var out [4]uint32
|
||||
for i, b := range bytes {
|
||||
pos := len(bytes) - i - 1
|
||||
out[pos/4] += uint32(b) << uint(pos%4*8)
|
||||
}
|
||||
return Decimal{
|
||||
integer: out,
|
||||
positive: r.Sign() >= 0,
|
||||
prec: 20,
|
||||
scale: uint8(inScale),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ScaleBytes converts a stringified decimal to a scaled byte slice
|
||||
func ScaleBytes(s string, scale uint8) []byte {
|
||||
z := make([]byte, 0, len(s)+1)
|
||||
if s[0] == '-' || s[0] == '+' {
|
||||
z = append(z, byte(s[0]))
|
||||
s = s[1:]
|
||||
}
|
||||
pos := len(s) - int(scale)
|
||||
if pos <= 0 {
|
||||
z = append(z, byte('0'))
|
||||
} else if pos > 0 {
|
||||
z = append(z, []byte(s[:pos])...)
|
||||
}
|
||||
if scale > 0 {
|
||||
z = append(z, byte('.'))
|
||||
for pos < 0 {
|
||||
z = append(z, byte('0'))
|
||||
pos++
|
||||
}
|
||||
z = append(z, []byte(s[pos:])...)
|
||||
}
|
||||
return z
|
||||
}
|
||||
20
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/LICENSE.txt
generated
vendored
Normal file
20
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2021 Swisscom (Switzerland) Ltd
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
120
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/algorithms/aead_aes_256_cbc_hmac_sha256.go
generated
vendored
Normal file
120
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/algorithms/aead_aes_256_cbc_hmac_sha256.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
package algorithms
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
|
||||
"github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/crypto"
|
||||
"github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/encryption"
|
||||
"github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/keys"
|
||||
)
|
||||
|
||||
// https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05
|
||||
// https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-TDS/%5bMS-TDS%5d.pdf
|
||||
|
||||
var _ Algorithm = &AeadAes256CbcHmac256Algorithm{}
|
||||
|
||||
type AeadAes256CbcHmac256Algorithm struct {
|
||||
algorithmVersion byte
|
||||
deterministic bool
|
||||
blockSizeBytes int
|
||||
keySizeBytes int
|
||||
minimumCipherTextLengthBytesNoAuthTag int
|
||||
minimumCipherTextLengthBytesWithAuthTag int
|
||||
cek keys.AeadAes256CbcHmac256
|
||||
version []byte
|
||||
versionSize []byte
|
||||
}
|
||||
|
||||
func NewAeadAes256CbcHmac256Algorithm(key keys.AeadAes256CbcHmac256, encType encryption.Type, algorithmVersion byte) AeadAes256CbcHmac256Algorithm {
|
||||
const keySizeBytes = 256 / 8
|
||||
const blockSizeBytes = 16
|
||||
const minimumCipherTextLengthBytesNoAuthTag = 1 + 2*blockSizeBytes
|
||||
const minimumCipherTextLengthBytesWithAuthTag = minimumCipherTextLengthBytesNoAuthTag + keySizeBytes
|
||||
|
||||
a := AeadAes256CbcHmac256Algorithm{
|
||||
algorithmVersion: algorithmVersion,
|
||||
deterministic: encType.Deterministic,
|
||||
blockSizeBytes: blockSizeBytes,
|
||||
keySizeBytes: keySizeBytes,
|
||||
cek: key,
|
||||
minimumCipherTextLengthBytesNoAuthTag: minimumCipherTextLengthBytesNoAuthTag,
|
||||
minimumCipherTextLengthBytesWithAuthTag: minimumCipherTextLengthBytesWithAuthTag,
|
||||
version: []byte{0x01},
|
||||
versionSize: []byte{1},
|
||||
}
|
||||
|
||||
a.version[0] = algorithmVersion
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AeadAes256CbcHmac256Algorithm) Encrypt(cleartext []byte) ([]byte, error) {
|
||||
buf := make([]byte, 0)
|
||||
var iv []byte
|
||||
if a.deterministic {
|
||||
iv = crypto.Sha256Hmac(cleartext, a.cek.IvKey())
|
||||
if len(iv) > a.blockSizeBytes {
|
||||
iv = iv[:a.blockSizeBytes]
|
||||
}
|
||||
} else {
|
||||
iv = make([]byte, a.blockSizeBytes)
|
||||
_, err := rand.Read(iv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
buf = append(buf, a.algorithmVersion)
|
||||
aescdbc := crypto.NewAESCbcPKCS5(a.cek.EncryptionKey(), iv)
|
||||
ciphertext := aescdbc.Encrypt(cleartext)
|
||||
authTag := a.prepareAuthTag(iv, ciphertext)
|
||||
buf = append(buf, authTag...)
|
||||
buf = append(buf, iv...)
|
||||
buf = append(buf, ciphertext...)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (a *AeadAes256CbcHmac256Algorithm) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||
// This algorithm always has the auth tag!
|
||||
minimumCiphertextLength := a.minimumCipherTextLengthBytesWithAuthTag
|
||||
|
||||
if len(ciphertext) < minimumCiphertextLength {
|
||||
return nil, fmt.Errorf("invalid ciphertext length: at least %v bytes expected", minimumCiphertextLength)
|
||||
}
|
||||
|
||||
idx := 0
|
||||
if ciphertext[idx] != a.algorithmVersion {
|
||||
return nil, fmt.Errorf("invalid algorithm version used: %v found but %v expected", ciphertext[idx],
|
||||
a.algorithmVersion)
|
||||
}
|
||||
|
||||
idx++
|
||||
authTag := ciphertext[idx : idx+a.keySizeBytes]
|
||||
idx += a.keySizeBytes
|
||||
|
||||
iv := ciphertext[idx : idx+a.blockSizeBytes]
|
||||
idx += len(iv)
|
||||
|
||||
realCiphertext := ciphertext[idx:]
|
||||
ourAuthTag := a.prepareAuthTag(iv, realCiphertext)
|
||||
|
||||
// bytes.Compare is subject to timing attacks
|
||||
if subtle.ConstantTimeCompare(ourAuthTag, authTag) != 1 {
|
||||
return nil, fmt.Errorf("invalid auth tag")
|
||||
}
|
||||
|
||||
// decrypt
|
||||
aescdbc := crypto.NewAESCbcPKCS5(a.cek.EncryptionKey(), iv)
|
||||
cleartext := aescdbc.Decrypt(realCiphertext)
|
||||
|
||||
return cleartext, nil
|
||||
}
|
||||
|
||||
func (a *AeadAes256CbcHmac256Algorithm) prepareAuthTag(iv []byte, ciphertext []byte) []byte {
|
||||
var input = make([]byte, 0)
|
||||
input = append(input, a.algorithmVersion)
|
||||
input = append(input, iv...)
|
||||
input = append(input, ciphertext...)
|
||||
input = append(input, a.versionSize...)
|
||||
return crypto.Sha256Hmac(input, a.cek.MacKey())
|
||||
}
|
||||
6
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/algorithms/algorithm.go
generated
vendored
Normal file
6
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/algorithms/algorithm.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package algorithms
|
||||
|
||||
type Algorithm interface {
|
||||
Encrypt([]byte) ([]byte, error)
|
||||
Decrypt([]byte) ([]byte, error)
|
||||
}
|
||||
69
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/crypto/aes_cbc_pkcs5.go
generated
vendored
Normal file
69
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/crypto/aes_cbc_pkcs5.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Inspired by: https://gist.github.com/hothero/7d085573f5cb7cdb5801d7adcf66dcf3
|
||||
|
||||
type AESCbcPKCS5 struct {
|
||||
key []byte
|
||||
iv []byte
|
||||
block cipher.Block
|
||||
}
|
||||
|
||||
func NewAESCbcPKCS5(key []byte, iv []byte) AESCbcPKCS5 {
|
||||
a := AESCbcPKCS5{
|
||||
key: key,
|
||||
iv: iv,
|
||||
block: nil,
|
||||
}
|
||||
a.initCipher()
|
||||
return a
|
||||
}
|
||||
|
||||
func (a AESCbcPKCS5) Encrypt(cleartext []byte) (cipherText []byte) {
|
||||
if a.block == nil {
|
||||
a.initCipher()
|
||||
}
|
||||
|
||||
blockMode := cipher.NewCBCEncrypter(a.block, a.iv)
|
||||
paddedCleartext := PKCS5Padding(cleartext, blockMode.BlockSize())
|
||||
cipherText = make([]byte, len(paddedCleartext))
|
||||
blockMode.CryptBlocks(cipherText, paddedCleartext)
|
||||
return
|
||||
}
|
||||
|
||||
func (a AESCbcPKCS5) Decrypt(ciphertext []byte) []byte {
|
||||
if a.block == nil {
|
||||
a.initCipher()
|
||||
}
|
||||
|
||||
blockMode := cipher.NewCBCDecrypter(a.block, a.iv)
|
||||
var cleartext = make([]byte, len(ciphertext))
|
||||
blockMode.CryptBlocks(cleartext, ciphertext)
|
||||
return PKCS5Trim(cleartext)
|
||||
}
|
||||
|
||||
func PKCS5Padding(inArr []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(inArr)%blockSize
|
||||
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(inArr, padText...)
|
||||
}
|
||||
|
||||
func PKCS5Trim(inArr []byte) []byte {
|
||||
padding := inArr[len(inArr)-1]
|
||||
return inArr[:len(inArr)-int(padding)]
|
||||
}
|
||||
|
||||
func (a *AESCbcPKCS5) initCipher() {
|
||||
block, err := aes.NewCipher(a.key)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unable to create cipher: %v", err))
|
||||
}
|
||||
|
||||
a.block = block
|
||||
}
|
||||
12
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/crypto/utils.go
generated
vendored
Normal file
12
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/crypto/utils.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
)
|
||||
|
||||
func Sha256Hmac(input []byte, key []byte) []byte {
|
||||
sha256Hmac := hmac.New(sha256.New, key)
|
||||
sha256Hmac.Write(input)
|
||||
return sha256Hmac.Sum(nil)
|
||||
}
|
||||
37
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/encryption/type.go
generated
vendored
Normal file
37
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/encryption/type.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package encryption
|
||||
|
||||
type Type struct {
|
||||
Deterministic bool
|
||||
Name string
|
||||
Value byte
|
||||
}
|
||||
|
||||
var Plaintext = Type{
|
||||
Deterministic: false,
|
||||
Name: "Plaintext",
|
||||
Value: 0,
|
||||
}
|
||||
|
||||
var Deterministic = Type{
|
||||
Deterministic: true,
|
||||
Name: "Deterministic",
|
||||
Value: 1,
|
||||
}
|
||||
|
||||
var Randomized = Type{
|
||||
Deterministic: false,
|
||||
Name: "Randomized",
|
||||
Value: 2,
|
||||
}
|
||||
|
||||
func From(encType byte) Type {
|
||||
switch encType {
|
||||
case 0:
|
||||
return Plaintext
|
||||
case 1:
|
||||
return Deterministic
|
||||
case 2:
|
||||
return Randomized
|
||||
}
|
||||
return Plaintext
|
||||
}
|
||||
51
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/keys/aead_aes_256_cbc_hmac_256.go
generated
vendored
Normal file
51
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/keys/aead_aes_256_cbc_hmac_256.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/crypto"
|
||||
"github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/utils"
|
||||
)
|
||||
|
||||
var _ Key = &AeadAes256CbcHmac256{}
|
||||
|
||||
type AeadAes256CbcHmac256 struct {
|
||||
rootKey []byte
|
||||
encryptionKey []byte
|
||||
macKey []byte
|
||||
ivKey []byte
|
||||
}
|
||||
|
||||
func NewAeadAes256CbcHmac256(rootKey []byte) AeadAes256CbcHmac256 {
|
||||
const keySize = 256
|
||||
const encryptionKeySaltFormat = "Microsoft SQL Server cell encryption key with encryption algorithm:%v and key length:%v"
|
||||
const macKeySaltFormat = "Microsoft SQL Server cell MAC key with encryption algorithm:%v and key length:%v"
|
||||
const ivKeySaltFormat = "Microsoft SQL Server cell IV key with encryption algorithm:%v and key length:%v"
|
||||
const algorithmName = "AEAD_AES_256_CBC_HMAC_SHA256"
|
||||
|
||||
encryptionKeySalt := utils.ProcessUTF16LE(fmt.Sprintf(encryptionKeySaltFormat, algorithmName, keySize))
|
||||
macKeySalt := utils.ProcessUTF16LE(fmt.Sprintf(macKeySaltFormat, algorithmName, keySize))
|
||||
ivKeySalt := utils.ProcessUTF16LE(fmt.Sprintf(ivKeySaltFormat, algorithmName, keySize))
|
||||
|
||||
return AeadAes256CbcHmac256{
|
||||
rootKey: rootKey,
|
||||
encryptionKey: crypto.Sha256Hmac(encryptionKeySalt, rootKey),
|
||||
macKey: crypto.Sha256Hmac(macKeySalt, rootKey),
|
||||
ivKey: crypto.Sha256Hmac(ivKeySalt, rootKey)}
|
||||
}
|
||||
|
||||
func (a AeadAes256CbcHmac256) IvKey() []byte {
|
||||
return a.ivKey
|
||||
}
|
||||
|
||||
func (a AeadAes256CbcHmac256) MacKey() []byte {
|
||||
return a.macKey
|
||||
}
|
||||
|
||||
func (a AeadAes256CbcHmac256) EncryptionKey() []byte {
|
||||
return a.encryptionKey
|
||||
}
|
||||
|
||||
func (a AeadAes256CbcHmac256) RootKey() []byte {
|
||||
return a.rootKey
|
||||
}
|
||||
5
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/keys/key.go
generated
vendored
Normal file
5
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/keys/key.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
package keys
|
||||
|
||||
type Key interface {
|
||||
RootKey() []byte
|
||||
}
|
||||
18
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/utils/utf16.go
generated
vendored
Normal file
18
vendor/github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/utils/utf16.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
func ConvertUTF16ToLittleEndianBytes(u []uint16) []byte {
|
||||
b := make([]byte, 2*len(u))
|
||||
for index, value := range u {
|
||||
binary.LittleEndian.PutUint16(b[index*2:], value)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func ProcessUTF16LE(inputString string) []byte {
|
||||
return ConvertUTF16ToLittleEndianBytes(utf16.Encode([]rune(inputString)))
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user