Что такое «неопределенный ссылочный / неразрешенный внешний символ»
Я попытаюсь объяснить, что такое «неопределенный ссылочный / неразрешенный внешний символ».
note : я использую g ++ и Linux, и все примеры для него
blockquote>Например, у нас есть некоторый код
// src1.cpp void print(); static int local_var_name; // 'static' makes variable not visible for other modules int global_var_name = 123; int main() { print(); return 0; }
и
// src2.cpp extern "C" int printf (const char*, ...); extern int global_var_name; //extern int local_var_name; void print () { // printf("%d%d\n", global_var_name, local_var_name); printf("%d\n", global_var_name); }
Создание объектных файлов
$ g++ -c src1.cpp -o src1.o $ g++ -c src2.cpp -o src2.o
После фазы ассемблера у нас есть объектный файл, который содержит любые экспортируемые символы. Посмотрите на символы
$ readelf --symbols src1.o Num: Value Size Type Bind Vis Ndx Name 5: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 _ZL14local_var_name # [1] 9: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 global_var_name # [2]
Я отклонил некоторые строки из вывода, потому что они не имеют значения
Итак, мы видим следующие символы для экспорта.
[1] - this is our static (local) variable (important - Bind has a type "LOCAL") [2] - this is our global variable
src2.cpp ничего не экспортирует, и мы не видели его символов
Свяжите наши объектные файлы
$ g++ src1.o src2.o -o prog
и запустите его
$ ./prog 123
Linker видит экспортированные символы и связывает их. Теперь мы пытаемся раскомментировать строки в src2.cpp, как здесь
// src2.cpp extern "C" int printf (const char*, ...); extern int global_var_name; extern int local_var_name; void print () { printf("%d%d\n", global_var_name, local_var_name); }
, и перестроить объектный файл
$ g++ -c src2.cpp -o src2.o
OK (нет ошибок), потому что мы только строим объектный файл, связь еще не завершена. Попробуйте установить ссылку
$ g++ src1.o src2.o -o prog src2.o: In function `print()': src2.cpp:(.text+0x6): undefined reference to `local_var_name' collect2: error: ld returned 1 exit status
Это произошло потому, что наше local_var_name статично, то есть оно не отображается для других модулей. Теперь глубже. Получить выход фазы перевода
$ g++ -S src1.cpp -o src1.s // src1.s look src1.s .file "src1.cpp" .local _ZL14local_var_name .comm _ZL14local_var_name,4,4 .globl global_var_name .data .align 4 .type global_var_name, @object .size global_var_name, 4 global_var_name: .long 123 .text .globl main .type main, @function main: ; assembler code, not interesting for us .LFE0: .size main, .-main .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2" .section .note.GNU-stack,"",@progbits
Итак, мы видели, что для local_var_name нет метки, поэтому линкер не нашел его. Но мы хакеры :), и мы можем это исправить. Откройте src1.s в текстовом редакторе и измените
.local _ZL14local_var_name .comm _ZL14local_var_name,4,4
на
.globl local_var_name .data .align 4 .type local_var_name, @object .size local_var_name, 4 local_var_name: .long 456789
i.e. вам должно быть как ниже
.file "src1.cpp" .globl local_var_name .data .align 4 .type local_var_name, @object .size local_var_name, 4 local_var_name: .long 456789 .globl global_var_name .align 4 .type global_var_name, @object .size global_var_name, 4 global_var_name: .long 123 .text .globl main .type main, @function main: ; ...
мы изменили видимость local_var_name и установили его значение в 456789. Попробуйте построить из него объектный файл
$ g++ -c src1.s -o src2.o
ok, см.
$ readelf --symbols src1.o 8: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 local_var_name
В настоящее время local_var_name имеет привязку GLOBAL (LOCAL)
link
$ g++ src1.o src2.o -o prog
и запускает ее
$ ./prog 123456789
ok, мы взломаем его:)
Итак, в результате - «неопределенная ссылка / неразрешенная внешняя ошибка символа» происходит, когда компоновщик не может найти глобальные символы в объектных файлах.
Как и вы, вы должны удалить строку из таблицы рекламодателей, прежде чем сможете удалить строку в таблице заданий, на которую она ссылается. Это:
ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`)
REFERENCES `jobs` (`advertiser_id`);
... фактически противоположно тому, что должно быть. Как бы то ни было, это означает, что перед рекламодателями вам придется записывать запись в таблицу заданий. Поэтому вам нужно использовать:
ALTER TABLE `jobs`
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`)
REFERENCES `advertisers` (`advertiser_id`);
После исправления отношения внешнего ключа будет выполняться ваш оператор удаления.
Если вы хотите удалить таблицу, вы должны выполнить следующий запрос за один шаг
SET FOREIGN_KEY_CHECKS = 0; DROP TABLE table_name;
У меня была эта проблема в миграции laravel, поэтому порядок отбрасываемых таблиц в методе down () имеет значение
Schema::dropIfExists('groups');
Schema::dropIfExists('contact');
, возможно, не работает, но если вы измените порядок, он будет работать.
Schema::dropIfExists('contact');
Schema::dropIfExists('groups');
В соответствии с вашим текущим (возможно, ошибочным) дизайном вы должны удалить строку из таблицы рекламодателей перед , вы можете удалить строку в таблице заданий, на которую она ссылается.
Кроме того, вы можете настроить свой внешний ключ таким образом, чтобы удаление в родительской таблице приводило к удалению строк в дочерних таблицах автоматически. Это называется каскадным удалением. Это выглядит примерно так:
ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1`
FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;
Сказав, что, как уже указывали другие, ваш внешний ключ чувствует, что он должен идти наоборот, поскольку таблица рекламодателей действительно содержит первичный ключ, а таблица заданий содержит внешний ключ. Я бы переписал его следующим образом:
ALTER TABLE `jobs`
ADD FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`);
И каскадное удаление не понадобится.
Как насчет этой альтернативы, которую я использовал: разрешить внешнему ключу NULL , а затем выбрать ON DELETE SET NULL.
Лично я предпочитаю использовать оба параметра " ON UPDATE CASCADE ", а также" ON DELETE SET NULL ", чтобы избежать ненужных осложнений, но при настройке вы можете выбрать другой подход. Кроме того, значения NULL'ing внешнего ключа могут в последствии привести к осложнениям, поскольку вы не знаете, что именно там произошло. Поэтому это изменение должно быть в тесной связи с тем, как работает ваш код приложения.
Надеюсь, это поможет.
Простым способом было бы отключить проверку внешнего ключа; внесите изменения, затем повторно включите проверку внешнего ключа.
SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them
, если вам необходимо как можно скорее поддержать клиента и не иметь доступа к
FOREIGN_KEY_CHECKS
, чтобы целостность данных могла быть отключена:
1) удалить внешний ключ
ALTER TABLE `advertisers`
DROP FOREIGN KEY `advertisers_ibfk_1`;
2) активировать операцию удаления thruogh sql или api
3) добавить внешний ключ обратно в схему
ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);
, однако, это горячее исправление, поэтому оно на свой страх и риск, потому что основной недостаток такого подхода заключается в том, что он необходим для сохранения целостности данных вручную.
Вы можете создать триггер для удаления ссылочных строк перед удалением задания.
DELIMITER $$
CREATE TRIGGER before_jobs_delete
BEFORE DELETE ON jobs
FOR EACH ROW
BEGIN
delete from advertisers where advertiser_id=OLD.advertiser_id;
END$$
DELIMITER ;
Когда вы создаете базу данных или создаете таблицы
Вы должны добавить, что строка в верхнем скрипте создает базу данных или таблицу
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
Теперь вы хотите удалить записи из таблицы? то вы пишете как
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1
Удачи!
Вам нужно удалить его по заказу. В таблицах есть зависимость
Если есть несколько заданий с одним и тем же рекламодателем, то ваш внешний ключ должен быть:
ALTER TABLE `jobs`
ADD CONSTRAINT `advertisers_ibfk_1`
FOREIGN KEY (`advertiser_id`)
REFERENCES `advertisers` (`advertiser_id`);
В противном случае (если это наоборот в вашем случае), если вы хотите, чтобы строки в рекламодателе будет автоматически удален, если строка в задании будет удалена, добавьте параметр «ON DELETE CASCADE» к вашему внешнему ключу
ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1`
FOREIGN KEY (`advertiser_id`)
REFERENCES `jobs` (`advertiser_id`);
ON DELETE CASCASE
Проверьте Ограничения внешнего ключа
Я думаю, что ваш внешний ключ назад. Попробуйте:
ALTER TABLE 'jobs'
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`)