Я пытаюсь запустить запрос, используя свободный конструктор запросов Laraval. Запрос включает пользовательскую функцию в части SELECT. Он работает с очень простым запросом, но при больших запросах присутствие пользовательского запроса заставляет соединение удаляться.
Вот простой запрос, который работает:
$query = DB::connection('crm') ->table('contacts') ->where('id', '=', '6eb31b38-b813-5d5c-d33d-52ab2498835b') ->addSelect('id', 'first_name', 'last_name') ->addSelect(DB::raw('my_contact_emails(id, 1) as email')) ; $row = $query->first();
Функция базы данных my_contact_emails () будет извлекать одно или несколько писем для контакта. Как единую строку, разделенную запятыми. У меня нет проблем с этим меньшим запросом.
У меня также есть более крупный запрос, который объединяет около 12 таблиц и имеет около 20 столбцов, которые он возвращает. Это тоже отлично работает, пока пользовательская функция не используется в нем. Как только я добавлю пользовательскую функцию, как показано в более мелком запросе выше, база данных MySQL сообщает об этой ошибке в свой журнал, и соединение закрывается:
140916 23:25:55 [Предупреждение] Прерванное соединение 2625770 для пользователя db: 'my_db': хост my_user: 'my.server.co.uk' (получена ошибка чтения пакетов связи)
Это использует Laravel PDO, с настройкой utf8_general_ci по всей доске (все таблицы, все столбцы, драйвер базы данных Laravel).
Если я возьму запрос, который генерирует построитель запросов, и вставьте его в PHPmyAdmin, тогда он отлично работает. То же самое с MySQL Workbench. Но с драйвером PDO Laravel 4.2 эта ошибка видна на сервере базы данных. Сам Laravel не сообщает об ошибках – он просто возвращает нулевые строки.
Редактировать 1: Изменить 2: Редактировать 3: Эти изменения удалены (4 и 5)
Редактировать 4:
В Laravel есть ряд опций, которые он устанавливает, когда он создает объект PDO. Это одно:
PDO::ATTR_EMULATE_PREPARES => false
Именно это приводит к тому, что пользовательская функция базы данных в предложении SELECT отключает соединение с базой данных. Если я устанавливаю его в true или комментирует, то запрос работает. Я буду исследовать только, для чего этот вариант PDO и почему он должен вызывать эту проблему.
Поэтому, если я правильно понимаю это, сброс PDO :: ATTR_EMULATE_PREPARES на false всегда будет идти в драйвер MySQL сначала для подготовки операторов. В моем случае это как-то не удается правильно подготовить инструкцию, а MySQL затем падает, когда пытается выполнить оператор. Мое решение состоит в том, чтобы подражать подготовке (установить ее в true), что (я думаю) означает, что PDO будет строить полный SQL-оператор, а не базу данных MySQL. Я отправлю это как ответ, когда я пойму более полно, что происходит, почему это не удается, почему эмулирование заставляет его работать, и что действительно нужно сделать, чтобы заставить его работать.
Изменить 5: Вот два запроса, которые показывают, что потерянное соединение происходит или не происходит. Я использую простой PDO prepare () / execute () / fetchAll (), поэтому Laracel выходит из цикла. Все внесенные изменения Laravel были установкой PDO::ATTR_EMULATE_PREPARES
после того, как был создан запрос.
В обоих запросах часть выбора:
SELECT my_contact_emails(c.id, 1) as email
Короткий запрос выглядит так:
FROM contacts as c limit 10
Более длинный запрос выглядит так:
from `contacts` as `c` inner join `contacts_cstm` as `cc` on `cc`.`id_c` = `c`.`id` inner join `sw_bookings_contacts_c` as `bc` on `bc`.`sw_booking50e1ontacts_idb` = `c`.`id` and `bc`.`deleted` = ? inner join `sw_bookings` as `b` on `bc`.`sw_booking50a3ookings_ida` = `b`.`id` and `b`.`deleted` = ? inner join `sw_bookings_cstm` as `b_cstm` on `b_cstm`.`id_c` = `b`.`id` inner join `sw_bookingsw_expedition_c` as `be` on `be`.`sw_bookinga016ookings_idb` = `b`.`id` and `be`.`deleted` = ? inner join `sw_expedition` as `e` on `be`.`sw_booking29d8edition_ida` = `e`.`id` and `e`.`deleted` = ? and `e`.`status` = ? inner join `erp_erplookup` as `el_type` on `el_type`.`contact_type` = `cc`.`type_c` and `el_type`.`deleted` = ? and `el_type`.`lookup_type` = ? left join `erp_erplookup` as `erp_l` on `erp_l`.`salutation` = `c`.`salutation` and `erp_l`.`deleted` = ? and `erp_l`.`lookup_type` = ? left join `sw_country_regions` as `crs` on `crs`.`id` = `c`.`primary_address_state` and `crs`.`deleted` = ? left join `sw_country_regions_cstm` as `crs_cstm` on `crs_cstm`.`id_c` = `crs`.`id` left join `sw_country_regions` as `cr` on `c`.`primary_address_state` = `cr`.`code` left join `sw_country_regions_cstm` as `crc` on `crc`.`id_c` = `cr`.`id` left join `accounts_contacts_1_c` as `ac1c` on `ac1c`.`accounts_ccb6contacts_idb` = `c`.`id` left join `accounts` as `student_of` on `student_of`.`id` = `ac1c`.`accounts_cd3b9ccounts_ida` left join `accounts_cstm` as `student_of_c` on `student_of_c`.`id_c` = `student_of`.`id` left join `sw_bookings_accounts_c` as `ba` on `ba`.`sw_booking9ce7ookings_ida` = `b`.`id` and `ba`.`deleted` = ? left join `accounts` as `booked_account` on `booked_account`.`id` = `ba`.`sw_booking6ef1ccounts_idb` and `booked_account`.`deleted` = ? left join `accounts_cstm` as `booked_account_c` on `booked_account_c`.`id_c` = `booked_account`.`id` where `b`.`booking_type` in (?, ?, ?, ?, ?) and `b_cstm`.`booking_status_c` in (?) and `c`.`deleted` = ? and `cc`.`type_c` in (?, ?, ?, ?) and (`b`.`booking_type` != ? or (`b`.`booking_type` = ? and `b_cstm`.`invoice_party_c` = ?)) and LEAST(DATEDIFF(CURDATE(), c.date_modified), DATEDIFF(CURDATE(), b.date_modified)) <= ? group by `c`.`id` limit 10 # Welcome to SugarCRM!
с массивом связывания:
[0,0,0,0,"ACTIVE",0,"contact_type",0,"salutation",0,0,0,"RESEARCH","DISS","PREMED","MASTERS", "SCHOOL","CONFIRMED",0,"Volunteer","Masters","Student","School","SCHOOL","SCHOOL","individual",28]
Если для параметра PDO::ATTR_EMULATE_PREPARES
установлено значение false, выполняется короткий запрос, а длинный запрос отключает соединение с базой данных. Когда для параметра PDO::ATTR_EMULATE_PREPARES
установлено значение true (по умолчанию), оба запроса работают правильно.
В более коротком запросе я попытался добавить переменные связывания, присоединился к еще нескольким таблицам, группа, но она продолжает работать нормально. Где-то между ними есть точка или термин, который заставляет его потерпеть неудачу.