Skip to main content

Connections

sqlServer

Commentary

added in 0.10.0

Connects to a SQL Server database instance.

A new transaction will be executedd every 20 ms or 500 rows, whichever happens first. You can override row size/write timing with batchConfigs. 1

Automatic table creation

By default for convenience, any tables ShadowTraffic writes to will be automatically created. This makes it easier to iterate on your generators without flipping back and forth between ShadowTraffic and SQL Server.

ShadowTraffic does this by scanning the structure of your generators and creating a suitable DDL, then executing it on your behalf.

If ShadowTraffic doesn't create the table exactly as you'd want it, you can override each column using the sqlHint function modifier. 2

If the table already exists, but you'd like to clear out any existing data, set tablePolicy to dropAndCreate. 3

Manual table control

If you don't ShadowTraffic to control your tables, you can turn this behavior off by setting tablePolicy to manual in the connection map. It'll then be up to you to make sure your tables exist before trying to write to them. 4

Generating updates and deletes

By default, ShadowTraffic only issues INSERT statements to your tables. But sometimes, it might be useful to issue UPDATE and DELETE statements too.

You can control the statement type by setting the op key on your generator. op must be one of insert, update, or delete.

For the latter two, you must also include a where key on your generator, which contains a map of column name to value. You need this because when you issue an update or a delete, you need to tell SQL Server what rows you want to change. The where map is used to check equality and select rows that match. 5


Examples

Configuring the connection

Basic configuration for SQL Server. Optionally, set batchConfigs to control how frequently transactions are written. In this example, a transaction is executed whenever 500 milliseconds pass or 5000 rows are accumulated—whichever comes first.

{
"connections": {
"sql": {
"kind": "sqlServer",
"connectionConfigs": {
"host": "localhost",
"port": 1433,
"username": "sql-server-user",
"password": "sql-server-pw",
"db": "mydb"
},
"batchConfigs": {
"lingerMs": 500,
"batchRows": 5000
}
}
}
}

Automatic table creation

By default, table sandbox doesn't need to be defined. ShadowTraffic will automatically create it for you.

{
"generators": [
{
"table": "sandbox",
"row": {
"id": {
"_gen": "uuid"
},
"level": {
"_gen": "uniformDistribution",
"bounds": [
1,
10
]
},
"active": {
"_gen": "boolean"
}
}
}
],
"connections": {
"sql": {
"kind": "sqlServer",
"connectionConfigs": {
"host": "localhost",
"port": 1433,
"username": "sql-server-user",
"password": "sql-server-pw",
"db": "mydb"
}
}
}
}

In this case, sandbox will be created like so:

Column_name | Type          | Computed | Length | Prec  | Scale | Nullable | TrimTrailingBlanks | FixedLenNullInSource | Collation
---------------------------------------------------------------------------------------------------
id | nvarchar(max) | no | -1 | | | yes | (n/a) | (n/a) | SQL_Latin1_General_CP1_CI_AS
level | float | no | 8 | 53 | | yes | (n/a) | (n/a) | NULL
active | bit | no | 1 | | | yes | (n/a) | (n/a) | NULL

Automatic table truncation

Use dropAndCreate to automatically clear out any rows in an existing target table.

{
"kind": "sqlServer",
"tablePolicy": "dropAndCreate",
"connectionConfigs": {
"host": "localhost",
"port": 1433,
"username": "sql-server-user",
"password": "sql-server-pw",
"db": "mydb"
}
}

Overriding column types

Use the optional sqlHint function modifier on any generator to override how its column is defined.

{
"table": "sandbox",
"row": {
"id": {
"_gen": "uuid",
"pgHint": "TEXT NOT NULL"
},
"level": {
"_gen": "uniformDistribution",
"bounds": [
1,
10
],
"pgHint": "INTEGER"
},
"active": {
"_gen": "boolean"
}
}
}

Now, sandbox will like this:

Column_name | Type          | Computed | Length | Prec  | Scale | Nullable | TrimTrailingBlanks | FixedLenNullInSource | Collation
---------------------------------------------------------------------------------------------------
id | nvarchar(max) | no | -1 | | | no | (n/a) | (n/a) | SQL_Latin1_General_CP1_CI_AS
level | float | no | 8 | 53 | | yes | (n/a) | (n/a) | NULL
active | bit | no | 1 | | | yes | (n/a) | (n/a) | NULL

Manual table creation

Use manual to prevent ShadowTraffic from automatically creating tables for you. When you do this, your tables must already exist before ShadowTraffic tries to write to them.

{
"kind": "sqlServer",
"tablePolicy": "manual",
"connectionConfigs": {
"host": "localhost",
"port": 1433,
"username": "sql-server-user",
"password": "sql-server-pw",
"db": "mydb"
}
}

Upserts and deletes

Use op and where to issue upserts and deletes. It's up to you to make sure that you don't try to update or delete rows that don't exist.

This example uses fork and stateMachine to generate many simultaneous rows being inserted, updated, and deleted.

In the first state, insertIt, a random value of about 50 is generated. In the second state, updateIt, the value gets updated to one of 1, 5, or 10. Finally, in deleteIt, the entire row is deleted.

id is generated once as a fork key and used as the basis for equality to perform updates and deletes.

{
"table": "sandbox",
"fork": {
"key": {
"_gen": "uuid"
}
},
"row": {
"id": {
"_gen": "var",
"var": "forkKey"
}
},
"stateMachine": {
"_gen": "stateMachine",
"initial": "insertIt",
"transitions": {
"insertIt": "updateIt",
"updateIt": "deleteIt"
},
"states": {
"insertIt": {
"row": {
"value": {
"_gen": "normalDistribution",
"mean": 50,
"sd": 15
}
}
},
"updateIt": {
"op": "update",
"where": {
"id": {
"_gen": "var",
"var": "forkKey"
}
},
"row": {
"value": {
"_gen": "oneOf",
"choices": [
1,
5,
10
]
}
}
},
"deleteIt": {
"op": "delete",
"where": {
"id": {
"_gen": "var",
"var": "forkKey"
}
}
}
}
}
}

A random snapshot of the table might look like:

> select * from sandbox limit 10;
id | value
--------------------------------------+-------
07f217c6-1c82-e1cb-6dd8-fc614ff1a6e3 | 49
83d35207-ac3f-b8a7-fd7e-c82e1bdc3b05 | 10
184a0e26-237f-915b-4d97-5dc1808d91df | 37

Specification

Connection JSON schema

{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "sqlServer"
},
"connectionConfigs": {
"type": "object",
"properties": {
"host": {
"type": "string"
},
"port": {
"type": "integer"
},
"db": {
"type": "string"
},
"username": {
"type": "string"
},
"password": {
"type": "string"
}
},
"required": [
"host",
"port",
"db"
]
},
"batchConfigs": {
"type": "object",
"properties": {
"lingerMs": {
"type": "integer",
"minimum": 0
},
"batchRows": {
"type": "integer",
"minimum": 1
}
}
},
"tablePolicy": {
"type": "string",
"enum": [
"manual",
"create",
"dropAndCreate"
]
}
},
"required": [
"connectionConfigs"
]
}

Generator JSON schema

{
"type": "object",
"properties": {
"connection": {
"type": "string"
},
"name": {
"type": "string"
},
"table": {
"type": "string"
},
"row": {
"type": "object"
},
"op": {
"type": "string",
"enum": [
"insert",
"update",
"delete"
]
},
"where": {
"type": "object"
},
"localConfigs": {
"type": "object",
"properties": {
"throttleMs": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"maxEvents": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaKeyProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
},
"jsonSchemaHint": {
"type": "object"
},
"maxBytes": {
"type": "integer",
"minimum": 1
},
"discard": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": [
"rate"
]
},
"repeat": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"times": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"times"
]
},
"protobufSchemaHint": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
},
"maxHistoryEvents": {
"type": "integer",
"minimum": 0
},
"maxMs": {
"type": "integer",
"minimum": 0
},
"time": {
"type": "integer"
},
"events": {
"type": "object",
"properties": {
"exactly": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"delay": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"ms": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"ms"
]
},
"history": {
"type": "object",
"properties": {
"events": {
"type": "object",
"properties": {
"max": {
"type": "integer",
"minimum": 0
}
}
}
}
},
"avroSchemaHint": {
"type": "object"
},
"throttle": {
"type": "object",
"properties": {
"ms": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"throughput": {
"oneOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"timeMultiplier": {
"oneOf": [
{
"type": "number"
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaValueProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
}
},
"required": [
"table",
"row"
],
"allOf": [
{
"if": {
"properties": {
"op": {
"const": "update"
}
}
},
"then": {
"required": [
"where"
]
}
},
{
"if": {
"properties": {
"op": {
"const": "delete"
}
}
},
"then": {
"required": [
"where"
]
}
}
]
}