package SQL::Translator::Producer::SQLServer;
# -------------------------------------------------------------------
-# $Id: SQLServer.pm,v 1.3 2005-07-11 20:12:02 duality72 Exp $
-# -------------------------------------------------------------------
-# Copyright (C) 2002-4 SQLFairy Authors
+# Copyright (C) 2002-2009 SQLFairy Authors
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
* !! Write some tests !!
* Reserved words list needs updating to SQLServer.
- * Triggers, Procedures and Views havn't been tested at all.
+ * Triggers, Procedures and Views DO NOT WORK
=cut
use strict;
use vars qw[ $DEBUG $WARN $VERSION ];
-$VERSION = sprintf "%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/;
+$VERSION = '1.59';
$DEBUG = 1 unless defined $DEBUG;
use Data::Dumper;
my @no_size = qw/tinyint smallint int integer bigint text bit image datetime/;
my $max_id_length = 128;
-my %used_identifiers = ();
my %global_names;
my %unreserve;
-my %truncated;
=pod
my $add_drop_table = $translator->add_drop_table;
my $schema = $translator->schema;
+ %global_names = (); #reset
+ %unreserve = ();
+
my $output;
$output .= header_comment."\n" unless ($no_comments);
# Generate the CREATE sql
for my $table ( $schema->get_tables ) {
my $table_name = $table->name or next;
- $table_name = mk_name( $table_name, '', undef, 1 );
my $table_name_ur = unreserve($table_name) || '';
my ( @comments, @field_defs, @index_defs, @constraint_defs );
#
my %field_name_scope;
for my $field ( $table->get_fields ) {
- my $field_name = mk_name(
- $field->name, '', \%field_name_scope, undef,1
- );
+ my $field_name = $field->name;
my $field_name_ur = unreserve( $field_name, $table_name );
my $field_def = qq["$field_name_ur"];
$field_def =~ s/\"//g;
my $list = $extra{'list'} || [];
# \todo deal with embedded quotes
my $commalist = join( ', ', map { qq['$_'] } @$list );
- my $seq_name;
if ( $data_type eq 'enum' ) {
- my $check_name = mk_name(
- $table_name.'_'.$field_name, 'chk' ,undef, 1
- );
+ my $check_name = mk_name( $field_name . '_chk' );
push @constraint_defs,
- "CONSTRAINT $check_name CHECK ($field_name IN ($commalist))";
+ "CONSTRAINT $check_name CHECK ($field_name IN ($commalist))";
$data_type .= 'character varying';
}
elsif ( $data_type eq 'set' ) {
else {
$field_def .= ' NULL' if $data_type ne 'bit';
}
- push @field_defs, $field_def;
#
# Default value
#
my $default = $field->default_value;
if ( defined $default ) {
- $field_def .= sprintf( ' DEFAULT %s',
- ( $field->is_auto_increment && $seq_name )
- ? qq[nextval('"$seq_name"'::text)] :
- ( $default =~ m/null/i ) ? 'NULL' : "'$default'"
+ SQL::Translator::Producer->_apply_default_value(
+ \$field_def,
+ $default,
+ [
+ 'NULL' => \'NULL',
+ ],
);
}
+
+ push @field_defs, $field_def;
}
#
# Constraint Declarations
#
my @constraint_decs = ();
- my $c_name_default;
for my $constraint ( $table->get_constraints ) {
my $name = $constraint->name || '';
# Make sure we get a unique name
- $name = mk_name( $name, undef, undef, 1 ) if $name;
my $type = $constraint->type || NORMAL;
my @fields = map { unreserve( $_, $table_name ) }
$constraint->fields;
$constraint->reference_fields;
next unless @fields;
+ my $c_def;
if ( $type eq PRIMARY_KEY ) {
- $name ||= mk_name( $table_name, 'pk', undef,1 );
- push @constraint_defs,
+ $name ||= mk_name( $table_name . '_pk' );
+ $c_def =
"CONSTRAINT $name PRIMARY KEY ".
'(' . join( ', ', @fields ) . ')';
}
elsif ( $type eq FOREIGN_KEY ) {
- $name ||= mk_name( $table_name, 'fk', undef,1 );
- #$name = mk_name( ($name || $table_name), 'fk', undef,1 );
- push @constraint_defs,
+ $name ||= mk_name( $table_name . '_fk' );
+ $c_def =
"CONSTRAINT $name FOREIGN KEY".
' (' . join( ', ', @fields ) . ') REFERENCES '.
$constraint->reference_table.
' (' . join( ', ', @rfields ) . ')';
+ my $on_delete = $constraint->on_delete;
+ if ( $on_delete && $on_delete ne "NO ACTION") {
+ $c_def .= " ON DELETE $on_delete";
+ }
+ my $on_update = $constraint->on_update;
+ if ( $on_update && $on_update ne "NO ACTION") {
+ $c_def .= " ON UPDATE $on_update";
+ }
}
elsif ( $type eq UNIQUE ) {
- $name ||= mk_name(
- $table_name,
- $name || ++$c_name_default,undef, 1
- );
- push @constraint_defs,
+ $name ||= mk_name( $table_name . '_uc' );
+ $c_def =
"CONSTRAINT $name UNIQUE " .
'(' . join( ', ', @fields ) . ')';
}
+ push @constraint_defs, $c_def;
}
#
# Indices
#
for my $index ( $table->get_indices ) {
- my $idx_name = $index->name || mk_name($table_name,'idx',undef,1);
+ my $idx_name = $index->name || mk_name($table_name . '_idx');
push @index_defs,
"CREATE INDEX $idx_name ON $table_name (".
join( ', ', $index->fields ) . ");";
@comments,
$create_statement,
@index_defs,
- ''
);
}
+# create view/procedure are NOT prepended to the input $sql, needs
+# to be filled in with the proper syntax
+
+=pod
+
# Text of view is already a 'create view' statement so no need to
# be fancy
foreach ( $schema->get_views ) {
my $name = $_->name();
$output .= "\n\n";
- $output .= "--\n-- View: $name\n--" unless $no_comments;
+ $output .= "--\n-- View: $name\n--\n\n" unless $no_comments;
my $text = $_->sql();
- $text =~ s/\r//g;
- $output .= $text;
+ $text =~ s/\r//g;
+ $output .= "$text\nGO\n";
}
# Text of procedure already has the 'create procedure' stuff
foreach ( $schema->get_procedures ) {
my $name = $_->name();
$output .= "\n\n";
- $output .= "--\n-- Procedure: $name\n--" unless $no_comments;
+ $output .= "--\n-- Procedure: $name\n--\n\n" unless $no_comments;
my $text = $_->sql();
$text =~ s/\r//g;
- $output .= $text;
- }
-
- # Warn out how we messed with the names.
- if ( $WARN ) {
- if ( %truncated ) {
- warn "Truncated " . keys( %truncated ) . " names:\n";
- warn "\t" . join( "\n\t", sort keys %truncated ) . "\n";
- }
- if ( %unreserve ) {
- warn "Encounted " . keys( %unreserve ) .
- " unsafe names in schema (reserved or invalid):\n";
- warn "\t" . join( "\n\t", sort keys %unreserve ) . "\n";
- }
+ $output .= "$text\nGO\n";
}
+=cut
return $output;
}
# -------------------------------------------------------------------
sub mk_name {
- my $basename = shift || '';
- my $type = shift || '';
- my $scope = shift || '';
- my $critical = shift || '';
- my $basename_orig = $basename;
- my $max_name = $type
- ? $max_id_length - (length($type) + 1)
- : $max_id_length;
- $basename = substr( $basename, 0, $max_name )
- if length( $basename ) > $max_name;
- my $name = $type ? "${type}_$basename" : $basename;
-
- if ( $basename ne $basename_orig and $critical ) {
- my $show_type = $type ? "+'$type'" : "";
- warn "Truncating '$basename_orig'$show_type to $max_id_length ",
- "character limit to make '$name'\n" if $WARN;
- $truncated{ $basename_orig } = $name;
- }
+ my ($name, $scope, $critical) = @_;
$scope ||= \%global_names;
if ( my $prev = $scope->{ $name } ) {