Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1293 dpurdie 1
###############################################################################
2
# Codestriker: Copyright (c) 2001, 2002 David Sitsky.  All rights reserved.
3
# sits@users.sourceforge.net
4
#
5
# This program is free software; you can redistribute it and modify it under
6
# the terms of the GPL.
7
 
8
package Codestriker::DB::Oracle;
9
 
10
use strict;
11
use DBI;
12
use Codestriker;
13
use Codestriker::DB::Database;
14
 
15
# Module for handling an Oracle database.
16
 
17
@Codestriker::DB::Oracle::ISA = ("Codestriker::DB::Database");
18
 
19
# Type mappings.
20
my $_TYPE = {
21
    $Codestriker::DB::Column::TYPE->{TEXT}	=> "clob",
22
    $Codestriker::DB::Column::TYPE->{VARCHAR}	=> "varchar2",
23
    $Codestriker::DB::Column::TYPE->{INT32}	=> "number(10)",
24
    $Codestriker::DB::Column::TYPE->{INT16}	=> "number(4)",
25
    $Codestriker::DB::Column::TYPE->{DATETIME}	=> "date",
26
    $Codestriker::DB::Column::TYPE->{FLOAT}	=> "float"
27
};
28
 
29
# Create a new Oracle database object.
30
sub new {
31
    my $type = shift;
32
 
33
    # Database is parent class.
34
    my $self = Codestriker::DB::Database->new();
35
    $self->{sequence_created} = 0;
36
    return bless $self, $type;
37
}
38
 
39
# Return the DBD module this is dependent on.
40
sub get_module_dependencies {
41
    return { name => 'DBD::Oracle', version => '0' };
42
}
43
 
44
# Retrieve a database connection.
45
sub get_connection {
46
    my $self = shift;
47
 
48
    # Oracle support transactions, don't enable auto_commit.
49
    my $dbh = $self->_get_connection(0, 1);
50
 
51
    # Make sure the default date type is set to something used consistently
52
    # in Codestriker.
53
    $dbh->do("ALTER session SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
54
 
55
    return $dbh;
56
}
57
 
58
# Method for retrieving the list of current tables attached to the database.
59
# For oracle, $dbh->tables doesn't work, need to retrieve data from the
60
# user_tables table.
61
sub get_tables() {
62
    my $self = shift;
63
 
64
    my @tables = ();
65
    my $table_select =
66
	$self->{dbh}->prepare_cached("SELECT table_name FROM user_tables");
67
    $table_select->execute();
68
    while (my ($table_name) = $table_select->fetchrow_array()) {
69
	push @tables, $table_name;
70
    }
71
    $table_select->finish();
72
 
73
    return @tables;
74
}
75
 
76
# Return the mapping for a specific type.
77
sub _map_type {
78
    my ($self, $type) = @_;
79
    return $_TYPE->{$type};
80
}
81
 
82
# Oracle implements autoincrements with triggers.
83
sub _get_autoincrement_type {
84
    return "";
85
}
86
 
87
# Create the table in the database for the specified table, and with the
88
# provided type mappings.
89
sub create_table {
90
    my ($self, $table) = @_;
91
 
92
    # Let the base class actually do the work in creating the table.
93
    $self->SUPER::create_table($table);
94
 
95
    # Create the necessary triggers for any autoincrement fields.
96
    foreach my $column (@{$table->get_columns()}) {
97
	if ($column->is_autoincrement()) {
98
	    print "Creating autoincrement trigger for table: " .
99
		$table->get_name() . " field: " . $column->get_name() . "\n";
100
	    $self->_oracle_handle_auto_increment($table->get_name(),
101
						 $column->get_name());
102
	}
103
    }
104
}
105
 
106
# Oracle-specific routine for creating a trigger on a new row insert to
107
# automatically assign a value to the specified fieldname from a sequence.
108
# This is used since Oracle doesn't support auto-increment or default values
109
# for fields.
110
sub _oracle_handle_auto_increment
111
{
112
    my ($self, $tablename, $fieldname) = @_;
113
 
114
    my $dbh = $self->{dbh};
115
 
116
    # Make sure the sequence is present in the database for the trigger to
117
    # work.
118
    eval {
119
	if ($self->{sequence_created} == 0) {
120
 
121
	    $dbh->do("CREATE SEQUENCE sequence");
122
	    print "Created sequence\n";
123
	    $self->{sequence_created} = 1;
124
	}
125
 
126
	# Now create the actual trigger on the table.
127
	$dbh->do("CREATE TRIGGER ${tablename}_${fieldname}_ins_row " .
128
		 "BEFORE INSERT ON ${tablename} FOR EACH ROW " .
129
		 "DECLARE newid integer; " .
130
		 "BEGIN " .
131
		 "IF (:NEW.${fieldname} IS NULL) " .
132
		 "THEN " .
133
		 "SELECT sequence.NextVal INTO newid FROM DUAL; " .
134
		 ":NEW.${fieldname} := newid; " .
135
		 "END IF; " .
136
		 "END;");
137
	print "Created trigger\n";
138
	$dbh->commit();
139
    };
140
    if ($@) {
141
	eval { $self->rollback() };
142
	die "Unable to create sequence/trigger.\n";
143
    }
144
}
145
 
146
# Add a field to a specific table.  If the field already exists, then catch
147
# the error and continue silently.  The SYNTAX for SQL Server is slightly
148
# different to standard SQL, there is no "COLUMN" keyword after "ADD".
149
sub add_field {
150
    my ($self, $table, $field, $definition) = @_;
151
 
152
    my $dbh = $self->{dbh};
153
    my $rc = 0;
154
 
155
    eval {
156
	$dbh->{PrintError} = 0;
157
	my $field_type = $self->_map_type($definition);
158
 
159
	$dbh->do("ALTER TABLE $table ADD $field $field_type");
160
	print "Added new field $field to table $table.\n";
161
	$rc = 1;
162
	$self->commit();
163
    };
164
    if ($@) {
165
	eval { $self->rollback() };
166
    }
167
 
168
    $dbh->{PrintError} = 1;
169
 
170
    return $rc;
171
}
172
 
173
# Indicate if the LIKE operator can be applied on a "text" field.
174
# For Oracle, this is false.
175
sub has_like_operator_for_text_field {
176
    my $self = shift;
177
    return 0;
178
}
179
 
180
# Function for generating an SQL subexpression for a case insensitive LIKE
181
# operation.
182
sub case_insensitive_like {
183
    my ($self, $field, $expression) = @_;
184
 
185
    # Convert the field and expression to lower case to get case insensitivity.
186
    my $field_lower = "lower($field)";
187
    my $expression_lower = $expression;
188
    $expression_lower =~ tr/[A-Z]/[a-z]/;
189
    $expression_lower = $self->{dbh}->quote($expression_lower);
190
 
191
    return "$field_lower LIKE $expression_lower";
192
}
193
 
194
1;
195