Skip to content

Latest commit

 

History

History
159 lines (131 loc) · 5.41 KB

README.md

File metadata and controls

159 lines (131 loc) · 5.41 KB

SQLServer Schema Manager

Introduction

A library for programmatically managing the schema of a SQLServer Database, with two modes of operation:

  • Declare the entire structure of a SQLServer instance in code, and apply it to a target database (automatically determines and executes all diff changes required).
  • Programmatically/interactively inspect the structure of an existing SQLServer instance, and make changes using code instead of SQL.

It can be used in tandem with other tools that manage a DB schema (e.g. an ORM), to manage the features that they do not support (e.g. the database itself, users, partitioning and compression).

Important note: This is a tool I developed for my own purposes many years ago, it has a lot of functionality and works quite well but is not recommended to be used in a production context without some further work.

Installation

This library is not packed or included in any package manager, so you will need to clone the repository and manually include it in your project.

Usage

Declarative Mode

  1. Define your desired server schema:
from sssm.db_entities.declared import Server, Database, Table, Index, ForeignKey, Login, IntegerColumn, VarcharColumn, DateColumn, IdentityColumn, FloatColumn, User

# Currently does not support creating Logins, so these will need to correspond to ones already existing on the server
admin_login = Login('admin')
writer_login = Login('writer', server_roles=['bulkadmin'])
reader_login = Login('reader')

server = Server(
    databases=[
        Database(
            name='MyDatabase',
            owner=admin_login.name,
            data_file_dir=r'D:\MSSQL\DATA',
            log_file_dir=r'D:\MSSQL\LOG',
            data_size=100_000,
            # Can also specify schema name if desired, otherwise default "db" is used
            tables=[
                Table(
                    name='Person',
                    columns=[
                        IdentityColumn(name='ID', primary_key=True),
                        VarcharColumn(name='Name', char_max_len=255),
                        DateColumn(name='DateOfBirth'),
                        IntegerColumn(name='HeightCM'),
                        FloatColumn(name='WeightKG'),
                        IntegerColumn(name='AddressID'),
                    ],
                    indexes=[
                        Index(name='IX_MyTable_Name', columns=['Name'], compression='PAGE'),
                    ],
                    foreign_keys=[
                        ForeignKey(column='AddressID', foreign_table='Address', foreign_column='ID'),
                    ],
                ),
                Table(
                    name='Address',
                    columns=[
                        IdentityColumn(name='ID', primary_key=True),
                        IntegerColumn(name='StreetNumber'),
                        VarcharColumn(name='StreetName', char_max_len=255),
                        VarcharColumn(name='PostCode', char_max_len=6),
                        VarcharColumn(name='State', char_max_len=100),
                        VarcharColumn(name='Country', char_max_len=255),
                    ],
                ),
            ],
            users=[
                User.for_login(admin_login),                    
                User.for_login(writer_login, db_roles=['db_datawriter']),   
                User.for_login(reader_login, db_roles=['db_datareader']),
            ]
        )
    ],
    logins=[
        admin_login,
        writer_login,
        reader_login,
    ],
)

Apply the schema to a target database:

import pyodbc

from sssm.align import align_server
from .schema import server

# Create connection using an admin login
connection = pyodbc.connect(...)

align_server(connection.cursor(), server)

This should be run from an interactive Python session or script, as it will prompt for confirmation before applying destructive changes.

Inspection Mode

Inspecting an existing server schema can be done either programmatically or in an interactive shell:

>>> import pyodbc
>>> from sssm.db_entities.reflected import ReflectedServer
# Create connection using an admin login
>>> connection = pyodbc.connect(...)
>>> server = ReflectedServer.from_cursor(connection.cursor())
>>> database = server.get_current_database()    # Get database specified in connection
>>> person_table = database.get_table('Person') # Get table by name
>>> person_table.get_compression()
'NONE'
>>> person_table.set_compression('PAGE')        # Rebuild table with PAGE compression
>>> person_table.get_compression()
'PAGE'
>>> person_table.clear_data()

Features

Supported Database Entities

Supports managing the following database entities and attributes:

  • Server Logins (not creating)
    • Server roles
  • Databases
    • Owner
    • Data and log file directories
    • Data size
    • Recovery model
  • Schemas
  • Tables
  • Users
    • Login name
    • DB roles
  • Columns
    • Data types
    • Max length
    • Nullable
    • Datetime/Numeric precision
  • Indexes / Primary keys
    • Columns
    • Clustered
    • Unique
    • Included columns
    • Compression
  • Foreign keys
    • Source and target columns
  • Partitions
    • Partition column

Other Features

  • Use ignore_extra_children on a declared object if you want to ignore (not delete) any extra existing children when aligning it to a reflected object.
  • Set old_name on a declared object to identify and rename the existing object when aligning it to a database.