From d2c555af2e79ed51bb973f80dbdea91a02755f64 Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sat, 26 Sep 2015 23:03:48 -0700 Subject: [PATCH 01/10] Ignore symbolic links that make tests run first when working on them. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d7737f8cf..acc3d5397 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ share/PrecompiledParsers/Parse/RecDescent/DDL/SQLT/*.pm *~ .#* *# +t/00* From 3f20ba799440b70a0ebc094076539dbd2908b6aa Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sat, 26 Sep 2015 23:13:10 -0700 Subject: [PATCH 02/10] Use DB2.pm and 64xml-to-mysql.t as initial templates --- lib/SQL/Translator/Producer/NuoDB.pm | 411 +++++++++++++++++++++++++++ t/65xml-to-nuodb.t | 98 +++++++ 2 files changed, 509 insertions(+) create mode 100644 lib/SQL/Translator/Producer/NuoDB.pm create mode 100644 t/65xml-to-nuodb.t diff --git a/lib/SQL/Translator/Producer/NuoDB.pm b/lib/SQL/Translator/Producer/NuoDB.pm new file mode 100644 index 000000000..ec522d7b8 --- /dev/null +++ b/lib/SQL/Translator/Producer/NuoDB.pm @@ -0,0 +1,411 @@ +package SQL::Translator::Producer::NuoDB; +# Started with lib/SQL/Translator/Producer/DB2.pm since it created a vastly correct DDL without modification +=head1 NAME + +SQL::Translator::Producer::NuoDB - NuoDB SQL producer + +=head1 SYNOPSIS + + use SQL::Translator; + + my $t = SQL::Translator->new( parser => '...', producer => 'NuoDB' ); + print $translator->translate( $file ); + +=head1 DESCRIPTION + +Creates an SQL DDL suitable for NuoDB. + +=cut + +use warnings; +use strict; +use warnings; +our ( $DEBUG, $WARN ); +our $VERSION = '1.59'; +$DEBUG = 0 unless defined $DEBUG; + +use SQL::Translator::Schema::Constants; +use SQL::Translator::Utils qw(header_comment); + +my %dt_translate; +BEGIN { + %dt_translate = ( + # + # MySQL types + # + int => 'integer', + mediumint => 'integer', + tinyint => 'smallint', + char => 'char', + tinyblob => 'blob', + mediumblob => 'blob', + longblob => 'long varchar for bit data', + tinytext => 'varchar', + text => 'varchar', + longtext => 'varchar', + mediumtext => 'varchar', + enum => 'varchar', + set => 'varchar', + date => 'date', + datetime => 'timestamp', + time => 'time', + year => 'date', + + # + # PostgreSQL types + # + 'double precision' => 'double', + serial => 'integer', + bigserial => 'integer', + money => 'double', + character => 'char', + 'character varying' => 'varchar', + bytea => 'BLOB', + interval => 'integer', + boolean => 'smallint', + point => 'integer', + line => 'integer', + lseg => 'integer', + box => 'integer', + path => 'integer', + polygon => 'integer', + circle => 'integer', + cidr => 'integer', + inet => 'varchar', + macaddr => 'varchar', + bit => 'number', + 'bit varying' => 'number', + + # + # DB types + # + number => 'integer', + varchar2 => 'varchar', + long => 'clob', +); +} + +my %nuodb_reserved = map { $_ => 1} qw/ +ADD DETERMINISTIC LEAVE RESTART +AFTER DISALLOW LEFT RESTRICT +ALIAS DISCONNECT LIKE RESULT +ALL DISTINCT LINKTYPE RESULT_SET_LOCATOR +ALLOCATE DO LOCAL RETURN +ALLOW DOUBLE LOCALE RETURNS +ALTER DROP LOCATOR REVOKE +AND DSNHATTR LOCATORS RIGHT +ANY DSSIZE LOCK ROLLBACK +APPLICATION DYNAMIC LOCKMAX ROUTINE +AS EACH LOCKSIZE ROW +ASSOCIATE EDITPROC LONG ROWS +ASUTIME ELSE LOOP RRN +AUDIT ELSEIF MAXVALUE RUN +AUTHORIZATION ENCODING MICROSECOND SAVEPOINT +AUX END MICROSECONDS SCHEMA +AUXILIARY END-EXEC MINUTE SCRATCHPAD +BEFORE END-EXEC1 MINUTES SECOND +BEGIN ERASE MINVALUE SECONDS +BETWEEN ESCAPE MODE SECQTY +BINARY EXCEPT MODIFIES SECURITY +BUFFERPOOL EXCEPTION MONTH SELECT +BY EXCLUDING MONTHS SENSITIVE +CACHE EXECUTE NEW SET +CALL EXISTS NEW_TABLE SIGNAL +CALLED EXIT NO SIMPLE +CAPTURE EXTERNAL NOCACHE SOME +CARDINALITY FENCED NOCYCLE SOURCE +CASCADED FETCH NODENAME SPECIFIC +CASE FIELDPROC NODENUMBER SQL +CAST FILE NOMAXVALUE SQLID +CCSID FINAL NOMINVALUE STANDARD +CHAR FOR NOORDER START +CHARACTER FOREIGN NOT STATIC +CHECK FREE NULL STAY +CLOSE FROM NULLS STOGROUP +CLUSTER FULL NUMPARTS STORES +COLLECTION FUNCTION OBID STYLE +COLLID GENERAL OF SUBPAGES +COLUMN GENERATED OLD SUBSTRING +COMMENT GET OLD_TABLE SYNONYM +COMMIT GLOBAL ON SYSFUN +CONCAT GO OPEN SYSIBM +CONDITION GOTO OPTIMIZATION SYSPROC +CONNECT GRANT OPTIMIZE SYSTEM +CONNECTION GRAPHIC OPTION TABLE +CONSTRAINT GROUP OR TABLESPACE +CONTAINS HANDLER ORDER THEN +CONTINUE HAVING OUT TO +COUNT HOLD OUTER TRANSACTION +COUNT_BIG HOUR OVERRIDING TRIGGER +CREATE HOURS PACKAGE TRIM +CROSS IDENTITY PARAMETER TYPE +CURRENT IF PART UNDO +CURRENT_DATE IMMEDIATE PARTITION UNION +CURRENT_LC_CTYPE IN PATH UNIQUE +CURRENT_PATH INCLUDING PIECESIZE UNTIL +CURRENT_SERVER INCREMENT PLAN UPDATE +CURRENT_TIME INDEX POSITION USAGE +CURRENT_TIMESTAMP INDICATOR PRECISION USER +CURRENT_TIMEZONE INHERIT PREPARE USING +CURRENT_USER INNER PRIMARY VALIDPROC +CURSOR INOUT PRIQTY VALUES +CYCLE INSENSITIVE PRIVILEGES VARIABLE +DATA INSERT PROCEDURE VARIANT +DATABASE INTEGRITY PROGRAM VCAT +DAY INTO PSID VIEW +DAYS IS QUERYNO VOLUMES +DB2GENERAL ISOBID READ WHEN +DB2GENRL ISOLATION READS WHERE +DB2SQL ITERATE RECOVERY WHILE +DBINFO JAR REFERENCES WITH +DECLARE JAVA REFERENCING WLM +DEFAULT JOIN RELEASE WRITE +DEFAULTS KEY RENAME YEAR +DEFINITION LABEL REPEAT YEARS +DELETE LANGUAGE RESET +DESCRIPTOR LC_CTYPE RESIGNAL +/; + +sub produce +{ + my ($translator) = @_; + $DEBUG = $translator->debug; + $WARN = $translator->show_warnings; + my $no_comments = $translator->no_comments; + my $add_drop_table = $translator->add_drop_table; + my $schema = $translator->schema; + my $output = ''; + my $indent = ' '; + + $output .= header_comment unless($no_comments); + my (@table_defs, @fks, @index_defs); + foreach my $table ($schema->get_tables) + { + push @table_defs, 'DROP TABLE ' . $table->name . ";" if $add_drop_table; + my ($table_def, $fks) = create_table($table, { + no_comments => $no_comments}); + push @table_defs, $table_def; + push @fks, @$fks; + + foreach my $index ($table->get_indices) + { + push @index_defs, create_index($index); + } + + } + my (@view_defs); + foreach my $view ( $schema->get_views ) + { + push @view_defs, create_view($view); + } + my (@trigger_defs); + foreach my $trigger ( $schema->get_triggers ) + { + push @trigger_defs, create_trigger($trigger); + } + + return wantarray ? (@table_defs, @fks, @index_defs, @view_defs, @trigger_defs) : + $output . join("\n\n", @table_defs, @fks, @index_defs, @view_defs, @trigger_defs) . "\n"; +} + +{ my %objnames; + + sub check_name + { + my ($name, $type, $length) = @_; + + my $newname = $name; + if(length($name) > $length) ## Maximum table name length is 18 + { + warn "Table name $name is longer than $length characters, truncated" if $WARN; +# if(grep {$_ eq substr($name, 0, $length) } +# values(%{$objnames{$type}})) +# { +# die "Got multiple matching table names when truncated"; +# } +# $objnames{$type}{$name} = substr($name, 0,$length); +# $newname = $objnames{$type}{$name}; + } + + if($nuodb_reserved{uc($newname)}) + { + warn "$newname is a reserved word in NuoDB!" if $WARN; + } + +# return sprintf("%-*s", $length-5, $newname); + return $newname; + } +} + +sub create_table +{ + my ($table, $options) = @_; + + my $table_name = check_name($table->name, 'tables', 128); + + my (@field_defs, @comments); + push @comments, "--\n-- Table: $table_name\n--" unless $options->{no_comments}; + foreach my $field ($table->get_fields) + { + push @field_defs, create_field($field); + } + my (@con_defs, @fks); + foreach my $con ($table->get_constraints) + { + my ($cdefs, $fks) = create_constraint($con); + push @con_defs, @$cdefs; + push @fks, @$fks; + } + + my $tablespace = $table->extra()->{'TABLESPACE'} || ''; + my $table_def = "CREATE TABLE $table_name (\n"; + $table_def .= join (",\n", map { " $_" } @field_defs, @con_defs); + $table_def .= "\n)"; + $table_def .= $tablespace ? "IN $tablespace;" : ';'; + + return $table_def, \@fks; +} + +sub create_field +{ + my ($field) = @_; + + my $field_name = check_name($field->name, 'fields', 30); +# use Data::Dumper; +# print Dumper(\%dt_translate); +# print $field->data_type, " ", $dt_translate{lc($field->data_type)}, "\n"; + my $data_type = uc($dt_translate{lc($field->data_type)} || $field->data_type); + my $size = $field->size(); + + my $field_def = "$field_name $data_type"; + $field_def .= $field->is_auto_increment ? + ' GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1)' : ''; + $field_def .= $data_type =~ /(CHAR|CLOB|NUMERIC|DECIMAL)/i ? "(${size})" : ''; + $field_def .= !$field->is_nullable ? ' NOT NULL':''; +# $field_def .= $field->is_primary_key ? ' PRIMARY KEY':''; + $field_def .= !defined $field->default_value ? '' : + $field->default_value =~ /current( |_)timestamp/i || + $field->default_value =~ /\Qnow()\E/i ? + ' DEFAULT CURRENT TIMESTAMP' : defined $field->default_value ? + (" DEFAULT " . ($data_type =~ /(INT|DOUBLE)/i ? + $field->default_value : "'" . $field->default_value . "'") + ) : ''; + + return $field_def; +} + +sub create_index +{ + my ($index) = @_; + + my $out = sprintf('CREATE %sINDEX %s ON %s ( %s );', + $index->type() =~ /^UNIQUE$/i ? 'UNIQUE' : '', + $index->name, + $index->table->name, + join(', ', $index->fields) ); + + return $out; +} + +sub create_constraint +{ + my ($constraint) = @_; + + my (@con_defs, @fks); + + my $ctype = $constraint->type =~ /^PRIMARY(_|\s)KEY$/i ? 'PRIMARY KEY' : + $constraint->type =~ /^UNIQUE$/i ? 'UNIQUE' : + $constraint->type =~ /^CHECK_C$/i ? 'CHECK' : + $constraint->type =~ /^FOREIGN(_|\s)KEY$/i ? 'FOREIGN KEY' : ''; + + my $expr = $constraint->type =~ /^CHECK_C$/i ? $constraint->expression : + ''; + my $ref = $constraint->type =~ /^FOREIGN(_|\s)KEY$/i ? ('REFERENCES ' . $constraint->reference_table . '(' . join(', ', $constraint->reference_fields) . ')') : ''; + my $update = $constraint->on_update ? $constraint->on_update : ''; + my $delete = $constraint->on_delete ? $constraint->on_delete : ''; + + my $out = join(' ', grep { $_ } + $constraint->name ? ('CONSTRAINT ' . $constraint->name) : '', + $ctype, + '(' . join (', ', $constraint->fields) . ')', + $expr ? $expr : $ref, + $update, + $delete); + if ($constraint->type eq FOREIGN_KEY) { + my $table_name = $constraint->table->name; + $out = "ALTER TABLE $table_name ADD $out;"; + push @fks, $out; + } + else { + push @con_defs, $out; + } + + return \@con_defs, \@fks; + +} + +sub create_view +{ + my ($view) = @_; + + my $out = sprintf("CREATE VIEW %s AS\n%s;", + $view->name, + $view->sql); + + return $out; +} + +sub create_trigger +{ + my ($trigger) = @_; + + my $db_events = join ', ', $trigger->database_events; + my $out = sprintf('CREATE TRIGGER %s %s %s ON %s %s %s MODE DB2SQL %s', + $trigger->name, + $trigger->perform_action_when || 'AFTER', + $db_events =~ /update_on/i ? + ('UPDATE OF '. join(', ', $trigger->fields)) : + $db_events || 'UPDATE', + $trigger->table->name, + $trigger->extra->{reference} || 'REFERENCING OLD AS oldrow NEW AS newrow', + $trigger->extra->{granularity} || 'FOR EACH ROW', + $trigger->action ); + + return $out; + +} + +sub alter_field +{ + my ($from_field, $to_field) = @_; + + my $data_type = uc($dt_translate{lc($to_field->data_type)} || $to_field->data_type); + + my $size = $to_field->size(); + $data_type .= $data_type =~ /CHAR/i ? "(${size})" : ''; + + my $out = sprintf('ALTER TABLE %s ALTER %s SET DATATYPE %s', + $to_field->table->name, + $to_field->name, + $data_type); + +} + +sub add_field +{ + my ($new_field) = @_; + + my $out = sprintf('ALTER TABLE %s ADD COLUMN %s', + $new_field->table->name, + create_field($new_field)); + + return $out; +} + +sub drop_field +{ + my ($field) = @_; + + return ''; +} +1; diff --git a/t/65xml-to-nuodb.t b/t/65xml-to-nuodb.t new file mode 100644 index 000000000..a0de1d029 --- /dev/null +++ b/t/65xml-to-nuodb.t @@ -0,0 +1,98 @@ +#!/usr/bin/perl +#Started with t/64xml-to-mysql.t +use strict; + +use FindBin qw/$Bin/; +use Test::More; +use Test::SQL::Translator; +use Test::Exception; +use Test::Differences; +#use Data::Dumper; +use SQL::Translator; +use SQL::Translator::Schema::Constants; + + +BEGIN { + maybe_plan(2, 'SQL::Translator::Parser::XML::SQLFairy', + 'SQL::Translator::Producer::NuoDB'); +} + +my $xmlfile = "$Bin/data/xml/schema.xml"; + +my $sqlt; +$sqlt = SQL::Translator->new( + no_comments => 1, + show_warnings => 0, + add_drop_table => 1, + producer_args => { + nuodb_version => 0, + }, +); + +die "Can't find test schema $xmlfile" unless -e $xmlfile; + +my @want = ( + q[DROP TABLE Basic;], + q[CREATE TABLE Basic ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + title STRING NOT NULL DEFAULT 'hello', + description STRING NULL DEFAULT '', + email STRING, + explicitnulldef STRING, + explicitemptystring STRING DEFAULT '', + emptytagdef STRING DEFAULT '', -- Hello emptytagdef + another_id INTEGER DEFAULT 2, + timest TIMESTAMP, + PRIMARY KEY (id), + KEY titleindex (title), + UNIQUE KEY emailuniqueindex (email), + UNIQUE KEY very_long_index_name_on_title_field_which_should_be_truncated_for_various_rdbms (title) +);], + + q[DROP TABLE Another;], + q[CREATE TABLE Another ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + num NUMERIC(10,2), + PRIMARY KEY (id) +);], + q[ALTER TABLE Basic ADD FOREIGN KEY (another_id) REFERENCES Another(id);], + q[CREATE VIEW email_list AS +SELECT email FROM Basic WHERE (email IS NOT NULL);], + + q[DROP TRIGGER IF EXISTS foo_trigger;], + q[SET DELIMITER @, +CREATE TRIGGER foo_trigger FOR Basic AFTER INSERT AS + timest='NOW'; +END_TRIGGER@ +SET DELIMITER ;], + + q[DROP TRIGGER IF EXISTS bar_trigger_insert;], + q[SET DELIMITER @ +CREATE TRIGGER bar_trigger_insert FOR Basic BEFORE INSERT AS + timest='NOW'; +END_TRIGGER@ +SET DELIMITER ;], + + q[DROP TRIGGER IF EXISTS bar_trigger_update;], + q[SET DELIMITER @ +CREATE TRIGGER bar_trigger_update FOR Basic BEFORE UPDATE AS + timest='NOW'; +END_TRIGGER@ +SET DELIMITER ;] +); + +my $sql = $sqlt->translate( + from => 'XML-SQLFairy', + to => 'NuoDB', + filename => $xmlfile, +) or die $sqlt->error; + +eq_or_diff($sql, join("", map { "$_\n\n" } @want)); + +my @sql = $sqlt->translate( + from => 'XML-SQLFairy', + to => 'NuoDB', + filename => $xmlfile, +) or die $sqlt->error; + +is_deeply(\@sql, \@want); From 77a5e6250c1b2016b0475ce2f6e2a00ef149a41f Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sun, 27 Sep 2015 00:17:08 -0700 Subject: [PATCH 03/10] Passes test --- lib/SQL/Translator/Producer/NuoDB.pm | 24 ++++++++++++------------ t/65xml-to-nuodb.t | 28 ++++++++++------------------ 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/lib/SQL/Translator/Producer/NuoDB.pm b/lib/SQL/Translator/Producer/NuoDB.pm index ec522d7b8..cc343f8bf 100644 --- a/lib/SQL/Translator/Producer/NuoDB.pm +++ b/lib/SQL/Translator/Producer/NuoDB.pm @@ -82,6 +82,9 @@ BEGIN { number => 'integer', varchar2 => 'varchar', long => 'clob', + + varchar => 'STRING', + text => 'STRING', ); } @@ -205,7 +208,7 @@ sub produce } return wantarray ? (@table_defs, @fks, @index_defs, @view_defs, @trigger_defs) : - $output . join("\n\n", @table_defs, @fks, @index_defs, @view_defs, @trigger_defs) . "\n"; + $output . join("\n\n", @table_defs, @fks, @index_defs, @view_defs, @trigger_defs) . "\n\n"; } { my %objnames; @@ -279,7 +282,7 @@ sub create_field my $field_def = "$field_name $data_type"; $field_def .= $field->is_auto_increment ? - ' GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1)' : ''; + ' GENERATED BY DEFAULT AS IDENTITY' : ''; $field_def .= $data_type =~ /(CHAR|CLOB|NUMERIC|DECIMAL)/i ? "(${size})" : ''; $field_def .= !$field->is_nullable ? ' NOT NULL':''; # $field_def .= $field->is_primary_key ? ' PRIMARY KEY':''; @@ -298,7 +301,7 @@ sub create_index { my ($index) = @_; - my $out = sprintf('CREATE %sINDEX %s ON %s ( %s );', + my $out = sprintf('CREATE %sINDEX %s ON %s (%s);', $index->type() =~ /^UNIQUE$/i ? 'UNIQUE' : '', $index->name, $index->table->name, @@ -325,8 +328,8 @@ sub create_constraint my $delete = $constraint->on_delete ? $constraint->on_delete : ''; my $out = join(' ', grep { $_ } - $constraint->name ? ('CONSTRAINT ' . $constraint->name) : '', - $ctype, + $ctype, + $constraint->name ? ('KEY ' . $constraint->name) : '', '(' . join (', ', $constraint->fields) . ')', $expr ? $expr : $ref, $update, @@ -360,15 +363,12 @@ sub create_trigger my ($trigger) = @_; my $db_events = join ', ', $trigger->database_events; - my $out = sprintf('CREATE TRIGGER %s %s %s ON %s %s %s MODE DB2SQL %s', + my $out = sprintf("DROP TRIGGER IF EXISTS %s;\nSET DELIMITER @\nCREATE TRIGGER %s FOR %s %s %s AS\n %s\nEND_TRIGGER@\nSET DELIMITER ;", + $trigger->name, $trigger->name, - $trigger->perform_action_when || 'AFTER', - $db_events =~ /update_on/i ? - ('UPDATE OF '. join(', ', $trigger->fields)) : - $db_events || 'UPDATE', $trigger->table->name, - $trigger->extra->{reference} || 'REFERENCING OLD AS oldrow NEW AS newrow', - $trigger->extra->{granularity} || 'FOR EACH ROW', + uc($trigger->perform_action_when) || 'AFTER', + uc($db_events) || 'UPDATE', $trigger->action ); return $out; diff --git a/t/65xml-to-nuodb.t b/t/65xml-to-nuodb.t index a0de1d029..3b2381fd0 100644 --- a/t/65xml-to-nuodb.t +++ b/t/65xml-to-nuodb.t @@ -36,15 +36,14 @@ my @want = ( q[CREATE TABLE Basic ( id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, title STRING NOT NULL DEFAULT 'hello', - description STRING NULL DEFAULT '', + description STRING DEFAULT '', email STRING, explicitnulldef STRING, explicitemptystring STRING DEFAULT '', - emptytagdef STRING DEFAULT '', -- Hello emptytagdef + emptytagdef STRING DEFAULT '', another_id INTEGER DEFAULT 2, timest TIMESTAMP, PRIMARY KEY (id), - KEY titleindex (title), UNIQUE KEY emailuniqueindex (email), UNIQUE KEY very_long_index_name_on_title_field_which_should_be_truncated_for_various_rdbms (title) );], @@ -56,27 +55,20 @@ my @want = ( PRIMARY KEY (id) );], q[ALTER TABLE Basic ADD FOREIGN KEY (another_id) REFERENCES Another(id);], + q[CREATE INDEX titleindex ON Basic (title);], q[CREATE VIEW email_list AS SELECT email FROM Basic WHERE (email IS NOT NULL);], - - q[DROP TRIGGER IF EXISTS foo_trigger;], - q[SET DELIMITER @, + q[DROP TRIGGER IF EXISTS foo_trigger; +SET DELIMITER @ CREATE TRIGGER foo_trigger FOR Basic AFTER INSERT AS - timest='NOW'; -END_TRIGGER@ -SET DELIMITER ;], - - q[DROP TRIGGER IF EXISTS bar_trigger_insert;], - q[SET DELIMITER @ -CREATE TRIGGER bar_trigger_insert FOR Basic BEFORE INSERT AS - timest='NOW'; + update modified=timestamp(); END_TRIGGER@ SET DELIMITER ;], - q[DROP TRIGGER IF EXISTS bar_trigger_update;], - q[SET DELIMITER @ -CREATE TRIGGER bar_trigger_update FOR Basic BEFORE UPDATE AS - timest='NOW'; + q[DROP TRIGGER IF EXISTS bar_trigger; +SET DELIMITER @ +CREATE TRIGGER bar_trigger FOR Basic BEFORE INSERT, UPDATE AS + update modified2=timestamp(); END_TRIGGER@ SET DELIMITER ;] ); From 76bfba1d11db61ae05346e8bc2ac2da333b76a47 Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sun, 27 Sep 2015 13:05:27 -0700 Subject: [PATCH 04/10] cleanup --- lib/SQL/Translator/Producer/NuoDB.pm | 60 ++-------------------------- t/65xml-to-nuodb-types.t | 52 ++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 56 deletions(-) create mode 100644 t/65xml-to-nuodb-types.t diff --git a/lib/SQL/Translator/Producer/NuoDB.pm b/lib/SQL/Translator/Producer/NuoDB.pm index cc343f8bf..d4ed32f1b 100644 --- a/lib/SQL/Translator/Producer/NuoDB.pm +++ b/lib/SQL/Translator/Producer/NuoDB.pm @@ -30,59 +30,7 @@ use SQL::Translator::Utils qw(header_comment); my %dt_translate; BEGIN { %dt_translate = ( - # - # MySQL types - # - int => 'integer', - mediumint => 'integer', - tinyint => 'smallint', - char => 'char', - tinyblob => 'blob', - mediumblob => 'blob', - longblob => 'long varchar for bit data', - tinytext => 'varchar', - text => 'varchar', - longtext => 'varchar', - mediumtext => 'varchar', - enum => 'varchar', - set => 'varchar', - date => 'date', - datetime => 'timestamp', - time => 'time', - year => 'date', - - # - # PostgreSQL types - # - 'double precision' => 'double', - serial => 'integer', - bigserial => 'integer', - money => 'double', - character => 'char', - 'character varying' => 'varchar', - bytea => 'BLOB', - interval => 'integer', - boolean => 'smallint', - point => 'integer', - line => 'integer', - lseg => 'integer', - box => 'integer', - path => 'integer', - polygon => 'integer', - circle => 'integer', - cidr => 'integer', - inet => 'varchar', - macaddr => 'varchar', - bit => 'number', - 'bit varying' => 'number', - - # - # DB types - # - number => 'integer', - varchar2 => 'varchar', - long => 'clob', - + int => 'INTEGER', varchar => 'STRING', text => 'STRING', ); @@ -157,9 +105,9 @@ DATA INSERT PROCEDURE VARIANT DATABASE INTEGRITY PROGRAM VCAT DAY INTO PSID VIEW DAYS IS QUERYNO VOLUMES -DB2GENERAL ISOBID READ WHEN -DB2GENRL ISOLATION READS WHERE -DB2SQL ITERATE RECOVERY WHILE +ISOBID READ WHEN +ISOLATION READS WHERE +ITERATE RECOVERY WHILE DBINFO JAR REFERENCES WITH DECLARE JAVA REFERENCING WLM DEFAULT JOIN RELEASE WRITE diff --git a/t/65xml-to-nuodb-types.t b/t/65xml-to-nuodb-types.t new file mode 100644 index 000000000..a44cd128e --- /dev/null +++ b/t/65xml-to-nuodb-types.t @@ -0,0 +1,52 @@ +#!/usr/bin/perl +# vim: set ft=perl: +# Started with 56-sqlite-producer.t +use strict; +use Test::More; +use Test::SQL::Translator qw(maybe_plan); + +use SQL::Translator::Schema; +use SQL::Translator::Schema::View; +use SQL::Translator::Schema::Table; +use SQL::Translator::Producer::NuoDB; + +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'id', + data_type => 'int', + default_value => 1, + ); + my $expected = "CREATE TABLE foo_table (\n id INTEGER DEFAULT 1\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'simple table'); +} + +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'f', + data_type => 'varchar', + ); + my $expected = "CREATE TABLE foo_table (\n f STRING\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'simple table'); +} + +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'f', + data_type => 'text', + ); + my $expected = "CREATE TABLE foo_table (\n f STRING\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'simple table'); +} +done_testing; From 26105ed16e0759ff21edf3686d8b31e1c7a1d5ba Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sun, 27 Sep 2015 17:25:58 -0700 Subject: [PATCH 05/10] Fixed index and constraint creatioin. Added reserved words and NOW. --- lib/SQL/Translator/Producer/NuoDB.pm | 47 ++++---- t/65xml-to-nuodb-types.t | 162 ++++++++++++++++++++++++++- 2 files changed, 185 insertions(+), 24 deletions(-) diff --git a/lib/SQL/Translator/Producer/NuoDB.pm b/lib/SQL/Translator/Producer/NuoDB.pm index d4ed32f1b..82f153959 100644 --- a/lib/SQL/Translator/Producer/NuoDB.pm +++ b/lib/SQL/Translator/Producer/NuoDB.pm @@ -33,6 +33,9 @@ BEGIN { int => 'INTEGER', varchar => 'STRING', text => 'STRING', + interval => 'INTEGER', + bytea => 'BINARY', + inet => 'STRING', ); } @@ -91,12 +94,12 @@ COUNT_BIG HOUR OVERRIDING TRIGGER CREATE HOURS PACKAGE TRIM CROSS IDENTITY PARAMETER TYPE CURRENT IF PART UNDO -CURRENT_DATE IMMEDIATE PARTITION UNION +IMMEDIATE PARTITION UNION CURRENT_LC_CTYPE IN PATH UNIQUE CURRENT_PATH INCLUDING PIECESIZE UNTIL CURRENT_SERVER INCREMENT PLAN UPDATE -CURRENT_TIME INDEX POSITION USAGE -CURRENT_TIMESTAMP INDICATOR PRECISION USER +INDEX POSITION USAGE +INDICATOR PRECISION USER CURRENT_TIMEZONE INHERIT PREPARE USING CURRENT_USER INNER PRIMARY VALIDPROC CURSOR INOUT PRIQTY VALUES @@ -115,6 +118,7 @@ DEFAULTS KEY RENAME YEAR DEFINITION LABEL REPEAT YEARS DELETE LANGUAGE RESET DESCRIPTOR LC_CTYPE RESIGNAL +SET STRING /; sub produce @@ -169,21 +173,14 @@ sub produce if(length($name) > $length) ## Maximum table name length is 18 { warn "Table name $name is longer than $length characters, truncated" if $WARN; -# if(grep {$_ eq substr($name, 0, $length) } -# values(%{$objnames{$type}})) -# { -# die "Got multiple matching table names when truncated"; -# } -# $objnames{$type}{$name} = substr($name, 0,$length); -# $newname = $objnames{$type}{$name}; } if($nuodb_reserved{uc($newname)}) { warn "$newname is a reserved word in NuoDB!" if $WARN; + $newname = '"'.$newname.'"'; } -# return sprintf("%-*s", $length-5, $newname); return $newname; } } @@ -233,11 +230,10 @@ sub create_field ' GENERATED BY DEFAULT AS IDENTITY' : ''; $field_def .= $data_type =~ /(CHAR|CLOB|NUMERIC|DECIMAL)/i ? "(${size})" : ''; $field_def .= !$field->is_nullable ? ' NOT NULL':''; -# $field_def .= $field->is_primary_key ? ' PRIMARY KEY':''; $field_def .= !defined $field->default_value ? '' : $field->default_value =~ /current( |_)timestamp/i || $field->default_value =~ /\Qnow()\E/i ? - ' DEFAULT CURRENT TIMESTAMP' : defined $field->default_value ? + ' DEFAULT \'NOW\'' : defined $field->default_value ? (" DEFAULT " . ($data_type =~ /(INT|DOUBLE)/i ? $field->default_value : "'" . $field->default_value . "'") ) : ''; @@ -249,11 +245,17 @@ sub create_index { my ($index) = @_; + my @fields; + # check each field name + for ($index->fields) { + push @fields, check_name($_, 'fields', 30); + } + my $out = sprintf('CREATE %sINDEX %s ON %s (%s);', - $index->type() =~ /^UNIQUE$/i ? 'UNIQUE' : '', + $index->type() =~ /^UNIQUE$/i ? 'UNIQUE ' : '', $index->name, $index->table->name, - join(', ', $index->fields) ); + join(', ', @fields)); return $out; } @@ -276,15 +278,22 @@ sub create_constraint my $delete = $constraint->on_delete ? $constraint->on_delete : ''; my $out = join(' ', grep { $_ } - $ctype, - $constraint->name ? ('KEY ' . $constraint->name) : '', - '(' . join (', ', $constraint->fields) . ')', + $ctype, + $constraint->name && $constraint->type ne FOREIGN_KEY ? ('KEY ' . $constraint->name) : '', + '(' . join (', ', check_name($constraint->fields, 'fields', 30)) . ')', $expr ? $expr : $ref, $update, $delete); if ($constraint->type eq FOREIGN_KEY) { my $table_name = $constraint->table->name; - $out = "ALTER TABLE $table_name ADD $out;"; + + $out = join(' ', + 'ALTER TABLE', + $table_name, + $constraint->name ? ('ADD CONSTRAINT ' . $constraint->name) : 'ADD', + ($out . ';'), + ); + push @fks, $out; } else { diff --git a/t/65xml-to-nuodb-types.t b/t/65xml-to-nuodb-types.t index a44cd128e..a8fd783d3 100644 --- a/t/65xml-to-nuodb-types.t +++ b/t/65xml-to-nuodb-types.t @@ -4,10 +4,10 @@ use strict; use Test::More; use Test::SQL::Translator qw(maybe_plan); - use SQL::Translator::Schema; use SQL::Translator::Schema::View; use SQL::Translator::Schema::Table; +use SQL::Translator::Schema::Constants; use SQL::Translator::Producer::NuoDB; { @@ -15,7 +15,7 @@ use SQL::Translator::Producer::NuoDB; name => 'foo_table', ); $table->add_field( - name => 'id', + name => 'id', data_type => 'int', default_value => 1, ); @@ -24,29 +24,181 @@ use SQL::Translator::Producer::NuoDB; is_deeply(@result[0], $expected, 'simple table'); } +# varchar { my $table = SQL::Translator::Schema::Table->new( name => 'foo_table', ); $table->add_field( - name => 'f', + name => 'f', data_type => 'varchar', ); my $expected = "CREATE TABLE foo_table (\n f STRING\n);"; my @result = SQL::Translator::Producer::NuoDB::create_table($table); - is_deeply(@result[0], $expected, 'simple table'); + is_deeply(@result[0], $expected, 'varchar to string'); } +# text { my $table = SQL::Translator::Schema::Table->new( name => 'foo_table', ); $table->add_field( - name => 'f', + name => 'f', data_type => 'text', ); my $expected = "CREATE TABLE foo_table (\n f STRING\n);"; my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'text to string'); +} + +# interval +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'i', + data_type => 'interval', + ); + my $expected = "CREATE TABLE foo_table (\n i INTEGER\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'interval to integer'); +} + +# bytea +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'b', + data_type => 'bytea', + ); + my $expected = "CREATE TABLE foo_table (\n b BINARY\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'bytea to binary'); +} + +# inet +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'ip', + data_type => 'inet', + ); + my $expected = "CREATE TABLE foo_table (\n ip STRING\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'inet to string'); +} + + +# default NOW() +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'c', + data_type => 'timestamp', + is_nullable => 0, + default_value => 'NOW()', + ); + my $expected = "CREATE TABLE foo_table (\n c TIMESTAMP NOT NULL DEFAULT 'NOW'\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'NOW() to NOW'); +} + +# reserved word field +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'set', + data_type => 'integer', + ); + $table->add_field( + name => 'string', + data_type => 'integer', + ); + my $expected = "CREATE TABLE foo_table (\n \"set\" INTEGER,\n \"string\" INTEGER\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'reserved word field'); +} + +# reserved word field used in constraint +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + + my $fk_constraint = SQL::Translator::Schema::Constraint->new( + table => $table, + name => 'foo_table_string', + type => FOREIGN_KEY, + fields => 'string', + reference_table => 'area', + reference_fields => 'id', + ); + + my $expected = "ALTER TABLE foo_table ADD CONSTRAINT foo_table_string FOREIGN KEY (\"string\") REFERENCES area(id);"; + my ($result, $result_fk) = SQL::Translator::Producer::NuoDB::create_constraint($fk_constraint); + is($result_fk->[0], $expected, 'reserved word field in constraint'); +} + +# reserved word field used in index +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + fields => [qw(string,set)], + ); + + my $index = $table->add_index(name => 'myindex', fields => ['string,set']); + my ($def) = SQL::Translator::Producer::NuoDB::create_index($index); + is($def, 'CREATE INDEX myindex ON foo_table ("string", "set");', 'reserved word field index'); +} + +# primary key +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'code', + data_type => 'integer', + is_nullable => 0, + is_primary_key => 1 + ); + $table->add_constraint( + fields => 'code', + type => PRIMARY_KEY, + ); + my $expected = "CREATE TABLE foo_table (\n code INTEGER NOT NULL,\n PRIMARY KEY (code)\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); is_deeply(@result[0], $expected, 'simple table'); } + +# constraint name +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + + my $fk_constraint = SQL::Translator::Schema::Constraint->new( + table => $table, + name => 'foo_table_code', + type => FOREIGN_KEY, + fields => 'code', + reference_table => 'area', + reference_fields => 'id', + ); + + my $expected = "ALTER TABLE foo_table ADD CONSTRAINT foo_table_code FOREIGN KEY (code) REFERENCES area(id);"; + my ($result, $result_fk) = SQL::Translator::Producer::NuoDB::create_constraint($fk_constraint); + is($result_fk->[0], $expected, 'named foreign constraint'); +} + done_testing; From 3b2adbf4a3eca57b22dcfde050d9277892a67529 Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sun, 27 Sep 2015 17:34:37 -0700 Subject: [PATCH 06/10] whitespace --- lib/SQL/Translator/Producer/NuoDB.pm | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/SQL/Translator/Producer/NuoDB.pm b/lib/SQL/Translator/Producer/NuoDB.pm index 82f153959..fd25533e1 100644 --- a/lib/SQL/Translator/Producer/NuoDB.pm +++ b/lib/SQL/Translator/Producer/NuoDB.pm @@ -94,12 +94,12 @@ COUNT_BIG HOUR OVERRIDING TRIGGER CREATE HOURS PACKAGE TRIM CROSS IDENTITY PARAMETER TYPE CURRENT IF PART UNDO -IMMEDIATE PARTITION UNION +IMMEDIATE PARTITION UNION CURRENT_LC_CTYPE IN PATH UNIQUE CURRENT_PATH INCLUDING PIECESIZE UNTIL CURRENT_SERVER INCREMENT PLAN UPDATE -INDEX POSITION USAGE -INDICATOR PRECISION USER +INDEX POSITION USAGE +INDICATOR PRECISION USER CURRENT_TIMEZONE INHERIT PREPARE USING CURRENT_USER INNER PRIMARY VALIDPROC CURSOR INOUT PRIQTY VALUES @@ -219,9 +219,7 @@ sub create_field my ($field) = @_; my $field_name = check_name($field->name, 'fields', 30); -# use Data::Dumper; -# print Dumper(\%dt_translate); -# print $field->data_type, " ", $dt_translate{lc($field->data_type)}, "\n"; + my $data_type = uc($dt_translate{lc($field->data_type)} || $field->data_type); my $size = $field->size(); @@ -284,6 +282,7 @@ sub create_constraint $expr ? $expr : $ref, $update, $delete); + if ($constraint->type eq FOREIGN_KEY) { my $table_name = $constraint->table->name; From f4880ea5a378d70309a2b16c443df22ae04e7a12 Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sun, 4 Oct 2015 10:09:07 -0700 Subject: [PATCH 07/10] added a couple unit tests --- t/65xml-to-nuodb-types.t | 64 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/t/65xml-to-nuodb-types.t b/t/65xml-to-nuodb-types.t index a8fd783d3..13b1531fd 100644 --- a/t/65xml-to-nuodb-types.t +++ b/t/65xml-to-nuodb-types.t @@ -124,7 +124,27 @@ use SQL::Translator::Producer::NuoDB; name => 'string', data_type => 'integer', ); - my $expected = "CREATE TABLE foo_table (\n \"set\" INTEGER,\n \"string\" INTEGER\n);"; + $table->add_field( + name => 'schema', + data_type => 'integer', + ); + $table->add_field( + name => 'part', + data_type => 'integer', + ); + $table->add_field( + name => 'lock', + data_type => 'integer', + ); + $table->add_field( + name => 'path', + data_type => 'integer', + ); + $table->add_field( + name => 'get', + data_type => 'integer', + ); + my $expected = "CREATE TABLE foo_table (\n \"set\" INTEGER,\n \"string\" INTEGER,\n \"schema\" INTEGER,\n \"part\" INTEGER,\n \"lock\" INTEGER,\n \"path\" INTEGER,\n \"get\" INTEGER\n);"; my @result = SQL::Translator::Producer::NuoDB::create_table($table); is_deeply(@result[0], $expected, 'reserved word field'); } @@ -201,4 +221,46 @@ use SQL::Translator::Producer::NuoDB; is($result_fk->[0], $expected, 'named foreign constraint'); } +# int identity +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'id', + data_type => 'integer', + is_auto_increment => 1, + is_nullable => 0, + is_primary_key => 1 + ); + $table->add_constraint( + fields => 'id', + type => PRIMARY_KEY, + ); + my $expected = "CREATE TABLE foo_table (\n id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,\n PRIMARY KEY (id)\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'int identity'); +} + +# bigint identity +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'id', + data_type => 'bigint', + is_auto_increment => 1, + is_nullable => 0, + is_primary_key => 1 + ); + $table->add_constraint( + fields => 'id', + type => PRIMARY_KEY, + ); + my $expected = "CREATE TABLE foo_table (\n id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL,\n PRIMARY KEY (id)\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'bitint identity'); +} + done_testing; From 238bbf383a7fb072d87966f22d7c021795e76f78 Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sun, 4 Oct 2015 10:43:57 -0700 Subject: [PATCH 08/10] actual nuodb reserved words --- lib/SQL/Translator/Producer/NuoDB.pm | 127 ++++++++++----------------- 1 file changed, 48 insertions(+), 79 deletions(-) diff --git a/lib/SQL/Translator/Producer/NuoDB.pm b/lib/SQL/Translator/Producer/NuoDB.pm index fd25533e1..9f923390d 100644 --- a/lib/SQL/Translator/Producer/NuoDB.pm +++ b/lib/SQL/Translator/Producer/NuoDB.pm @@ -40,85 +40,54 @@ BEGIN { } my %nuodb_reserved = map { $_ => 1} qw/ -ADD DETERMINISTIC LEAVE RESTART -AFTER DISALLOW LEFT RESTRICT -ALIAS DISCONNECT LIKE RESULT -ALL DISTINCT LINKTYPE RESULT_SET_LOCATOR -ALLOCATE DO LOCAL RETURN -ALLOW DOUBLE LOCALE RETURNS -ALTER DROP LOCATOR REVOKE -AND DSNHATTR LOCATORS RIGHT -ANY DSSIZE LOCK ROLLBACK -APPLICATION DYNAMIC LOCKMAX ROUTINE -AS EACH LOCKSIZE ROW -ASSOCIATE EDITPROC LONG ROWS -ASUTIME ELSE LOOP RRN -AUDIT ELSEIF MAXVALUE RUN -AUTHORIZATION ENCODING MICROSECOND SAVEPOINT -AUX END MICROSECONDS SCHEMA -AUXILIARY END-EXEC MINUTE SCRATCHPAD -BEFORE END-EXEC1 MINUTES SECOND -BEGIN ERASE MINVALUE SECONDS -BETWEEN ESCAPE MODE SECQTY -BINARY EXCEPT MODIFIES SECURITY -BUFFERPOOL EXCEPTION MONTH SELECT -BY EXCLUDING MONTHS SENSITIVE -CACHE EXECUTE NEW SET -CALL EXISTS NEW_TABLE SIGNAL -CALLED EXIT NO SIMPLE -CAPTURE EXTERNAL NOCACHE SOME -CARDINALITY FENCED NOCYCLE SOURCE -CASCADED FETCH NODENAME SPECIFIC -CASE FIELDPROC NODENUMBER SQL -CAST FILE NOMAXVALUE SQLID -CCSID FINAL NOMINVALUE STANDARD -CHAR FOR NOORDER START -CHARACTER FOREIGN NOT STATIC -CHECK FREE NULL STAY -CLOSE FROM NULLS STOGROUP -CLUSTER FULL NUMPARTS STORES -COLLECTION FUNCTION OBID STYLE -COLLID GENERAL OF SUBPAGES -COLUMN GENERATED OLD SUBSTRING -COMMENT GET OLD_TABLE SYNONYM -COMMIT GLOBAL ON SYSFUN -CONCAT GO OPEN SYSIBM -CONDITION GOTO OPTIMIZATION SYSPROC -CONNECT GRANT OPTIMIZE SYSTEM -CONNECTION GRAPHIC OPTION TABLE -CONSTRAINT GROUP OR TABLESPACE -CONTAINS HANDLER ORDER THEN -CONTINUE HAVING OUT TO -COUNT HOLD OUTER TRANSACTION -COUNT_BIG HOUR OVERRIDING TRIGGER -CREATE HOURS PACKAGE TRIM -CROSS IDENTITY PARAMETER TYPE -CURRENT IF PART UNDO -IMMEDIATE PARTITION UNION -CURRENT_LC_CTYPE IN PATH UNIQUE -CURRENT_PATH INCLUDING PIECESIZE UNTIL -CURRENT_SERVER INCREMENT PLAN UPDATE -INDEX POSITION USAGE -INDICATOR PRECISION USER -CURRENT_TIMEZONE INHERIT PREPARE USING -CURRENT_USER INNER PRIMARY VALIDPROC -CURSOR INOUT PRIQTY VALUES -CYCLE INSENSITIVE PRIVILEGES VARIABLE -DATA INSERT PROCEDURE VARIANT -DATABASE INTEGRITY PROGRAM VCAT -DAY INTO PSID VIEW -DAYS IS QUERYNO VOLUMES -ISOBID READ WHEN -ISOLATION READS WHERE -ITERATE RECOVERY WHILE -DBINFO JAR REFERENCES WITH -DECLARE JAVA REFERENCING WLM -DEFAULT JOIN RELEASE WRITE -DEFAULTS KEY RENAME YEAR -DEFINITION LABEL REPEAT YEARS -DELETE LANGUAGE RESET -DESCRIPTOR LC_CTYPE RESIGNAL -SET STRING +ALL AS BETWEEN BITS +BOTH BREAK BY CALL +CASCADE CASE CATCH COLLATE +COLUMN CONSTRAINT CONTAINING CONTINUE +CREATE CURRENT CURRENT_DATE CURRENT_TIME +CURRENT_TIMESTAMP DEFAULT DELETE DESCRIBE +DISTINCT ELSE END END_FOR +END_FUNCTION END_IF END_PROCEDURE END_TRIGGER +END_TRY END_WHILE ENUM ESCAPE +EXECUTE EXISTS FALSE FETCH +FOR FOREIGN FOR_UPDATE FROM +FULL GENERATED GROUP HAVING +IDENTITY IF IN INNER +INOUT INSERT INTO IS +JOIN KEY LEADING LEFT +LIKE LIMIT LOGICAL_AND LOGICAL_NOT +LOGICAL_OR MAX MAXVALUE MIN +NATIONAL NATURAL NCHAR NCLOB +NEXT NEXT_VALUE NOT_BETWEEN NOT_CONTAINING +NOT_IN NOT_LIKE NOT_STARTING NTEXT +NULL NUMERIC NVARCHAR OCTETS +OFF OFFSET ON ONLY +ORDER OUT PRIMARY REAL +RECORD_BATCHING REFERENCES REGEXP RESTART +RESTRICT RETURN RIGHT ROLLBACK +ROWS SELECT SET SHOW +SMALLDATETIME SMALLINT STARTING STRING_TYPE +THEN THROW TINYBLOB TINYINT +TO TRAILING TRUE TRY +UNION UNIQUE UNKNOWN UPDATE +USING VAR VER WHEN +WHERE WHILE WITH +ABS ACOS ASIN ATAN2 +ATAN BIT_LENGTH CAST CEILING +CHARACTER_LENGTH COALESCE CONCAT CONVERT_TZ +COS COT CURRENT_USER DATE +DATE_ADD DATE_SUB DAYOFWEEK DAY +DEGREES EXTRACT FLOOR GREATEST +HOUR IFNULL LEAST LOCATE +LOWER LTRIM MINUTE MOD +MONTH MSLEEP NOW NULLIF +OCTET_LENGTH OPTIONAL_FIELD PI POSITION +POWER RADIANS RAND REPLACE +ROUND RTRIM SECOND SIN +SQRT SUBSTRING_INDEX SUBSTR TAN +TRIM UPPER USER YEAR +STRING SCHEMA PART LOCK +PATH GET /; sub produce From 2b267cc4a9fcbecf0cb449f0fa6e90a734734121 Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Fri, 15 Dec 2017 19:05:02 -0800 Subject: [PATCH 09/10] NOW() stays NOW() --- lib/SQL/Translator/Producer/NuoDB.pm | 2 +- t/65xml-to-nuodb-types.t | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/SQL/Translator/Producer/NuoDB.pm b/lib/SQL/Translator/Producer/NuoDB.pm index 9f923390d..373f8c502 100644 --- a/lib/SQL/Translator/Producer/NuoDB.pm +++ b/lib/SQL/Translator/Producer/NuoDB.pm @@ -200,7 +200,7 @@ sub create_field $field_def .= !defined $field->default_value ? '' : $field->default_value =~ /current( |_)timestamp/i || $field->default_value =~ /\Qnow()\E/i ? - ' DEFAULT \'NOW\'' : defined $field->default_value ? + ' DEFAULT NOW()' : defined $field->default_value ? (" DEFAULT " . ($data_type =~ /(INT|DOUBLE)/i ? $field->default_value : "'" . $field->default_value . "'") ) : ''; diff --git a/t/65xml-to-nuodb-types.t b/t/65xml-to-nuodb-types.t index 13b1531fd..ec3a9458d 100644 --- a/t/65xml-to-nuodb-types.t +++ b/t/65xml-to-nuodb-types.t @@ -106,9 +106,9 @@ use SQL::Translator::Producer::NuoDB; is_nullable => 0, default_value => 'NOW()', ); - my $expected = "CREATE TABLE foo_table (\n c TIMESTAMP NOT NULL DEFAULT 'NOW'\n);"; + my $expected = "CREATE TABLE foo_table (\n c TIMESTAMP NOT NULL DEFAULT NOW()\n);"; my @result = SQL::Translator::Producer::NuoDB::create_table($table); - is_deeply(@result[0], $expected, 'NOW() to NOW'); + is_deeply(@result[0], $expected, 'NOW() stays NOW()'); } # reserved word field From 2ddbd16d2e1dd8326364f4c237504e4d1ea68629 Mon Sep 17 00:00:00 2001 From: Stephen Jazdzewski Date: Sat, 16 Dec 2017 12:37:28 -0800 Subject: [PATCH 10/10] NuoDB does not support WITHOUT TIME ZONE types --- lib/SQL/Translator/Producer/NuoDB.pm | 3 +++ t/65xml-to-nuodb-types.t | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/SQL/Translator/Producer/NuoDB.pm b/lib/SQL/Translator/Producer/NuoDB.pm index 373f8c502..54e27618d 100644 --- a/lib/SQL/Translator/Producer/NuoDB.pm +++ b/lib/SQL/Translator/Producer/NuoDB.pm @@ -192,6 +192,9 @@ sub create_field my $data_type = uc($dt_translate{lc($field->data_type)} || $field->data_type); my $size = $field->size(); + # NuoDB does not support WITHOUT TIME ZONE types + $data_type =~ s/ WITHOUT TIME ZONE//i; + my $field_def = "$field_name $data_type"; $field_def .= $field->is_auto_increment ? ' GENERATED BY DEFAULT AS IDENTITY' : ''; diff --git a/t/65xml-to-nuodb-types.t b/t/65xml-to-nuodb-types.t index ec3a9458d..f8f1798d5 100644 --- a/t/65xml-to-nuodb-types.t +++ b/t/65xml-to-nuodb-types.t @@ -111,6 +111,22 @@ use SQL::Translator::Producer::NuoDB; is_deeply(@result[0], $expected, 'NOW() stays NOW()'); } +# without time zone +{ + my $table = SQL::Translator::Schema::Table->new( + name => 'foo_table', + ); + $table->add_field( + name => 'c', + data_type => 'timestamp WITHOUT TIME ZONE', + is_nullable => 1, + ); + my $expected = "CREATE TABLE foo_table (\n c TIMESTAMP\n);"; + my @result = SQL::Translator::Producer::NuoDB::create_table($table); + is_deeply(@result[0], $expected, 'Ignore WITHOUT TIME ZONE'); +} + + # reserved word field { my $table = SQL::Translator::Schema::Table->new(