Как я могу обойти MySQL Errcode 13 с помощью SELECT INTO OUTFILE?

114

Я пытаюсь сбросить содержимое таблицы в файл csv с помощью оператора MySQL SELECT INTO OUTFILE. Если я сделаю:

SELECT column1, column2
INTO OUTFILE 'outfile.csv'
FIELDS TERMINATED BY ','
FROM table_name;

Outfile.csv будет создан на сервере в том же каталоге, в котором хранятся файлы базы данных.

Однако, когда я меняю свой запрос на:

SELECT column1, column2
INTO OUTFILE '/data/outfile.csv'
FIELDS TERMINATED BY ','
FROM table_name;

Я получил:

ERROR 1 (HY000): Can't create/write to file '/data/outfile.csv' (Errcode: 13)

Errcode 13 - это ошибка разрешений, но я получаю ее, даже если меняю владельца / data на mysql: mysql и даю ему 777 разрешений. MySQL работает от имени пользователя "mysql".

Как ни странно, я могу создать файл в / tmp, но не в каком-либо другом каталоге, который я пробовал, даже с такими разрешениями, чтобы пользователь mysql мог писать в каталог.

Это MySQL 5.0.75, работающий на Ubuntu.

Райан Олсон
источник
3
Поскольку число 13 является системной ошибкой, вероятно, это не так, но есть параметр mySQL, ограничивающий INTO OUTFILE каталогом: dev.mysql.com/doc/refman/5.0/en/ ... возможно, стоит взглянуть, действительно ли это установлен на /tmp.
Пекка
В моей установке эта переменная пуста, что, согласно этому документу, означает, что мои выходные каталоги не должны быть ограничены.
Райан Олсон

Ответы:

189

Какая именно версия Ubuntu и это Ubuntu Server Edition?

Последние версии Ubuntu Server Edition (например, 10.04) поставляются с AppArmor, а профиль MySQL по умолчанию может находиться в принудительном режиме. Вы можете проверить это, выполнив sudo aa-statusтак:

# sudo aa-status
5 profiles are loaded.
5 profiles are in enforce mode.
   /usr/lib/connman/scripts/dhclient-script
   /sbin/dhclient3
   /usr/sbin/tcpdump
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/sbin/mysqld
0 profiles are in complain mode.
1 processes have profiles defined.
1 processes are in enforce mode :
   /usr/sbin/mysqld (1089)
0 processes are in complain mode.

Если mysqld включен в принудительный режим, то он, вероятно, запрещает запись. Записи также будут записаны, /var/log/messagesкогда AppArmor блокирует запись / доступ. Что вы можете сделать , это изменить /etc/apparmor.d/usr.sbin.mysqldи добавить /data/и /data/*около дна , как так:

...  
/usr/sbin/mysqld  {  
    ...  
    /var/log/mysql/ r,  
    /var/log/mysql/* rw,  
    /var/run/mysqld/mysqld.pid w,  
    /var/run/mysqld/mysqld.sock w,  
    **/data/ r,  
    /data/* rw,**  
}

А затем заставьте AppArmor перезагрузить профили.

# sudo /etc/init.d/apparmor reload

ВНИМАНИЕ: вышеуказанное изменение позволит MySQL читать и записывать в каталог / data. Мы надеемся, что вы уже учли последствия этого для безопасности.

Vin-G
источник
2
Ненавижу указывать на это, но есть причина, по которой App Armor не позволяет этого. MySQL теперь может изменять и читать что угодно в папке / data. Только не взламывайте сейчас.
Райан Уорд
2
@Serdar, Распространяемый с дистрибутивом набор правил MySQL AppArmor не позволяет этого по умолчанию . В этом есть смысл, поскольку это хорошая основа правил для новой установки. Я считаю, что мы должны иметь право изменять наборы правил в соответствии с нашими потребностями после установки. Первоначальный запросчик имел намерение разрешить MySQL писать в определенные каталоги. Но если выше это явно не ясно, то примечание для тех, кто наткнется на это решение: ВНИМАНИЕ: вышеуказанное изменение позволит MySQL читать и записывать в каталог / data. Мы надеемся, что вы уже учли последствия этого для безопасности.
Vin-G
1
ОТЛИЧНЫЙ ОТВЕТ !!! Это решило мою проблему, я тоже пытался писать в любой другой каталог. Теперь я должен исследовать, о чем все это было! :) Узнав об этом, я рекомендую другим людям прочитать об apparmor (и, следовательно, о команде aa-status): en.wikipedia.org/wiki/AppArmor
David L
1
В моем случае это помогло: /your/abs/folder/ r, /your/abs/folder/** rwk, }не забудьте поставить запятую в конце!
ACV,
1
работает писать в / tmp. Вместо этого используйте окна. Linux отстой
Виктор Ионеску
17

Ubuntu использует AppArmor, что мешает вам получить доступ к / data /. Fedora использует selinux, и это предотвратит это на машине RHEL / Fedora / CentOS.

Чтобы изменить AppArmor, чтобы MySQL мог получить доступ к / data /, выполните следующие действия:

sudo gedit /etc/apparmor.d/usr.sbin.mysqld

добавьте эту строку в любом месте списка каталогов:

/data/ rw,

затем выполните:

sudo /etc/init.d/apparmor restart

Другой вариант - полностью отключить AppArmor для mysql, это НЕ РЕКОМЕНДУЕТСЯ :

sudo mv /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/

Не забудьте перезапустить apparmor:

sudo /etc/init.d/apparmor restart

ладья
источник
Чтобы фактически отключить apparmor для mysql, мне нужно было сделать: cyberciti.biz/faq/ubuntu-linux-howto-disable-apparmor-commands
silver_mx
14

Я знаю, что вы сказали, что уже пытались установить разрешения на 777, но поскольку у меня есть доказательства того, что для меня это была проблема с разрешением, я публикую то, что я точно выполняю, в надежде, что это может помочь. Вот мой опыт:

tmp $ pwd
/Users/username/tmp
tmp $ mkdir bkptest
tmp $ mysqldump -u root -T bkptest bkptest
mysqldump: Got error: 1: Can't create/write to file '/Users/username/tmp/bkptest/people.txt' (Errcode: 13) when executing 'SELECT INTO OUTFILE'
tmp $ chmod a+rwx bkptest/
tmp $ mysqldump -u root -T bkptest bkptest
tmp $ ls bkptest/
people.sql  people.txt
tmp $ 
basilikode
источник
me @ server: / data $ pwd / data me @ server: / data $ ls -al total 60 ... drwxrwxrwx 2 mysql mysql 4096 06.05.2010 16:27 dumptest me @ server: / data $ mysqldump -u dbuser -p -T dumptest -B db_name --tables test Введите пароль: mysqldump: Получена ошибка: 1: Невозможно создать / записать в файл '/data/dumptest/test.txt' (код ошибки: 13) при выполнении 'SELECT INTO OUTFILE 'me @ server: / data $ sudo chmod a + rwx dumptest / me @ server: / data $ mysqldump -u dbuser -p -T dumptest -B db_name --tables test Введите пароль: mysqldump: Получена ошибка: 1: ( та же ошибка)
Райан Олсон
Ой, ну, не понимал, что комментарии не будут форматироваться, но перепроверил несколько разных способов. Сначала с целевым каталогом, принадлежащим mysql: mysql, затем с целевым каталогом, принадлежащим пользователю, с которым я запускал команду dump, поскольку оба способа по-прежнему дают мне ту же ошибку разрешений.
Райан Олсон,
Для справки, это сработало для меня, несмотря на то, что я изменил права доступа к устройству
Alex
Я пробовал внести изменения в apparmor, но это не сработало. У меня сработало изменение разрешения chmod 777!
Sudarshan_SMD
7

MySQL здесь тупеет. Он пытается создать файлы в / tmp / data / .... Итак, вы можете сделать следующее:

mkdir /tmp/data
mount --bind /data /tmp/data

Тогда попробуйте свой запрос. Это сработало для меня после нескольких часов отладки проблемы.

vimdude
источник
Мне больше всего нравится этот ответ. Это просто, это работает, и вам не нужно возиться с apparmor. Другой способ сделать это с использованием каналов не подходит для больших объемов экспорта из-за всей выполняемой буферизации.
Крис Селин
6

Эта проблема меня давно беспокоит. Я заметил, что это обсуждение не указывает на решение на RHEL / Fecora. Я использую RHEL, и я не нахожу файлов конфигурации, соответствующих AppArmer в Ubuntu, но я решил свою проблему, сделав КАЖДЫЙ каталог в каталоге PATH читаемым и доступным для mysql. Например, если вы создаете каталог / tmp, следующие две команды позволяют SELECT INTO OUTFILE выводить файл .sql И .sql

chown mysql:mysql /tmp
chmod a+rx /tmp

Если вы создаете каталог в своем домашнем каталоге / home / tom, вы должны сделать это как для / home, так и для / home / tom.

fanchyna
источник
3
Использование / tmp в качестве примера не является хорошей идеей, и вы действительно не хотите менять владельца каталога / tmp (в большинстве случаев).
sastorsl
Смена владельца / tmp - это плохо, но создание временной папки внутри / tmp chown mysql:mysqlрешило мою проблему
Самуэль Прево
6

Ты можешь сделать это :

mysql -u USERNAME --password=PASSWORD --database=DATABASE --execute='SELECT `FIELD`, `FIELD` FROM `TABLE` LIMIT 0, 10000 ' -X > file.xml
Навраттан Ядав
источник
Спасибо! Можно ли управлять выводом в формате CSV?
Хамман Сэмюэл
4

Некоторые вещи, которые стоит попробовать:

  • это secure_file_priv системная переменная? Если это так, все файлы должны быть записаны в этот каталог.
  • убедитесь, что файл не существует - MySQL будет создавать только новые файлы, а не перезаписывать существующие.
МДМА
источник
1
Я бы также выбрал secure_file_priv. Если файл уже существует, сообщение об ошибке другое (не код ошибки 13).
Xavier Maillard
secure_file_priv в настоящее время не установлен, поэтому, насколько я понимаю, это означает, что я не должен ограничиваться в том, где я могу записывать файлы. Я неправильно понимаю это и нужно ли мне явно устанавливать для него что-то вроде '/', если я хочу иметь возможность писать где угодно в файловой системе?
Райан Олсон
Кроме того, перед выполнением запроса я проверяю, что файл не существует.
Райан Олсон
Спасибо за ответ. Основываясь на ваших выводах, я не думаю, что ни одно из этих предложений вызывает вашу проблему.
mdma
3

У меня такая же проблема, и я решил ее, выполнив следующие действия:

  • Операционная система: ubuntu 12.04
  • лампа установлена
  • предположим, что ваш каталог для сохранения выходного файла: / var / www / csv /

Выполните следующую команду на терминале и отредактируйте этот файл с помощью редактора gedit, чтобы добавить свой каталог в выходной файл.

sudo gedit /etc/apparmor.d/usr.sbin.mysqld

  • теперь файл будет открыт в редакторе, пожалуйста, добавьте туда свой каталог

    / var / www / csv / * rw,

  • аналогично я добавил в свой файл, как следующее изображение:

введите описание изображения здесь

Выполните следующую команду, чтобы перезапустить службы:

sudo /etc/init.d/apparmor перезапуск

Например, я выполняю следующий запрос в построителе запросов phpmyadmin для вывода данных в файл csv

SELECT colName1, colName2,colName3
INTO OUTFILE '/var/www/csv/OUTFILE.csv'
FIELDS TERMINATED BY ','
FROM tableName;

Это успешно сделано и записывает все строки с выбранными столбцами в файл OUTPUT.csv ...

Солнечный СМ
источник
2

В моем случае решение заключалось в том, чтобы сделать каждый каталог в пути к каталогу читаемым и доступным с помощью mysql( chmod a+rx). Каталог все еще был указан относительным путем в командной строке.

chmod a+rx /tmp
chmod a+rx /tmp/migration
etc.
Alsciende
источник
2

Я столкнулся с той же проблемой. Моя проблема заключалась в том, что каталог, в который я пытался выполнить сброс, не имел разрешения на запись для процесса mysqld. Первоначальный дамп sql будет записан, но запись файла csv / txt завершится ошибкой. Похоже, дамп sql запускается от имени текущего пользователя, а преобразование в csv / txt выполняется от имени пользователя, который запускает mysqld. Таким образом, каталог требует разрешения на запись для обоих пользователей.

Мэттью Макмиллан
источник
1

Вам необходимо указать абсолютный путь, а не относительный.

Укажите полный путь к каталогу / data, в который вы пытаетесь писать.

Айк Уокер
источник
Мне это кажется абсолютным путем. Это не?
Пекка
2
Попробуйте это от имени пользователя mysql, чтобы убедиться, что вы можете создать файл вне mysql:touch /data/outfile.csv
Айк Уокер,
1
Сначала я не мог этого сделать, потому что оболочка пользователя mysql была установлена ​​на / bin / false, поэтому я не мог войти в систему как mysql. Чтобы убедиться, что это не усугубляет проблему, я установил оболочку mysql в / bin / bash, su'd этому пользователю и коснулся файла в / data. Файл был успешно создан, принадлежит mysql.
Райан Олсон,
3
Вы можете использовать su для учетной записи, даже если она использует одну из «отключенных» оболочек: su --shell=/bin/sh nameofaccount
Marc B,
Спасибо, я не знал об этом.
Райан Олсон,
1

Использует ли Ubuntu SELinux? Убедитесь, что он включен и принудительно. /var/log/audit/audit.log может быть полезным (если Ubuntu придерживает его - это расположение RHEL / Fedora).

Чарльз
источник
0

У меня была такая же проблема с CentOs 6.7. В моем случае все разрешения были установлены, но ошибка все равно произошла. Проблема заключалась в том, что SE Linux находился в режиме принудительного исполнения.

Я переключил его на «разрешающий» с помощью команды sudo setenforce 0

Потом у меня все наладилось.

Стефан Бичер
источник