Parcourir la source

migration from Mysql to PostgreSQL added

Roman Dmitriev il y a 3 mois
Parent
commit
4375217a69

+ 227 - 0
docs/databases/migrate2psql.pl

@@ -0,0 +1,227 @@
+#!/usr/bin/perl
+
+#
+# Copyright (C) Roman Dmitriev, rnd@rajven.ru
+#
+
+use utf8;
+use open ":encoding(utf8)";
+use open ':std', ':encoding(UTF-8)';
+use Encode;
+no warnings 'utf8';
+use English;
+use FindBin '$Bin';
+use lib "/opt/Eye/scripts";
+use Getopt::Long qw(GetOptions);
+use Data::Dumper;
+use eyelib::config;
+use eyelib::main;
+use eyelib::database;
+use eyelib::common;
+use eyelib::net_utils;
+use strict;
+use warnings;
+
+sub get_table_columns {
+    my ($db, $table) = @_;
+    my $sth = $db->column_info(undef, undef, $table, '%');
+    my @cols;
+    while (my $row = $sth->fetchrow_hashref) {
+        push @cols, $row->{COLUMN_NAME};
+    }
+    return @cols;
+}
+
+sub batch_sql_cached {
+    my ($db, $sql, $data) = @_;
+    eval {
+        my $sth = $db->prepare_cached($sql) or die "Unable to prepare SQL: " . $db->errstr;
+        for my $params (@$data) {
+            next unless @$params;
+            $sth->execute(@$params) or die "Unable to execute with params [" . join(',', @$params) . "]: " . $sth->errstr;
+        }
+        $db->commit() if (!$db->{AutoCommit});
+        1;
+    } or do {
+        my $err = $@ || 'Unknown error';
+        eval { $db->rollback() };
+        print "batch_db_sql_cached failed: $err";
+	return 0;
+    };
+    return 1;
+}
+
+# debug disable force
+$debug = 0;
+
+# === Разбор аргументов командной строки ===
+my $opt_clear = 0;
+my $opt_batch = 0;
+GetOptions(
+    'clear' => \$opt_clear,
+    'batch' => \$opt_batch,
+) or die "Usage: $0 [--clear] [--batch]\n";
+
+# === Явное указание портов ===
+my $MYSQL_PORT = 3306;
+my $PG_PORT    = 5432;
+
+# === Подключение к MySQL (источник) ===
+my $mysql_dsn = "dbi:mysql:database=$DBNAME;host=$DBHOST;port=$MYSQL_PORT;mysql_local_infile=1";
+my $mysql_db = DBI->connect($mysql_dsn, $DBUSER, $DBPASS, {
+    RaiseError => 0,
+    AutoCommit => 1,
+    mysql_enable_utf8 => 1
+});
+if (!defined $mysql_db) {
+    die "Cannot connect to MySQL server: $DBI::errstr\n";
+}
+$mysql_db->do('SET NAMES utf8mb4');
+
+# === Подключение к PostgreSQL (цель) ===
+my $pg_dsn = "dbi:Pg:dbname=$DBNAME;host=$DBHOST;port=$PG_PORT;";
+my $pg_db = DBI->connect($pg_dsn, $DBUSER, $DBPASS, {
+    RaiseError => 0,
+    AutoCommit => 1,
+    pg_enable_utf8 => 1,
+    pg_server_prepare => 0
+});
+if (!defined $pg_db) {
+    print "Cannot connect to PostgreSQL server: $DBI::errstr\n";
+    print "For install/configure PostgreSQL server please run migrate2psql.sh!\n";
+    exit 100;
+}
+
+# === Получение списка таблиц ===
+print "Fetching table list from MySQL...\n";
+my @migration_tables = get_records_sql($mysql_db, 'SHOW TABLES');
+my %tables;
+my $table_index = 'Tables_in_' . $DBNAME;
+
+foreach my $row (@migration_tables) {
+    next unless $row && exists $row->{$table_index};
+    my $table_name = $row->{$table_index};
+    # Пропускаем traffic_detail (слишком большая)
+    $tables{$table_name} = ($table_name !~ /(traffic_detail|sessions)/) ? 1 : 0;
+}
+
+# Фильтруем только те, что будем мигрировать
+my @tables_to_migrate = sort grep { $tables{$_} } keys %tables;
+my $total_tables = scalar @tables_to_migrate;
+
+if ($total_tables == 0) {
+    print "No tables to migrate!\n";
+    exit 0;
+}
+
+# === Опционально: очистка всех таблиц перед импортом ===
+if ($opt_clear) {
+    print "\n⚠️  --clear mode: Truncating all target tables before import...\n";
+    for my $table (@tables_to_migrate) {
+        eval {
+            $pg_db->do("TRUNCATE TABLE \"$table\" RESTART IDENTITY");
+        };
+        if ($@) {
+            chomp $@;
+            print "  ⚠️  Failed to truncate table '$table': $@\n";
+        } else {
+            print "  → Truncated: $table\n";
+        }
+    }
+    print "\n";
+}
+
+print "\n=== Starting migration of $total_tables tables ===\n\n";
+
+# === Миграция по таблицам с прогрессом ===
+for my $idx (0 .. $#tables_to_migrate) {
+    my $table = $tables_to_migrate[$idx];
+    my $table_num = $idx + 1;
+
+    print "[$table_num/$total_tables] Processing table: $table\n";
+
+    my $rec_count = get_count_records($mysql_db, $table);
+    print "  → Expected records: $rec_count\n";
+
+    if ($rec_count == 0) {
+        print "  → Empty table. Skipping.\n\n";
+        next;
+    }
+
+    # === Построчное чтение ===
+    my $select_sth = $mysql_db->prepare("SELECT * FROM `$table`");
+    $select_sth->execute();
+
+    my $inserted = 0;
+    my $errors   = 0;
+
+# === Режим вставки: построчный или пакетный ===
+if ($opt_batch) {
+    print "  → Using BATCH mode (500 records per chunk)\n";
+
+    # Получаем список колонок один раз
+    my @columns = get_table_columns($mysql_db, $table);
+    my $quoted_columns = '"' . join('", "', @columns) . '"';
+    my $placeholders = join(', ', ('?') x @columns);
+    my $insert_sql = "INSERT INTO \"$table\" ($quoted_columns) VALUES ($placeholders)";
+
+    my @batch_buffer;
+    my $chunk_size = 500;
+
+    while (my $row = $select_sth->fetchrow_hashref) {
+	my @values;
+        for my $key (@columns) {
+	    my $value = $row->{$key};
+    	    if (lc($key) eq 'ip') {
+        	$value = undef if !defined($value) || $value eq '';
+    		}
+            push @values, $value;
+	    }
+        push @batch_buffer, \@values;
+        if (@batch_buffer >= 500) {
+	    my $insert_status = batch_sql_cached($pg_db, $insert_sql, \@batch_buffer);
+	    if ($insert_status) { $inserted += @batch_buffer; } else { $errors+=@batch_buffer; }
+            @batch_buffer = ();
+	    }
+    }
+    # Остаток
+    if (@batch_buffer) {
+	my $insert_status = batch_sql_cached($pg_db, $insert_sql, \@batch_buffer);
+        if ($insert_status) { $inserted += @batch_buffer; } else { $errors+=@batch_buffer; }
+	}
+    } else {
+    # === построчный режим ===
+    while (my $row = $select_sth->fetchrow_hashref) {
+        # === Приведение имён полей к нижнему регистру ===
+        my %row_normalized;
+        while (my ($key, $value) = each %$row) {
+	    my $n_key = lc($key);
+	    if ($n_key eq 'ip') {
+		if (!defined $value || $value eq '') { $value = undef; }
+		}
+            $row_normalized{$n_key} = $value;
+        }
+
+        my $ret_id = insert_record($pg_db, $table, \%row_normalized);
+	if ($ret_id>0) { $inserted++; } else {
+            $errors++;
+	    print Dumper(\%row_normalized) if ($debug);
+    	    }
+    }
+    $select_sth->finish();
+    }
+
+    # === Итог по таблице ===
+    my $status = ($errors == 0) ? "✅ SUCCESS" : "⚠️  COMPLETED WITH ERRORS";
+    print "  → Result: $status\n";
+    print "     Inserted: $inserted | Errors: $errors | Expected: $rec_count\n";
+    
+    if ($inserted + $errors != $rec_count) {
+        print "    ❗ WARNING: Record count mismatch! (source: $rec_count, processed: " . ($inserted + $errors) . ")\n";
+    }
+    
+    print "\n";
+}
+
+print "🎉 Migration completed! Processed $total_tables tables.\n";
+exit 0;

+ 4 - 11
docs/databases/migrate2psql.sh

@@ -153,15 +153,6 @@ update_system() {
     $PACKAGE_MANAGER update -y
 }
 
-upgrade_system() {
-    print_step "Updating system"
-    if [[ "$PACKAGE_MANAGER" == "apt-get" ]]; then
-        apt-get dist-upgrade -y
-    else
-        $PACKAGE_MANAGER upgrade -y
-    fi
-}
-
 # Install packages
 install_packages() {
     print_step "Installing packages"
@@ -263,7 +254,7 @@ EOF
 
     if [[ $? -ne 0 ]]; then
         print_error "Error importing create_db.sql"
-        return 1
+        exit 102
     fi
 
     print_info "Database structure imported successfully"
@@ -365,7 +356,7 @@ eye_migrate2pgsql() {
     setup_database
     
     #data migration
-    /opt/Eye/scripts/docs/databases/migrate2psql.pl
+    /opt/Eye/docs/databases/migrate2psql.pl --clear
     
     if [ $? -eq 0 ]; then
 	setup_configs
@@ -476,6 +467,8 @@ if [[ "$DB_TYPE" == "postgresql" ]]; then
     exit 0
 fi
 
+DB_TYPE="postgresql"
+
 if [[ -f "$PHP_CONFIG" ]]; then
     # Извлекаем язык
     if HTML_LANG=$(grep -oP 'define\s*\(\s*"HTML_LANG"\s*,\s*"\K[^"]+' "$PHP_CONFIG" 2>/dev/null); then

+ 2 - 2
docs/databases/mysql/en/create_db.sql

@@ -85,7 +85,7 @@ CREATE TABLE `devices` (
   `protocol` int(11) NOT NULL DEFAULT 0,
   `control_port` int(11) NOT NULL DEFAULT 23,
   `port_count` int(11) NOT NULL DEFAULT 0,
-  `SN` varchar(80) DEFAULT NULL,
+  `sn` varchar(80) DEFAULT NULL,
   `description` varchar(255) DEFAULT NULL,
   `snmp_version` tinyint(4) NOT NULL DEFAULT 0,
   `snmp3_auth_proto` varchar(10) NOT NULL DEFAULT 'sha512',
@@ -355,7 +355,7 @@ CREATE TABLE `user_auth` (
   `description` varchar(250) DEFAULT NULL,
   `dns_name` varchar(253) DEFAULT NULL,
   `dns_ptr_only` tinyint(1) NOT NULL DEFAULT 0,
-  `WikiName` varchar(250) DEFAULT NULL,
+  `wikiname` varchar(250) DEFAULT NULL,
   `dhcp_acl` text DEFAULT NULL,
   `queue_id` int(11) NOT NULL DEFAULT 0,
   `mac` varchar(20) NOT NULL DEFAULT '',

+ 1 - 1
docs/databases/mysql/reset_admin.sql

@@ -1,3 +1,3 @@
 --- default user: admin
 --- default password admin
-INSERT INTO `customers` (`id`, `Login`, `password`, `api_key`,`rights`) VALUES (1, 'admin', '$2y$11$wohV8Tuqu0Yai9Shacei5OKfMxG5bnLxB5ACcZcJJ3pYEbIH0qLGG', 'c3284d0f94606de1fd2af172aba15bf31','1') ON DUPLICATE KEY UPDATE Login="admin", password="$2y$11$wohV8Tuqu0Yai9Shacei5OKfMxG5bnLxB5ACcZcJJ3pYEbIH0qLGG";
+INSERT INTO `customers` (`id`, `login`, `password`, `api_key`,`rights`) VALUES (1, 'admin', '$2y$11$wohV8Tuqu0Yai9Shacei5OKfMxG5bnLxB5ACcZcJJ3pYEbIH0qLGG', 'c3284d0f94606de1fd2af172aba15bf31','1') ON DUPLICATE KEY UPDATE login="admin", password="$2y$11$wohV8Tuqu0Yai9Shacei5OKfMxG5bnLxB5ACcZcJJ3pYEbIH0qLGG";

+ 4 - 4
docs/databases/mysql/ru/create_db.sql

@@ -85,7 +85,7 @@ CREATE TABLE `devices` (
   `protocol` int(11) NOT NULL DEFAULT 0,
   `control_port` int(11) NOT NULL DEFAULT 23,
   `port_count` int(11) NOT NULL DEFAULT 0,
-  `SN` varchar(80) DEFAULT NULL,
+  `sn` varchar(80) DEFAULT NULL,
   `description` varchar(255) DEFAULT NULL,
   `snmp_version` tinyint(4) NOT NULL DEFAULT 0,
   `snmp3_auth_proto` varchar(10) NOT NULL DEFAULT 'sha512',
@@ -323,8 +323,8 @@ CREATE TABLE `traffic_detail` (
   `router_id` int(11) NOT NULL DEFAULT 0,
   `ts` timestamp NULL DEFAULT NULL,
   `proto` tinyint(3) UNSIGNED DEFAULT NULL,
-  `src_ip` int(10) UNSIGNED NOT NULL,
-  `dst_ip` int(10) UNSIGNED NOT NULL,
+  `src_ip` bigint(20) NOT NULL DEFAULT 0,
+  `dst_ip` bigint(20) NOT NULL DEFAULT 0,
   `src_port` smallint(5) UNSIGNED NOT NULL,
   `dst_port` smallint(5) UNSIGNED NOT NULL,
   `bytes` bigint(20) NOT NULL,
@@ -355,7 +355,7 @@ CREATE TABLE `user_auth` (
   `description` varchar(250) DEFAULT NULL,
   `dns_name` varchar(253) DEFAULT NULL,
   `dns_ptr_only` tinyint(1) NOT NULL DEFAULT 0,
-  `WikiName` varchar(250) DEFAULT NULL,
+  `wikiname` varchar(250) DEFAULT NULL,
   `dhcp_acl` text DEFAULT NULL,
   `queue_id` int(11) NOT NULL DEFAULT 0,
   `mac` varchar(20) NOT NULL DEFAULT '',

+ 2 - 2
docs/databases/postgres/en/create_db.sql

@@ -114,7 +114,7 @@ password VARCHAR(255),
 protocol SMALLINT NOT NULL DEFAULT 0,
 control_port INTEGER NOT NULL DEFAULT 23,
 port_count INTEGER NOT NULL DEFAULT 0,
-SN VARCHAR(80),
+sn VARCHAR(80),
 description VARCHAR(255),
 snmp_version SMALLINT NOT NULL DEFAULT 0,
 snmp3_auth_proto VARCHAR(10) NOT NULL DEFAULT 'sha512',
@@ -469,7 +469,7 @@ deleted SMALLINT NOT NULL DEFAULT 0,
 description VARCHAR(250),
 dns_name VARCHAR(253),
 dns_ptr_only SMALLINT NOT NULL DEFAULT 0,
-WikiName VARCHAR(250),
+wikiname VARCHAR(250),
 dhcp_acl TEXT,
 queue_id INTEGER NOT NULL DEFAULT 0,
 mac VARCHAR(20) NOT NULL DEFAULT '',

+ 7 - 7
docs/databases/postgres/ru/create_db.sql

@@ -114,7 +114,7 @@ password VARCHAR(255),
 protocol SMALLINT NOT NULL DEFAULT 0,
 control_port INTEGER NOT NULL DEFAULT 23,
 port_count INTEGER NOT NULL DEFAULT 0,
-SN VARCHAR(80),
+sn VARCHAR(80),
 description VARCHAR(255),
 snmp_version SMALLINT NOT NULL DEFAULT 0,
 snmp3_auth_proto VARCHAR(10) NOT NULL DEFAULT 'sha512',
@@ -470,7 +470,7 @@ deleted SMALLINT NOT NULL DEFAULT 0,
 description VARCHAR(250),
 dns_name VARCHAR(253),
 dns_ptr_only SMALLINT NOT NULL DEFAULT 0,
-WikiName VARCHAR(250),
+wikiname VARCHAR(250),
 dhcp_acl TEXT,
 queue_id INTEGER NOT NULL DEFAULT 0,
 mac VARCHAR(20) NOT NULL DEFAULT '',
@@ -554,9 +554,9 @@ router_id BIGINT DEFAULT 0,
 auth_id BIGINT NOT NULL DEFAULT 0,
 ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 byte_in BIGINT NOT NULL DEFAULT 0,
-byte_out BIGINT NOT NULL DEFAULT 0
-pkt_in INTEGER,
-pkt_out INTEGER,
+byte_out BIGINT NOT NULL DEFAULT 0,
+pkt_in INTEGER NOT NULL DEFAULT 0,
+pkt_out INTEGER NOT NULL DEFAULT 0,
 step SMALLINT NOT NULL DEFAULT 3600
 );
 COMMENT ON TABLE user_stats IS 'Статистика трафика пользователей (агрегированная)';
@@ -569,8 +569,8 @@ auth_id BIGINT NOT NULL DEFAULT 0,
 ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 byte_in BIGINT NOT NULL DEFAULT 0,
 byte_out BIGINT NOT NULL DEFAULT 0,
-pkt_in INTEGER,
-pkt_out INTEGER,
+pkt_in INTEGER NOT NULL DEFAULT 0,
+pkt_out INTEGER NOT NULL DEFAULT 0,
 step SMALLINT NOT NULL DEFAULT 600
 );
 COMMENT ON TABLE user_stats_full IS 'Подробная статистика трафика пользователей';

+ 2 - 2
html/admin/devices/editdevice.php

@@ -91,7 +91,7 @@ if (getPOST("editdevice") !== null && isset($id)) {
 
     // === ОСТАЛЬНЫЕ ПОЛЯ =========================================================
     $new['description']           = trim(getPOST("f_description", null, ''));
-    $new['SN']                    = trim(getPOST("f_SN", null, ''));
+    $new['sn']                    = trim(getPOST("f_sn", null, ''));
     $new['firmware']              = trim(getPOST("f_firmware", null, ''));
 
     // SNMP
@@ -213,7 +213,7 @@ print_editdevice_submenu($page_url, $id, $device['device_type'], $user_info['log
             print_device_model_select($db_link, 'f_device_model_id', $device['device_model_id']);
             print "</td>\n";
             print "<td class='data' ><input type='text' name='f_firmware' value='" . $device['firmware'] . "'></td>\n";
-            print "<td class='data' ><input type='text' name='f_SN' value='" . $device['SN'] . "'></td>\n";
+            print "<td class='data' ><input type='text' name='f_sn' value='" . $device['sn'] . "'></td>\n";
             print "</tr>\n";
             print "<tr><td colspan=2>" . WEB_location_name . "</td><td colspan=2>" . WEB_cell_description . "</td>";
             print "</tr><tr>";

+ 1 - 1
html/admin/devices/index.php

@@ -95,7 +95,7 @@ foreach ($switches as $row) {
         print "<td class=\"$cl\">".$row['ip']."</td>\n";
         }
     print "<td class=\"$cl\">" . get_vendor_name($db_link, $row['vendor_id']) . " " . $row['model_name'] . "</td>\n";
-    print '<td class="'.$cl.'" style="width: 1%; white-space: nowrap;">' . $row['SN'] ."</td>\n";
+    print '<td class="'.$cl.'" style="width: 1%; white-space: nowrap;">' . $row['sn'] ."</td>\n";
     print "<td class=\"$cl\">" . get_building($db_link, $row['building_id']);
     if (!empty($row['description'])) { print  '<hr style="opacity: 0;">' . $row['description']; }
     print "</td>\n";

+ 3 - 3
html/admin/iplist/nagios.php

@@ -127,13 +127,13 @@ foreach ($users as $user) {
     } else {
         print "<td class=\"$cl\" width=200>".$user['description']."</td>\n";
     }
-    if (!empty($user['WikiName'])) {
+    if (!empty($user['wikiname'])) {
         $wiki_url = rtrim(get_option($db_link, 60),'/');
         if (preg_match('/127.0.0.1/', $wiki_url)) { print "<td class=\"$cl\" ></td>\n"; } else {
             $wiki_web = rtrim(get_option($db_link, 63),'/');
             $wiki_web = ltrim($wiki_web,'/');
-            $wiki_link = $wiki_url.'/'.$wiki_web.'/'.$user['WikiName'];
-            print "<td class=\"$cl\" >"; print_url($user['WikiName'],$wiki_link); print "</td>\n";
+            $wiki_link = $wiki_url.'/'.$wiki_web.'/'.$user['wikiname'];
+            print "<td class=\"$cl\" >"; print_url($user['wikiname'],$wiki_link); print "</td>\n";
             }
         } else {
         print "<td class=\"$cl\" ></td>\n";

+ 4 - 4
html/admin/users/editauth.php

@@ -59,7 +59,7 @@ if (getPOST("editauth") !== null && !$old_auth_info['deleted']) {
             'ip_int'      => $ip_aton,
             'mac'         => $mac,
             'description' => trim(getPOST("f_description", null, '')),
-            'WikiName'    => trim(getPOST("f_wiki", null, ''))
+            'wikiname'    => trim(getPOST("f_wiki", null, ''))
         ];
 
         $f_dnsname = trim(getPOST("f_dns_name", null, ''));
@@ -408,14 +408,14 @@ if (empty($auth_info['end_life']) or $auth_info['end_life'] == '0000-00-00 00:00
                 <td><?php print WEB_cell_nagios_handler; ?></td>
                 <td width=200>
                     <?php
-                    if (!empty($auth_info['WikiName'])) {
+                    if (!empty($auth_info['wikiname'])) {
                         $wiki_url = rtrim(get_option($db_link, 60), '/');
                         if (preg_match('/127.0.0.1/', $wiki_url)) {
                             print WEB_cell_wikiname;
                         } else {
                             $wiki_web = rtrim(get_option($db_link, 63), '/');
                             $wiki_web = ltrim($wiki_web, '/');
-                            $wiki_link = $wiki_url . '/' . $wiki_web . '/' . $auth_info['WikiName'];
+                            $wiki_link = $wiki_url . '/' . $wiki_web . '/' . $auth_info['wikiname'];
                             print_url(WEB_cell_wikiname, $wiki_link);
                         }
                     } else {
@@ -436,7 +436,7 @@ if (empty($auth_info['end_life']) or $auth_info['end_life'] == '0000-00-00 00:00
                     } ?></td>
             <tr>
                 <td><input type="text" name="f_handler" value="<?php echo $auth_info['nagios_handler']; ?>"></td>
-                <td><input type="text" name="f_wiki" value="<?php echo $auth_info['WikiName']; ?>"></td>
+                <td><input type="text" name="f_wiki" value="<?php echo $auth_info['wikiname']; ?>"></td>
                 <td><?php if (empty($device) or (!empty($device) and $device['device_type'] > 2)) {
                         print_qa_select('f_nagios', $auth_info['nagios']);
                     } ?>

+ 14 - 12
scripts/eyelib/database.pm

@@ -170,7 +170,7 @@ sub batch_db_sql_csv {
 
     my $db = init_db();
 
-    if ($config_ref{DBTYPE} eq 'mysql') {
+    if (get_db_type($db) eq 'mysql') {
         # --- MySQL: попытка LOAD DATA, fallback на INSERT ---
         log_debug("Using LOAD DATA LOCAL INFILE for MySQL");
 
@@ -244,13 +244,7 @@ sub batch_db_sql_csv {
             }
         }
 
-    } elsif ($config_ref{DBTYPE} eq 'postgresql') {
-        unless ($db->{Driver}->{Name} eq 'Pg') {
-            my $err = "PostgreSQL expected but connected via " . $db->{Driver}->{Name};
-            log_error($err);
-            $db->disconnect();
-            return 0;
-        }
+    } elsif (get_db_type($db) eq 'pg') {
 
         if (!$db->can('pg_putcopydata') || !$db->can('pg_putcopyend')) {
             log_debug("pg_putcopydata/pg_putcopyend not available — falling back to bulk INSERT");
@@ -346,7 +340,7 @@ sub batch_db_sql_csv {
         }
 
     } else {
-        my $err = "Unsupported DBTYPE: '$config_ref{DBTYPE}'";
+        my $err = "Unsupported DBTYPE: ". get_db_type($db);
         log_error($err);
         $db->disconnect();
         return 0;
@@ -550,7 +544,7 @@ sub _execute_param {
     my $was_modified = 0;
     my $original_sql = $sql;
     if ($mode eq 'id' && $sql =~ /^\s*INSERT\b/i) {
-        if ($config_ref{DBTYPE} && $config_ref{DBTYPE} eq 'Pg') {
+        if (get_db_type($db) eq 'pg') {
             # Добавляем RETURNING id, если его ещё нет
             unless ($sql =~ /\bRETURNING\b/i) {
                 $sql .= ' RETURNING id';
@@ -619,7 +613,7 @@ sub _execute_param {
         # Сюда попадём только если НЕ было модификации (т.е. MySQL или старый Pg-путь)
         if ($original_sql =~ /^\s*INSERT/i) {
             my $id;
-            if ($config_ref{DBTYPE} && $config_ref{DBTYPE} eq 'mysql') {
+            if (get_db_type($db) eq 'mysql') {
                 $id = $sth->{mysql_insertid};
             } else {
                 ($id) = $db->selectrow_array("SELECT lastval()");
@@ -721,6 +715,14 @@ return hash_to_text($result);
 
 #---------------------------------------------------------------------------------------------------------------
 
+sub get_db_type {
+my $db = shift;
+return lc($db->{Driver}->{Name});
+#'mysql', 'pg'
+}
+
+#---------------------------------------------------------------------------------------------------------------
+
 sub insert_record {
 my ($db, $table, $record) = @_;
 return unless $db && $table;
@@ -749,7 +751,7 @@ my $new_str = '';
 foreach my $field (keys %$record) {
     my $val = defined $record->{$field} ? $record->{$field} : undef;
     # Экранируем имя поля в зависимости от СУБД
-    my $quoted_field = $config_ref{DBTYPE} eq 'mysql'
+    my $quoted_field = get_db_type($db) eq 'mysql'
         ? '`' . $field . '`'
         : '"' . $field . '"';
     $fields .= "$quoted_field, ";

+ 6 - 0
scripts/updates/3-0-1/migration.msql

@@ -126,3 +126,9 @@ ALTER TABLE `traffic_detail` MODIFY `src_ip` BIGINT NOT NULL DEFAULT 0, MODIFY `
 
 -- Исправление customers: убрать строковые 'NULL'
 ALTER TABLE `customers` MODIFY `login` VARCHAR(20) DEFAULT NULL, MODIFY `password` VARCHAR(255) DEFAULT NULL;
+
+-- 1. Переименовать `SN` → `sn` в таблице `devices`
+ALTER TABLE `devices` CHANGE COLUMN `SN` `sn` VARCHAR(80) DEFAULT NULL;
+
+-- 2. Переименовать `WikiName` → `wikiname` в таблице `user_auth`
+ALTER TABLE `user_auth` CHANGE COLUMN `WikiName` `wikiname` VARCHAR(250) DEFAULT NULL;

+ 3 - 3
scripts/utils/set_port_descr.pl

@@ -29,7 +29,7 @@ use Fcntl qw(:flock);
 open(SELF,"<",$0) or die "Cannot open $0 - $!";
 flock(SELF, LOCK_EX|LOCK_NB) or exit 1;
 
-my @auth_list = get_records_sql($dbh,"SELECT A.id,A.user_id,A.ip,A.mac,A.dns_name,A.description,A.dhcp_hostname,A.WikiName,K.login,K.ou_id FROM user_auth as A, user_list as K WHERE K.id=A.user_id AND A.deleted=0 ORDER BY A.id");
+my @auth_list = get_records_sql($dbh,"SELECT A.id,A.user_id,A.ip,A.mac,A.dns_name,A.description,A.dhcp_hostname,A.wikiname,K.login,K.ou_id FROM user_auth as A, user_list as K WHERE K.id=A.user_id AND A.deleted=0 ORDER BY A.id");
 
 my %auth_ref;
 foreach my $auth (@auth_list) {
@@ -40,12 +40,12 @@ $auth_ref{$auth->{id}}{mac}=$auth->{mac};
 $auth_ref{$auth->{id}}{dns_name}=$auth->{dns_name};
 $auth_ref{$auth->{id}}{description}=$auth->{description};
 $auth_ref{$auth->{id}}{dhcp_hostname}=$auth->{dhcp_hostname};
-$auth_ref{$auth->{id}}{WikiName}=$auth->{WikiName};
+$auth_ref{$auth->{id}}{wikiname}=$auth->{wikiname};
 $auth_ref{$auth->{id}}{login}=$auth->{login};
 my $a_netdev = get_record_sql($dbh,"SELECT * FROM devices WHERE user_id = ".$auth->{user_id});
 $auth_ref{$auth->{id}}{device}=$a_netdev;
 if ($auth->{dns_name}) { $auth_ref{$auth->{id}}{description} = $auth->{dns_name}; }
-if (!$auth_ref{$auth->{id}}{description} and $auth->{WikiName}) { $auth_ref{$auth->{id}}{description} = $auth->{WikiName}; }
+if (!$auth_ref{$auth->{id}}{description} and $auth->{wikiname}) { $auth_ref{$auth->{id}}{description} = $auth->{wikiname}; }
 if (!$auth_ref{$auth->{id}}{description} and $auth->{description}) { $auth_ref{$auth->{id}}{description} = translit($auth->{description}); }
 if (!$auth_ref{$auth->{id}}{description}) { $auth_ref{$auth->{id}}{description} = $auth->{ip}; }
 $auth_ref{$auth->{id}}{description}=~s/\./-/g;