better schemas support for SQL Server > 2000
Rafael Kitover [Wed, 17 Oct 2012 18:49:35 +0000 (14:49 -0400)]
Use schema_name() instead of user_name() on > 2000 to detect the
current schema, and query [$db].sys.schemas instead of
[$db].dbo.sysusers for schema names on > 2000.

frew has reported that schema_name() has worked better for him for users
which aren't the owners of the schema.

Changes
lib/DBIx/Class/Schema/Loader/DBI/MSSQL.pm

diff --git a/Changes b/Changes
index b378bb3..704f03e 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,7 @@
 Revision history for Perl extension DBIx::Class::Schema::Loader
 
+        - MSSQL: on > 2000 use schema_name() instead of user_name() to detect
+          current schema and query sys.schemas instead of sysusers.
         - SQL Anywhere: introspect ON DELETE/UPDATE rules, default is now
           RESTRICT. is_deferrable still defaults to 1
         - rewrite pg fk introspection to use catalog views instead of
index 6d0681e..1890212 100644 (file)
@@ -51,6 +51,11 @@ been renamed to a more generic option.
 
 =cut
 
+# SQL Server 2000: Ancient as time itself, but still out in the wild
+sub _is_2k {
+    return shift->schema->storage->_server_info->{normalized_dbms_version} < 9;
+}
+
 sub _system_databases {
     return (qw/
         master model tempdb msdb
@@ -63,18 +68,31 @@ sub _system_tables {
     /);
 }
 
-sub _owners {
+sub _schemas {
     my ($self, $db) = @_;
 
-    my $owners = $self->dbh->selectcol_arrayref(<<"EOF");
+    my $owners = $self->dbh->selectcol_arrayref($self->_is_2k ? <<"EOF2K" : <<"EOF");
 SELECT name
 FROM [$db].dbo.sysusers
 WHERE uid <> gid
+EOF2K
+SELECT name
+FROM [$db].sys.schemas
 EOF
 
     return grep !/^(?:#|guest|INFORMATION_SCHEMA|sys)/, @$owners;
 }
 
+sub _current_schema {
+    my $self = shift;
+
+    if ($self->_is_2k) {
+        return ($self->dbh->selectrow_array('SELECT user_name()'))[0];
+    }
+
+    return ($self->dbh->selectrow_array('SELECT schema_name()'))[0];
+}
+
 sub _current_db {
     my $self = shift;
     return ($self->dbh->selectrow_array('SELECT db_name()'))[0];
@@ -142,7 +160,7 @@ EOF
             }
             else {
                 if ($db ne $current_db) {
-                    $self->dbh->do("USE [$db]");
+                    $self->_switch_db($db);
 
                     $self->qualify_objects(1);
                 }
@@ -154,7 +172,7 @@ EOF
     }
     elsif (ref $self->db_schema eq 'ARRAY' || (not defined $self->db_schema)) {
         my $owners = $self->db_schema;
-        $owners ||= [ $self->dbh->selectrow_array('SELECT user_name()') ];
+        $owners ||= [ $self->_current_schema ];
 
         $self->qualify_objects(1) if @$owners > 1;
 
@@ -163,7 +181,7 @@ EOF
 
     foreach my $db (keys %{ $self->db_schema }) {
         if ($self->db_schema->{$db} eq '%') {
-            $self->db_schema->{$db} = [ $self->_owners($db) ];
+            $self->db_schema->{$db} = [ $self->_schemas($db) ];
 
             $self->qualify_objects(1);
         }
@@ -359,11 +377,8 @@ sub _columns_info_for {
 
     my $result = $self->next::method(@_);
 
-    # SQL Server: Ancient as time itself, but still out in the wild
-    my $is_2k = $self->schema->storage->_server_info->{normalized_dbms_version} < 9;
-    
     # get type info (and identity)
-    my $rows = $self->dbh->selectall_arrayref($is_2k ? <<"EOF2K" : <<"EOF");
+    my $rows = $self->dbh->selectall_arrayref($self->_is_2k ? <<"EOF2K" : <<"EOF");
 SELECT c.column_name, c.character_maximum_length, c.data_type, c.datetime_precision, c.column_default, (sc.status & 0x80) is_identity
 FROM [$db].INFORMATION_SCHEMA.COLUMNS c
 JOIN [$db].dbo.sysusers ss ON