Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 4fd8bdbf

Von Moritz Bunkus vor fast 18 Jahren hinzugefügt

  • ID 4fd8bdbfb46b8b63a7d05457959b98c4956d1dbd
  • Vorgänger 73fb84d7
  • Nachfolger 3c559a20

Neuer Datenbankupgrademechanismus: Die Upgradedateien im neuen Verzeichnis sql/Pg-upgrade2 enthalten Informationen über Abhängigkeiten, die von Lx-Office ausgewertet werden, um die Reihenfolge zu bestimmen, in der Updates angewandt werden. Wird nicht mehr über Versionsnummern geregelt.

Unterschiede anzeigen:

SL/DBUpgrade2.pm
1
package SL::DBUpgrade2;
2

  
3
require Exporter;
4
@ISA = qw(Exporter);
5

  
6
@EXPORT = qw(parse_dbupdate_controls sort_dbupdate_controls);
7

  
8
sub parse_dbupdate_controls {
9
  $main::lxdebug->enter_sub();
10

  
11
  my ($form, $dbdriver) = @_;
12

  
13
  my $locale = $main::locale;
14

  
15
  local *IN;
16
  my %all_controls;
17

  
18
  my $path = "sql/${dbdriver}-upgrade2";
19

  
20
  foreach my $file_name (<$path/*.sql>, <$path/*.pl>) {
21
    next unless (open(IN, $file_name));
22

  
23
    my $file = $file_name;
24
    $file =~ s|.*/||;
25

  
26
    my $control = {
27
      "priority" => 1000,
28
      "depends" => [],
29
    };
30

  
31
    while (<IN>) {
32
      chomp();
33
      next unless (/^(--|\#)\s*\@/);
34
      s/^(--|\#)\s*\@//;
35
      s/\s*$//;
36
      next if ($_ eq "");
37

  
38
      my @fields = split(/\s*:\s*/, $_, 2);
39
      next unless (scalar(@fields) == 2);
40

  
41
      if ($fields[0] eq "depends") {
42
        push(@{$control->{"depends"}}, split(/\s+/, $fields[1]));
43
      } else {
44
        $control->{$fields[0]} = $fields[1];
45
      }
46
    }
47

  
48
    _control_error($form, $file_name,
49
                   $locale->text("Missing 'tag' field."))
50
      unless ($control->{"tag"});
51

  
52
    _control_error($form, $file_name,
53
                   $locale->text("The 'tag' field must only consist of " .
54
                                 "alphanumeric characters or the carachters " .
55
                                 "- _ ( )"))
56
      if ($control->{"tag"} =~ /[^a-zA-Z0-9_\(\)\-]/);
57

  
58
    _control_error($form, $file_name,
59
                   sprintf($locale->text("More than one control file " .
60
                                         "with the tag '%s' exist."),
61
                           $control->{"tag"}))
62
      if (defined($all_controls{$control->{"tag"}}));
63

  
64
    _control_error($form, $file_name,
65
                   sprintf($locale->text("Missing 'description' field.")))
66
      unless ($control->{"description"});
67

  
68
    $control->{"priority"} *= 1;
69
    $control->{"priority"} = 1000 unless ($control->{"priority"});
70

  
71
    $control->{"file"} = $file;
72

  
73
    map({ delete($control->{$_}); } qw(depth applied));
74

  
75
    $all_controls{$control->{"tag"}} = $control;
76

  
77
    close(IN);
78
  }
79

  
80
  foreach my $control (values(%all_controls)) {
81
    foreach my $dependency (@{$control->{"depends"}}) {
82
      _control_error($form, $control->{"file"},
83
                     sprintf($locale->text("Unknown dependency '%s'."),
84
                             $dependency))
85
        if (!defined($all_controls{$dependency}));
86
    }
87

  
88
    map({ $_->{"loop"} = 0; } values(%all_controls));
89
    _check_for_loops($form, $control->{"file"}, \%all_controls,
90
                     $control->{"tag"});
91
  }
92

  
93
  map({ _dbupdate2_calculate_depth(\%all_controls, $_->{"tag"}) }
94
      values(%all_controls));
95

  
96
  $main::lxdebug->leave_sub();
97

  
98
  return \%all_controls;
99
}
100

  
101
sub _check_for_loops {
102
  my ($form, $file_name, $controls, $tag, @path) = @_;
103

  
104
  push(@path, $tag);
105

  
106
  _control_error($form, $file_name,
107
                 $main::locale->text("Dependency loop detected:") .
108
                 " " . join(" -> ", @path))
109
    if ($controls->{$tag}->{"loop"});
110

  
111
  $controls->{$tag}->{"loop"} = 1;
112
  map({ _check_for_loops($form, $file_name, $controls, $_, @path); }
113
      @{$controls->{$tag}->{"depends"}});
114
}
115

  
116
sub _control_error {
117
  my ($form, $file_name, $message) = @_;
118

  
119
  my $form = $main::form;
120
  my $locale = $main::locale;
121

  
122
  $form->error(sprintf($locale->text("Error in database control file '%s': %s"),
123
                       $file_name, $message));
124
}
125

  
126
sub _dbupdate2_calculate_depth {
127
  $main::lxdebug->enter_sub();
128

  
129
  my ($tree, $tag) = @_;
130

  
131
  my $node = $tree->{$tag};
132

  
133
  return $main::lxdebug->leave_sub() if (defined($node->{"depth"}));
134

  
135
  my $max_depth = 0;
136

  
137
  foreach $tag (@{$node->{"depends"}}) {
138
    _dbupdate2_calculate_depth($tree, $tag);
139
    my $value = $tree->{$tag}->{"depth"};
140
    $max_depth = $value if ($value > $max_depth);
141
  }
142

  
143
  $node->{"depth"} = $max_depth + 1;
144

  
145
  $main::lxdebug->leave_sub();
146
}
147

  
148
sub sort_dbupdate_controls {
149
  return
150
    sort({ $a->{"depth"} != $b->{"depth"} ? $a->{"depth"} <=> $b->{"depth"} :
151
             $a->{"priority"} != $b->{"priority"} ?
152
             $a->{"priority"} <=> $b->{"priority"} :
153
             $a->{"tag"} cmp $b->{"tag"} } values(%{$_[0]}));
154
}
155

  
156

  
157
1;
SL/User.pm
34 34

  
35 35
package User;
36 36

  
37
use SL::DBUpgrade2;
38

  
37 39
sub new {
38 40
  $main::lxdebug->enter_sub();
39 41

  
......
162 164
		  '$myconfig{tel}', 'user')|;
163 165
      $dbh->do($query);
164 166
    }
167

  
168
    $self->create_schema_info_table($form, $dbh);
169

  
165 170
    $dbh->disconnect;
166 171

  
167 172
    $rc = 0;
168 173

  
169
    if (&update_available($myconfig{"dbdriver"}, $dbversion)) {
174
    my $controls =
175
      parse_dbupdate_controls($form, $myconfig{"dbdriver"});
170 176

  
171
      map { $form->{$_} = $myconfig{$_} }
172
        qw(dbname dbhost dbport dbdriver dbuser dbpasswd dbconnect);
177
    map({ $form->{$_} = $myconfig{$_} }
178
        qw(dbname dbhost dbport dbdriver dbuser dbpasswd dbconnect));
179

  
180
    if (update_available($myconfig{"dbdriver"}, $dbversion) ||
181
        update2_available($form, $controls)) {
173 182

  
174 183
      $form->{"stylesheet"} = "lx-office-erp.css";
175 184
      $form->{"title"} = $main::locale->text("Dataset upgrade");
......
185 194
      }
186 195

  
187 196
      # update the tables
188
      open FH, ">$userspath/nologin" or die "
189
$!";
197
      open(FH, ">$userspath/nologin") or die("$!");
190 198

  
191 199
      # required for Oracle
192 200
      $form->{dbdefault} = $sid;
......
196 204
      $SIG{QUIT} = 'IGNORE';
197 205

  
198 206
      $self->dbupdate($form);
207
      $self->dbupdate2($form, $controls);
199 208

  
200 209
      # remove lock file
201
      unlink "$userspath/nologin";
210
      unlink("$userspath/nologin");
202 211

  
203 212
      print($form->parse_html_template("dbupgrade/footer"));
204 213

  
......
453 462
sub process_query {
454 463
  $main::lxdebug->enter_sub();
455 464

  
456
  my ($self, $form, $dbh, $filename, $version) = @_;
465
  my ($self, $form, $dbh, $filename, $version_or_control) = @_;
457 466

  
458 467
  #  return unless (-f $filename);
459 468

  
......
510 519
    }
511 520
  }
512 521

  
513
  if ($version) {
522
  if (ref($version_or_control) eq "HASH") {
523
    $dbh->do("INSERT INTO schema_info (tag, login) VALUES (" .
524
             $dbh->quote($version_or_control->{"tag"}) . ", " .
525
             $dbh->quote($form->{"login"}) . ")");
526
  } elsif ($version_or_control) {
514 527
    $dbh->do("UPDATE defaults SET version = " . $dbh->quote($version));
515 528
  }
516 529
  $dbh->commit();
......
725 738
  return ($#upgradescripts > -1);
726 739
}
727 740

  
741
sub create_schema_info_table {
742
  $main::lxdebug->enter_sub();
743

  
744
  my ($self, $form, $dbh) = @_;
745

  
746
  my $query = "SELECT tag FROM schema_info LIMIT 1";
747
  if (!$dbh->do($query)) {
748
    $query =
749
      "CREATE TABLE schema_info (" .
750
      "  tag text, " .
751
      "  login text, " .
752
      "  itime timestamp DEFAULT now(), " .
753
      "  PRIMARY KEY (tag))";
754
    $dbh->do($query) || $form->dberror($query);
755
  }
756

  
757
  $main::lxdebug->leave_sub();
758
}
759

  
728 760
sub dbupdate {
729 761
  $main::lxdebug->enter_sub();
730 762

  
......
794 826
      last if ($version < $mindb);
795 827

  
796 828
      # apply upgrade
797
      $main::lxdebug->message(DEBUG2, "Appliying Update $upgradescript");
829
      $main::lxdebug->message(DEBUG2, "Applying Update $upgradescript");
798 830
      if ($file_type eq "sql") {
799 831
        $self->process_query($form, $dbh, "sql/" . $form->{"dbdriver"} . "-upgrade/$upgradescript", $str_maxdb);
800 832
      } else {
......
815 847
  return $rc;
816 848
}
817 849

  
850
sub dbupdate2 {
851
  $main::lxdebug->enter_sub();
852

  
853
  my ($self, $form, $controls) = @_;
854

  
855
  $form->{sid} = $form->{dbdefault};
856

  
857
  my @upgradescripts = ();
858
  my ($query, $sth, $tag);
859
  my $rc = -2;
860

  
861
  @upgradescripts = sort_dbupdate_controls($controls);
862

  
863
  foreach my $db (split / /, $form->{dbupdate}) {
864

  
865
    next unless $form->{$db};
866

  
867
    # strip db from dataset
868
    $db =~ s/^db//;
869
    &dbconnect_vars($form, $db);
870

  
871
    my $dbh =
872
      DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
873
      or $form->dberror;
874

  
875
    map({ $_->{"applied"} = 0; } @upgradescripts);
876

  
877
    $query = "SELECT tag FROM schema_info";
878
    $sth = $dbh->prepare($query);
879
    $sth->execute() || $form->dberror($query);
880
    while (($tag) = $sth->fetchrow_array()) {
881
      $controls->{$tag}->{"applied"} = 1 if (defined($controls->{$tag}));
882
    }
883
    $sth->finish();
884

  
885
    my $all_applied = 1;
886
    foreach (@upgradescripts) {
887
      if (!$_->{"applied"}) {
888
        $all_applied = 0;
889
        last;
890
      }
891
    }
892

  
893
    next if ($all_applied);
894

  
895
    foreach my $control (@upgradescripts) {
896
      next if ($control->{"applied"});
897

  
898
      $control->{"file"} =~ /\.(sql|pl)$/;
899
      my $file_type = $1;
900

  
901
      # apply upgrade
902
      $main::lxdebug->message(DEBUG2, "Applying Update $control->{file}");
903
      print($form->parse_html_template("dbupgrade/upgrade_message2",
904
                                       $control));
905

  
906
      if ($file_type eq "sql") {
907
        $self->process_query($form, $dbh, "sql/" . $form->{"dbdriver"} .
908
                             "-upgrade2/$control->{file}", $control);
909
      } else {
910
        $self->process_perl_script($form, $dbh, "sql/" . $form->{"dbdriver"} .
911
                                   "-upgrade2/$control->{file}", $control);
912
      }
913
    }
914

  
915
    $rc = 0;
916
    $dbh->disconnect;
917

  
918
  }
919

  
920
  $main::lxdebug->leave_sub();
921

  
922
  return $rc;
923
}
924

  
925
sub update2_available {
926
  $main::lxdebug->enter_sub();
927

  
928
  my ($form, $controls) = @_;
929

  
930
  map({ $_->{"applied"} = 0; } values(%{$controls}));
931

  
932
  dbconnect_vars($form, $form->{"dbname"});
933

  
934
  my $dbh =
935
    DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) ||
936
    $form->dberror;
937

  
938
  my ($query, $tag, $sth);
939

  
940
  $query = "SELECT tag FROM schema_info";
941
  $sth = $dbh->prepare($query);
942
  $sth->execute() || $form->dberror($query);
943
  while (($tag) = $sth->fetchrow_array()) {
944
    $controls->{$tag}->{"applied"} = 1 if (defined($controls->{$tag}));
945
  }
946
  $sth->finish();
947
  $dbh->disconnect();
948

  
949
  map({ $main::lxdebug->leave_sub() and return 1 if (!$_->{"applied"}) }
950
      values(%{$controls}));
951

  
952
  $main::lxdebug->leave_sub();
953
  return 0;
954
}
955

  
818 956
sub create_config {
819 957
  $main::lxdebug->enter_sub();
820 958

  
doc/sql-upgrade-dateien.txt
1
Neuer Mechanismus f?r SQL-Upgradedateien
2
----------------------------------------
3

  
4
Der alte Mechanismus f?r SQL-Upgradescripte, der auf einer
5
Versionsnummer beruht und dann in sql/Pg-upgrade nach einem Script f?r
6
diese Versionsnummer sucht, schr?nkt sehr ein, z.B. was die parallele
7
Entwicklung im stable- und unstable-Baum betrifft.
8

  
9
Dieser Mechanismus wurde f?r Lx-Office 2.4.1 deutlich erweitert. Es
10
werden weiterhin alle Scripte aus sql/Pg-upgrade
11
ausgef?hrt. Zus?tzlich gibt es aber ein zweites Verzeichnis,
12
sql/Pg-upgrade2. In diesem Verzeichnis muss pro Datenbankupgrade eine
13
Datei existieren, die neben den eigentlich auszuf?hrenden SQL- oder
14
Perl-Befehlen einige Kontrollinformationen enth?lt.
15

  
16
Neu sind die Kontrollinformationen, die Abh?ngigkeiten und Priorit?ten
17
definieren k?nnen werden, sodass Datenbankscripte zwar in einer
18
sicheren Reihenfolge ausgef?hrt werden (z.B. darf ein "ALTER TABLE"
19
erst ausgef?hrt werden, wenn die Tabelle mit "CREATE TABLE" angelegt
20
wurde), diese Reihenfolge aber so flexibel ist, dass man keine
21
Versionsnummern mehr braucht.
22

  
23
Lx-Office merkt sich dabei, welches der Upgradescripte in
24
sql/Pg-upgrade2 bereits durchgef?hrt wurde und f?hrt diese nicht
25
erneut aus. Dazu dient die Tabelle "schema_info", die bei der
26
Anmeldung automatisch angelegt wird.
27

  
28
Format der Kontrollinformationen
29
--------------------------------
30

  
31
Die Kontrollinformationen sollten sich am Anfang der jeweiligen
32
Upgradedatei befinden. Jede Zeile, die Kontrollinformationen enth?lt,
33
hat dabei das folgende Format:
34

  
35
F?r SQL-Upgradedateien:
36

  
37
-- @key: value
38

  
39

  
40
F?r Perl-Upgradedateien:
41

  
42
# @key: value
43

  
44

  
45
Leerzeichen vor "value" werden entfern.
46

  
47
Die folgenden Schl?sselworte werden verarbeitet:
48

  
49
* tag: Wird zwingend ben?tigt. Dies ist der "Name" des
50
  Upgrades. Dieser "tag" kann von anderen Kontrolldateien in ihren
51
  Abh?ngigkeiten verwendet werden (Schl?sselwort "depends"). Der "tag"
52
  ist auch der Name, der in der Datenbank eingetragen wird.
53

  
54
  Normalerweise sollte die Kontrolldatei genau so hei?en wie der
55
  "tag", nur mit der Endung ".sql" bzw. "pl".
56

  
57
  Ein Tag darf nur aus alphanumerischen Zeichen sowie den Zeichen _ -
58
  ( ) bestehen. Insbesondere sind Leerzeichen nicht erlaubt und
59
  sollten stattdessen mit Unterstrichen ersetzt werden.
60

  
61
* description: Ben?tigt. Eine Beschreibung, was in diesem Update
62
  passiert. Diese wird dem Benutzer beim eigentlichen Datenbankupdate
63
  angezeigt. W?hrend der Tag in englisch gehalten sein sollte, sollte
64
  die Beschreibung auf Deutsch erfolgen.
65

  
66
* depends: Optional. Eine mit Leerzeichen getrennte Liste von "tags",
67
  von denen dieses Upgradescript abh?ngt. Lx-Office stellt sicher,
68
  dass die in dieser Liste aufgef?hrten Scripte bereits durchgef?hrt
69
  wurden, bevor dieses Script ausgef?hrt wird.
70

  
71
  Abh?ngigkeiten werden rekursiv betrachtet. Wenn also ein Script "b"
72
  existiert, das von ?nderungen in "a" abh?ngt, und eine neue
73
  Kontrolldatei f?r "c" erstellt wird, die von ?nderungen in "a" und
74
  "b" abh?ngt, so gen?gt es, in "c" nur den Tag "b" als Abh?ngigkeit
75
  zu definieren.
76

  
77
  Es ist nicht erlaubt, sich selbst referenzierende Abh?ngigkeiten zu
78
  definieren (z.B. "a" -> "b", "b" -> "c" und "c" -> "a").
79

  
80
* priority: Optional. Ein Zahlenwert, der die Reihenfolge bestimmt, in
81
  der Scripte ausgef?hrt werden, die die gleichen Abh?ngigkeitstiefen
82
  besitzen. Fehlt dieser Parameter, so wird der Wert 1000 benutzt.
83

  
84
  Dies ist reine Kosmetik. F?r echte Reihenfolgen muss "depends"
85
  benutzt werden. Lx-Office sortiert die auszuf?hrenden Scripte zuerst
86
  nach der Abh?ngigkeitstiefe (wenn "z" von "y" abh?ngt und "y" von
87
  "x", so hat "z" eine Abh?ngigkeitstiefe von 2, "y" von 1 und "x" von
88
  0. "x" w?rde hier zuerst ausgef?hrt, dann "y", dann "z"), dann nach
89
  der Priorit?t und bei gleicher Priorit?t alphabetisch nach dem
90
  "tag".
91

  
92
Hilfsscript dbupgrade2_tool.pl
93
------------------------------
94

  
95
Um die Arbeit mit den Abh?ngigkeiten etwas zu erleichtern, existiert
96
ein Hilfsscript namens "scripts/dbupgrade2_tool.pl". Es muss aus dem
97
Lx-Office-ERP-Basisverzeichnis heraus aufgerufen werden. Dieses Tool
98
liest alle Datenbankupgradescripte aus dem Verzeichnis sql/Pg-upgrade2
99
aus. Es benutzt daf?r die gleichen Methoden wie Lx-Office selber,
100
sodass alle Fehlersituationen von der Kommandozeile ?berpr?ft werden
101
k?nnen.
102

  
103
Wird dem Script kein weiterer Parameter ?bergeben, so wird nur eine
104
?berpr?fung der Felder und Abh?ngigkeiten vorgenommen. Man kann sich
105
aber auch Informationen auf verschiedene Art ausgeben lassen:
106

  
107
1. Listenform: "./scripts/dbupgrade2_tool.pl --list"
108

  
109
   Gibt eine Liste aller Scripte aus. Die Liste ist in der Reihenfolge
110
   sortiert, in der Lx-Office die Scripte ausf?hren w?rde. Es werden
111
   neben der Listenposition der Tag, die Abh?ngigkeitstiefe und die
112
   Priorit?t ausgegeben.
113

  
114
2. Baumform: "./scripts/dbupgrade2_tool.pl --tree"
115

  
116
   Listet alle Tags in Baumform basierend auf den Abh?ngigkeiten
117
   auf. Die "Wurzelknoten" sind dabei die Scripte, von denen keine
118
   anderen abh?ngen. Die Unterknoten sind Scripte, die beim
119
   ?bergeordneten Script als Abh?ngigkeit eingetragen sind.
120

  
121
3. Umgekehrte Baumform: "./scripts/dbupgrade2_tool.pl --rtree"
122

  
123
   Listet alle Tags in Baumform basierend auf den Abh?ngigkeiten auf.
124
   Die "Wurzelknoten" sind dabei die Scripte mit der geringsten
125
   Abh?ngigkeitstiefe. Die Unterknoten sind Scripte, die das
126
   ?bergeordnete Script als Abh?ngigkeit eingetragen haben.
127

  
128
4. Baumform mit Postscriptausgabe: "./scripts/dbupgrade2_tool.pl --graphviz"
129

  
130
   Ben?tigt das Tool "graphviz", um mit seiner Hilfe die Baumform aus
131
   3. in eine Postscriptdatei namens "db_dependencies.ps"
132
   auszugeben. Dies ist vermutlich die ?bersichtlichste Form, weil
133
   hierbei jeder Knoten nur einmal ausgegeben wird. Bei den
134
   Textmodusbaumformen hingegen k?nnen Knoten und all ihre
135
   Abh?ngigkeiten mehrfach ausgegeben werden.
136

  
137
5. Scripte, von denen kein anderes Script abh?ngt:
138
   "./scripts/dbupgrade2_tool.pl --nodeps"
139

  
140
   Listet die Tags aller Scripte auf, von denen keine anderen Scripte
141
   abh?ngen.
142

  
locale/de/admin
29 29
  'Date Format'                 => 'Datumsformat',
30 30
  'Delete'                      => 'L?schen',
31 31
  'Delete Dataset'              => 'Datenbank l?schen',
32
  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
32 33
  'Directory'                   => 'Verzeichnis',
33 34
  'Driver'                      => 'Treiber',
34 35
  'Dropdown Limit'              => 'Auswahllistenbegrenzung',
35 36
  'E-mail'                      => 'eMail',
36 37
  'Edit User'                   => 'Benutzerdaten bearbeiten',
38
  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
37 39
  'Existing Datasets'           => 'existierende Datenbanken',
38 40
  'Fax'                         => 'Fax',
39 41
  'File locked!'                => 'Datei gesperrt!',
......
48 50
  'Login'                       => 'Anmeldung',
49 51
  'Login name missing!'         => 'Loginname fehlt.',
50 52
  'Manager'                     => 'Manager',
53
  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
54
  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
55
  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
51 56
  'Multibyte Encoding'          => 'Schriftsatz',
52 57
  'Name'                        => 'Name',
53 58
  'New Templates'               => 'neue Vorlagen',
......
72 77
  'Stylesheet'                  => 'Stilvorlage',
73 78
  'Supervisor'                  => 'Supervisor',
74 79
  'Templates'                   => 'Vorlagen',
80
  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
75 81
  'The following Datasets are not in use and can be deleted' => 'Die folgenden Datenbanken sind nicht in Verwendung und k?nnen gel?scht werden',
76 82
  'The following Datasets need to be updated' => 'Folgende Datenbanken m?ssen aktualisiert werden',
77 83
  'The passwords do not match.' => 'Die Passw&ouml;rter stimmen nicht &uuml;berein.',
78 84
  'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'In diesem Schritt werden bestehende Datenbanken gesucht. Es werden noch keine ?nderungen vorgenommen!',
79 85
  'To add a user to a group edit a name, change the login name and save.  A new user with the same variables will then be saved under the new login name.' => 'Um einer Gruppe einen neuen Benutzer hinzuzuf?gen, ?ndern und speichern Sie am einfachsten einen bestehen den Zugriffsnamen. Unter dem neuen Namen wird dann ein Benutzer mit denselben Einstellungen angelegt.',
86
  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
80 87
  'Unlock System'               => 'System entsperren',
81 88
  'Update Dataset'              => 'Datenbank aktualisieren',
82 89
  'Use Templates'               => 'benutze Vorlagen',
locale/de/all
96 96
  'Ansprechpartner'             => '',
97 97
  'Application Error. No Format given!' => 'Fehler in der Anwendung. Das Format fehlt.',
98 98
  'Application Error. Wrong Format: ' => 'Fehler in der Anwendung. Falsches Format: ',
99
  'Applying <TMPL_VAR file ESCAPE=HTML>:' => 'F&uuml;hre <TMPL_VAR file ESCAPE=HTML> aus:',
99 100
  'Apr'                         => 'Apr',
100 101
  'April'                       => 'April',
101 102
  'Are you sure you want to delete Invoice Number' => 'Soll die Rechnung mit folgender Nummer wirklich gel?scht werden:',
......
322 323
  'Department deleted!'         => 'Abteilung gel?scht.',
323 324
  'Department saved!'           => 'Abteilung gespeichert.',
324 325
  'Departments'                 => 'Abteilungen',
326
  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
325 327
  'Deposit'                     => 'Gutschrift',
326 328
  'Description'                 => 'Beschreibung',
327 329
  'Description missing!'        => 'Beschreibung fehlt.',
......
416 418
  'Erl?se EU o. UStId'          => 'Erl&ouml;se EU o. UStId',
417 419
  'Erl?se Inland'               => 'Erl&ouml;se Inland',
418 420
  'Error'                       => 'Fehler',
421
  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
419 422
  'Error!'                      => 'Fehler!',
420 423
  'Exch'                        => 'Wechselkurs.',
421 424
  'Exchangerate'                => 'Wechselkurs',
......
621 624
  'Method'                      => 'Verfahren',
622 625
  'Microfiche'                  => 'Mikrofilm',
623 626
  'Minimum Amount'              => 'Mindestbetrag',
627
  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
628
  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
624 629
  'Missing Method!'             => 'Fehlender Voranmeldungszeitraum',
625 630
  'Missing Preferences: Outputroutine disabled' => 'Die Ausgabefunktionen sind wegen unzureichender Voreinstellungen deaktiviert!',
626 631
  'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
......
630 635
  'Model'                       => 'Modell',
631 636
  'Monat'                       => 'Monat',
632 637
  'Monthly'                     => 'monatlich',
638
  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
633 639
  'Multibyte Encoding'          => 'Schriftsatz',
634 640
  'MwSt. inkl.'                 => 'MwSt. inkl.',
635 641
  'N/A'                         => 'N.Z.',
......
945 951
  'Templates'                   => 'Vorlagen',
946 952
  'Terms missing in row '       => '+Tage fehlen in Zeile ',
947 953
  'Terms: Net'                  => 'Zahlungsziel',
954
  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
948 955
  'The base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gel&ouml;scht werden.',
949 956
  'The base unit does not exist.' => 'Die Basiseinheit existiert nicht.',
950 957
  'The base unit relations must not contain loops (e.g. by saying that unit A\'s base unit is B, B\'s base unit is C and C\'s base unit is A) in row %d.' => 'Die Beziehungen der Einheiten d&uuml;rfen keine Schleifen beinhalten (z.B. wenn gesagt wird, dass Einheit As Basiseinheit B, Bs Basiseinheit C und Cs Basiseinheit A ist) in Zeile %d.',
......
1054 1061
  'Unit'                        => 'Einheit',
1055 1062
  'Unit of measure'             => 'Ma?einheit',
1056 1063
  'Units'                       => 'Einheiten',
1064
  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
1057 1065
  'Unlock System'               => 'System entsperren',
1058 1066
  'Until'                       => 'Bis',
1059 1067
  'Update'                      => 'Erneuern',
locale/de/am
71 71
  'Department deleted!'         => 'Abteilung gel?scht.',
72 72
  'Department saved!'           => 'Abteilung gespeichert.',
73 73
  'Departments'                 => 'Abteilungen',
74
  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
74 75
  'Description'                 => 'Beschreibung',
75 76
  'Description missing!'        => 'Beschreibung fehlt.',
76 77
  'Discount'                    => 'Rabatt',
......
99 100
  'Erl?se EU m. UStId'          => 'Erl&ouml;se EU m. UStId',
100 101
  'Erl?se EU o. UStId'          => 'Erl&ouml;se EU o. UStId',
101 102
  'Erl?se Inland'               => 'Erl&ouml;se Inland',
103
  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
102 104
  'Expense'                     => 'Aufwandskonto',
103 105
  'Expense Account'             => 'Aufwandskonto',
104 106
  'Expense/Asset'               => 'Aufwand/Anlagen',
......
138 140
  'Link'                        => 'Verkn?pfungen',
139 141
  'Long Dates'                  => 'Lange Monatsnamen',
140 142
  'Long Description'            => 'Langtext',
143
  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
144
  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
145
  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
141 146
  'Name'                        => 'Name',
142 147
  'Netto Terms'                 => 'Zahlungsziel netto',
143 148
  'No'                          => 'Nein',
......
197 202
  'Template Code'               => 'Vorlagenk?rzel',
198 203
  'Template Code missing!'      => 'Vorlagenk?rzel fehlt!',
199 204
  'Template saved!'             => 'Schablone gespeichert!',
205
  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
200 206
  'The base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gel&ouml;scht werden.',
201 207
  'The base unit does not exist.' => 'Die Basiseinheit existiert nicht.',
202 208
  'The base unit relations must not contain loops (e.g. by saying that unit A\'s base unit is B, B\'s base unit is C and C\'s base unit is A) in row %d.' => 'Die Beziehungen der Einheiten d&uuml;rfen keine Schleifen beinhalten (z.B. wenn gesagt wird, dass Einheit As Basiseinheit B, Bs Basiseinheit C und Cs Basiseinheit A ist) in Zeile %d.',
......
256 262
  'UStVA-Nr. 98'                => 'Kz. 98',
257 263
  'Umsatzsteuervoranmeldung'    => 'Umsatzsteuervoranmeldung',
258 264
  'Unit'                        => 'Einheit',
265
  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
259 266
  'Value'                       => 'Wert',
260 267
  'Variable'                    => 'Variable',
261 268
  'Warehouse deleted!'          => 'Das Lager wurde gel?scht.',
locale/de/locales.pl
15 15
$basedir  = "../..";
16 16
$bindir   = "$basedir/bin/mozilla";
17 17
$dbupdir  = "$basedir/sql/Pg-upgrade";
18
$dbupdir2 = "$basedir/sql/Pg-upgrade2";
18 19
$menufile = "menu.ini";
19 20
$submitsearch = qr/type\s*=\s*[\"\']?submit/i;
20 21

  
......
45 46
@dbplfiles = grep { /\.pl$/ } readdir DIR;
46 47
closedir DIR;
47 48

  
49
opendir DIR, $dbupdir2 or die "$!";
50
@dbplfiles2 = grep { /\.pl$/ } readdir DIR;
51
closedir DIR;
52

  
48 53
# slurp the translations in
49 54
if (-f 'all') {
50 55
  require "all";
......
59 64

  
60 65
map({ handle_file($_, $bindir); } @progfiles);
61 66
map({ handle_file($_, $dbupdir); } @dbplfiles);
67
map({ handle_file($_, $dbupdir2); } @dbplfiles2);
62 68

  
63 69
sub handle_file {
64 70
  my ($file, $dir) = @_;
locale/de/login
3 3
  'Database Host'               => 'Datenbankcomputer',
4 4
  'Dataset'                     => 'Datenbank',
5 5
  'Dataset upgrade'             => 'Datenbankaktualisierung',
6
  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
7
  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
6 8
  'Incorrect username or password!' => 'Ung?ltiger Benutzername oder falsches Passwort!',
7 9
  'Licensed to'                 => 'Lizensiert f?r',
8 10
  'Login'                       => 'Anmeldung',
9 11
  'Login Name'                  => 'Benutzername',
12
  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
13
  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
14
  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
10 15
  'Password'                    => 'Passwort',
16
  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
17
  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
11 18
  'User'                        => 'Benutzer',
12 19
  'Version'                     => 'Version',
13 20
  'You are logged out!'         => 'Auf Wiedersehen!',
locale/de/ustva
32 32
  'Dauerfristverl?ngerung'      => 'Dauerfristverl?ngerung',
33 33
  'Dec'                         => 'Dez',
34 34
  'December'                    => 'Dezember',
35
  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
35 36
  'Description'                 => 'Beschreibung',
36 37
  'ELSTER Export nach Taxbird'  => 'ELSTER-Export nach Taxbird',
37 38
  'ELSTER Export nach Winston'  => 'ELSTER Export nach Winston',
38 39
  'ELSTER-Steuernummer: '       => 'ELSTER-Steuernummer: ',
40
  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
39 41
  'Fax'                         => 'Fax',
40 42
  'Fax. : '                     => 'Fax. : ',
41 43
  'Fax.: '                      => 'Fax.: ',
......
69 71
  'May'                         => 'Mai',
70 72
  'May '                        => 'Mai',
71 73
  'Method'                      => 'Verfahren',
74
  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
75
  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
72 76
  'Missing Method!'             => 'Fehlender Voranmeldungszeitraum',
73 77
  'Missing Preferences: Outputroutine disabled' => 'Die Ausgabefunktionen sind wegen unzureichender Voreinstellungen deaktiviert!',
74 78
  'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
79
  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
75 80
  'Name'                        => 'Name',
76 81
  'Nov'                         => 'Nov',
77 82
  'November'                    => 'November',
......
93 98
  'Tel. : '                     => 'Tel. : ',
94 99
  'Tel.: '                      => 'Tel.: ',
95 100
  'Telefon'                     => 'Telefon',
101
  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
96 102
  'USTVA-Hint: Method'          => 'Wenn Sie Ist-Versteuert sind, w?hlen Sie die Einnahmen-/?berschu?-Rechnung aus. Sind Sie Soll-Versteuert und bilanzverpflichtet, dann w?hlen Sie Bilanz aus.',
97 103
  'USTVA-Hint: Tax Authoritys'  => 'Bitte das Bundesland UND die Stadt bzw. den Einzugsbereich Ihres zust?ndigen Finanzamts ausw?hlen.',
98 104
  'UStVA'                       => 'UStVA',
99 105
  'UStVA als PDF-Dokument'      => 'UStVa als PDF-Dokument',
106
  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
100 107
  'Vendor not on file!'         => 'Lieferant ist nicht in der Datenbank!',
101 108
  'Verfahren'                   => 'Verfahren',
102 109
  'Verrechnung des Erstattungsbetrages erw?nscht (Zeile 71)' => 'Verrechnung des Erstattungsbetrages erw?nscht (Zeile 71)',
scripts/dbupgrade2_tool.pl
1
#!/usr/bin/perl
2

  
3
BEGIN {
4
  if (! -d "bin" || ! -d "SL") {
5
    print("This tool must be run from the Lx-Office ERP base directory.\n");
6
    exit(1);
7
  }
8
}
9

  
10
use DBI;
11
use Data::Dumper;
12
use Getopt::Long;
13

  
14
use SL::LXDebug;
15

  
16
$lxdebug = LXDebug->new();
17

  
18
use SL::Form;
19
use SL::DBUpgrade2;
20

  
21
#######
22
#######
23
#######
24

  
25
sub show_help {
26
  print("dbupgrade2_tool.pl [--list] [--tree] [--rtree] [--graphviz]\n" .
27
        "                   [--nodepds] [--help]\n");
28
}
29

  
30
sub calc_rev_depends {
31
  map({ $_->{"rev_depends"} = []; } values(%{$controls}));
32
  foreach my $control (values(%{$controls})) {
33
    map({ push(@{$controls->{$_}{"rev_depends"}}, $control->{"tag"}) }
34
        @{$control->{"depends"}});
35
  }
36
}
37

  
38
sub dump_list {
39
  my @sorted_controls = sort_dbupdate_controls($controls);
40

  
41
  print("LIST VIEW\n\n");
42
  print("number tag depth priority\n");
43
  $i = 0;
44
  foreach (@sorted_controls) {
45
    print("$i $_->{tag} $_->{depth} $_->{priority}\n");
46
    $i++;
47
  }
48

  
49
  print("\n");
50
}
51

  
52
sub dump_node {
53
  my ($tag, $depth) = @_;
54

  
55
  print(" " x $depth . $tag . "\n");
56

  
57
  my $c = $controls->{$tag};
58
  my $num = scalar(@{$c->{"depends"}});
59
  for (my $i = 0; $i < $num; $i++) {
60
    dump_node($c->{"depends"}[$i], $depth + 1);
61
  }
62
}
63

  
64
sub dump_tree {
65
  print("TREE VIEW\n\n");
66

  
67
  calc_rev_depends();
68

  
69
  my @sorted_controls = sort_dbupdate_controls($controls);
70

  
71
  foreach my $control (@sorted_controls) {
72
    dump_node($control->{"tag"}, "") unless (@{$control->{"rev_depends"}});
73
  }
74

  
75
  print("\n");
76
}
77

  
78
sub dump_node_reverse {
79
  my ($tag, $depth) = @_;
80

  
81
  print(" " x $depth . $tag . "\n");
82

  
83
  my $c = $controls->{$tag};
84
  my $num = scalar(@{$c->{"rev_depends"}});
85
  for (my $i = 0; $i < $num; $i++) {
86
    dump_node_reverse($c->{"rev_depends"}[$i], $depth + 1);
87
  }
88
}
89

  
90
sub dump_tree_reverse {
91
  print("REVERSE TREE VIEW\n\n");
92

  
93
  calc_rev_depends();
94

  
95
  my @sorted_controls = sort_dbupdate_controls($controls);
96

  
97
  foreach my $control (@sorted_controls) {
98
    last if ($control->{"depth"} > 1);
99
    dump_node_reverse($control->{"tag"}, "");
100
  }
101

  
102
  print("\n");
103
}
104

  
105
sub dump_graphviz {
106
  print("GRAPHVIZ POSTCRIPT\n\n");
107
  print("Output will be written to db_dependencies.ps\n");
108
  $dot = "|dot -Tps ";
109
  open(OUT, "${dot}> db_dependencies.ps");
110
  print(OUT
111
        "digraph db_dependencies {\n" .
112
        "node [shape=box];\n");
113
  my %ranks;
114
  foreach my $c (values(%{$controls})) {
115
    $ranks{$c->{"depth"}} = [] unless ($ranks{$c->{"depth"}});
116
    push(@{$ranks{$c->{"depth"}}}, $c->{"tag"});
117
  }
118
  foreach (sort(keys(%ranks))) {
119
    print(OUT "{ rank = same; " .
120
          join("", map({ '"' . $_ . '"; ' } @{$ranks{$_}})) .
121
          " }\n");
122
  }
123
  foreach my $c (values(%{$controls})) {
124
    print(OUT "$c->{tag};\n");
125
    foreach my $d (@{$c->{"depends"}}) {
126
      print(OUT "$c->{tag} -> $d;\n");
127
    }
128
  }
129
  print(OUT "}\n");
130
  close(OUT);
131
}
132

  
133
sub dump_nodeps {
134
  calc_rev_depends();
135

  
136
  print("SCRIPTS NO OTHER SCRIPTS DEPEND ON\n\n" .
137
        join("\n",
138
             map({ $_->{"tag"} }
139
                 grep({ !@{$_->{"rev_depends"}} }
140
                      values(%{$controls})))) .
141
        "\n\n");
142
}
143

  
144
#######
145
#######
146
#######
147

  
148
eval { require "lx-erp.conf"; };
149

  
150
$form = Form->new();
151
$locale = Locale->new("de", "login");
152

  
153
#######
154
#######
155
#######
156

  
157
my ($opt_list, $opt_tree, $opt_rtree, $opt_nodeps, $opt_graphviz, $opt_help);
158

  
159
GetOptions("list" => \$opt_list,
160
           "tree" => \$opt_tree,
161
           "rtree" => \$opt_rtree,
162
           "nodeps" => \$opt_nodeps,
163
           "graphviz" => \$opt_graphviz,
164
           "help" => \$opt_help,
165
  );
166

  
167
if ($opt_help) {
168
  show_help();
169
  exit(0);
170
}
171

  
172
$controls = parse_dbupdate_controls($form, "Pg");
173

  
174
if ($opt_list) {
175
  dump_list();
176
}
177

  
178
if ($opt_tree) {
179
  dump_tree();
180
}
181

  
182
if ($opt_rtree) {
183
  dump_tree_reverse();
184
}
185

  
186
if ($opt_graphviz) {
187
  dump_graphviz();
188
}
189

  
190
if ($opt_nodeps) {
191
  dump_nodeps();
192
}
sql/Pg-upgrade/Pg-upgrade-2.4.0.0-2.4.0.1.sql
1
ALTER TABLE language ADD COLUMN output_numberformat text;
2
ALTER TABLE language ADD COLUMN output_dateformat text;
3
ALTER TABLE language ADD COLUMN output_longdates boolean;
sql/Pg-upgrade/Pg-upgrade-2.4.0.1-2.4.0.2.sql
1
CREATE TABLE units_language (
2
       unit varchar (20) NOT NULL,
3
       language_id integer NOT NULL,
4
       localized varchar (20),
5
       localized_plural varchar (20),
6

  
7
       FOREIGN KEY (unit) REFERENCES units (name),
8
       FOREIGN KEY (language_id) REFERENCES language (id)
9
);
10
CREATE INDEX units_name_idx ON units (name);
11
CREATE INDEX units_language_unit_idx ON units_language (unit);
sql/Pg-upgrade/Pg-upgrade-2.4.0.2-2.4.0.3.sql
1
update tax set id=0 WHERE taxkey=0;
sql/Pg-upgrade2/README
1
Bitte lesen Sie die Datei doc/sql-upgrade-dateien.txt, bevor
2
Sie hier Dateien anlegen.
3

  
sql/Pg-upgrade2/language_output_formatting.sql
1
-- @tag: language_output_formatting
2
-- @description: Speichern des Ausgabeformates f&uuml;r Zahlen und Datumsangaben bei jeder Sprache.
3
-- @depends:
4
ALTER TABLE language ADD COLUMN output_numberformat text;
5
ALTER TABLE language ADD COLUMN output_dateformat text;
6
ALTER TABLE language ADD COLUMN output_longdates boolean;
sql/Pg-upgrade2/tax_id_if_taxkey_is_0.sql
1
-- @tag: tax_id_if_taxkey_is_0
2
-- @description: Aktualisierung der Spalte tax.id, wenn tax.taxkey = 0 ist.
3
-- @depends:
4
UPDATE tax SET id = 0 WHERE taxkey = 0;
sql/Pg-upgrade2/units_translations_and_singular_plural_distinction.sql
1
-- @tag: units_translations_and_singular_plural_distinction
2
-- @description: F&uuml;r jede Einheit kann f&uuml;r jede Sprache eine &Uuml;bersetzung sowie eine Unterscheidung zwischen Singular und Plural gespeichert werden.
3
-- @depends:
4
CREATE TABLE units_language (
5
       unit varchar (20) NOT NULL,
6
       language_id integer NOT NULL,
7
       localized varchar (20),
8
       localized_plural varchar (20),
9

  
10
       FOREIGN KEY (unit) REFERENCES units (name),
11
       FOREIGN KEY (language_id) REFERENCES language (id)
12
);
13
CREATE INDEX units_name_idx ON units (name);
14
CREATE INDEX units_language_unit_idx ON units_language (unit);
templates/webpages/dbupgrade/upgrade_message2_de.html
1
F&uuml;hre <TMPL_VAR file ESCAPE=HTML> aus: <TMPL_VAR description ESCAPE=HTML><br>
templates/webpages/dbupgrade/upgrade_message2_master.html
1
<translate>Applying <TMPL_VAR file ESCAPE=HTML>:</translate> <TMPL_VAR description ESCAPE=HTML><br>

Auch abrufbar als: Unified diff