Bagaimana cara mengatasi MySQL Errcode 13 dengan SELECT INTO OUTFILE?

114

Saya mencoba untuk membuang isi tabel ke file csv menggunakan pernyataan MySQL SELECT INTO OUTFILE. Jika aku melakukan:

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

outfile.csv akan dibuat di server di direktori yang sama dengan tempat file database ini disimpan.

Namun, ketika saya mengubah kueri saya menjadi:

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

Saya mendapat:

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

Errcode 13 adalah kesalahan izin, tetapi saya mendapatkannya bahkan jika saya mengubah kepemilikan / data ke mysql: mysql dan memberinya 777 izin. MySQL berjalan sebagai pengguna "mysql".

Anehnya saya dapat membuat file di / tmp, hanya saja tidak di direktori lain yang pernah saya coba, bahkan dengan izin yang disetel sedemikian rupa sehingga pengguna mysql harus dapat menulis ke direktori tersebut.

Ini adalah MySQL 5.0.75 yang berjalan di Ubuntu.

Ryan Olson
sumber
3
Melihat 13 adalah kesalahan sistem, ini mungkin bukan itu, tetapi ada pengaturan mySQL yang membatasi INTO OUTFILE ke direktori: dev.mysql.com/doc/refman/5.0/en/… mungkin layak untuk dilihat sekilas apakah itu diatur ke /tmp.
Pekka
Variabel itu kosong pada instalasi saya, yang menurut dokumen itu berarti direktori keluaran saya tidak boleh dibatasi.
Ryan Olson

Jawaban:

189

Versi Ubuntu mana yang ini dan apakah Ubuntu Server Edition ini?

Edisi Server Ubuntu terbaru (seperti 10.04) dikirimkan dengan AppArmor dan profil MySQL mungkin dalam mode penerapan secara default. Anda dapat memeriksanya dengan menjalankan sudo aa-statusseperti ini:

# 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.

Jika mysqld disertakan dalam mode penegakan, maka mode inilah yang mungkin menolak penulisan. Entri juga akan ditulis /var/log/messagesketika AppArmor memblokir penulisan / akses. Apa yang dapat Anda lakukan adalah mengedit /etc/apparmor.d/usr.sbin.mysqlddan menambah /data/dan /data/*mendekati bagian bawah seperti:

...  
/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,**  
}

Dan kemudian buat AppArmor memuat ulang profil.

# sudo /etc/init.d/apparmor reload

PERINGATAN: perubahan di atas akan memungkinkan MySQL untuk membaca dan menulis ke direktori / data. Kami harap Anda telah mempertimbangkan implikasi keamanan dari ini.

Vin-G
sumber
2
Saya tidak suka menunjukkan hal ini, tetapi ada alasan App Armor tidak mengizinkan ini. MySQL sekarang memiliki kemampuan untuk mengubah dan membaca apa pun di folder / data. Hanya saja, jangan diretas sekarang.
Ryan Ward
2
@Serdar, Aturan AppArmor MySQL yang didistribusikan dengan distro tidak mengizinkannya secara default . Ini masuk akal karena ini adalah dasar aturan yang baik untuk pemasangan baru. Saya yakin kita harus dan diizinkan untuk mengubah seperangkat aturan agar sesuai dengan kebutuhan kita pasca-instalasi. Itu adalah niat asli penanya untuk mengizinkan MySQL menulis ke direktori tertentu. Tetapi jika tidak langsung eksplisit di atas, catatan untuk membuat orang tersandung pada solusi ini: PERINGATAN: perubahan di atas akan memungkinkan MySQL untuk membaca dan menulis ke direktori / data. Kami harap Anda telah mempertimbangkan implikasi keamanan dari ini.
Vin-G
1
JAWABAN BESAR !!! Ini memecahkan masalah saya, saya juga mencoba menulis di direktori lain. Sekarang, saya harus meneliti tentang apa semua ini! :) Belajar tentang ini, saya merekomendasikan orang lain untuk membaca tentang apparmor (dan karenanya, perintah aa-status): en.wikipedia.org/wiki/AppArmor
David L
1
Dalam kasus saya ini membantu: /your/abs/folder/ r, /your/abs/folder/** rwk, }jangan lupa untuk menyertakan koma di akhir!
ACV
1
itu berfungsi untuk menulis di / tmp. Gunakan windows sebagai gantinya. Linux menyebalkan
Victor Ionescu
17

Ubuntu menggunakan AppArmor dan itulah yang mencegah Anda mengakses / data /. Fedora menggunakan selinux dan itu akan mencegah ini pada mesin RHEL / Fedora / CentOS.

Untuk memodifikasi AppArmor agar memungkinkan MySQL mengakses / data / lakukan hal berikut:

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

tambahkan baris ini di mana saja dalam daftar direktori:

/data/ rw,

lalu lakukan:

sudo /etc/init.d/apparmor restart

Opsi lain adalah menonaktifkan AppArmor untuk mysql sama sekali, ini TIDAK DIANJURKAN :

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

Jangan lupa restart apparmor:

sudo /etc/init.d/apparmor restart

benteng
sumber
Untuk benar-benar menonaktifkan apparmor untuk mysql yang perlu saya lakukan: cyberciti.biz/faq/ubuntu-linux-howto-disable-apparmor-commands
silver_mx
14

Saya tahu Anda mengatakan bahwa Anda sudah mencoba menyetel izin ke 777, tetapi karena saya memiliki bukti bahwa bagi saya itu adalah masalah izin, saya memposting apa yang sebenarnya saya jalankan dengan harapan dapat membantu. Inilah pengalaman saya:

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.dll
sumber
me @ server: / data $ pwd / data me @ server: / data $ ls -al total 60 ... drwxrwxrwx 2 mysql mysql 4096 2010-05-06 16:27 dumptest me @ server: / data $ mysqldump -u dbuser -p -T dumptest -B db_name --tables test Masukkan kata sandi: mysqldump: Mendapat kesalahan: 1: Tidak dapat membuat / menulis ke file '/data/dumptest/test.txt' (Errcode: 13) saat menjalankan '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 Masukkan kata sandi: mysqldump: Ada kesalahan: 1: ( kesalahan yang sama)
Ryan Olson
Oy, yah, tidak menyadari komentar tidak akan diformat, tetapi periksa kembali beberapa cara berbeda. Pertama dengan direktori target yang dimiliki oleh mysql: mysql, kemudian dengan direktori target milik pengguna saya menjalankan perintah dump karena, kedua cara masih memberi saya kesalahan izin yang sama.
Ryan Olson
Sebagai catatan, ini berhasil untuk saya meskipun telah mengubah izin apparmor
Alex
Saya mencoba melakukan modifikasi pada apparmor, tidak berhasil. Mengubah izin 'chmod 777' berhasil untuk saya!
Sudarshan_SMD
7

MySQL semakin bodoh di sini. Ia mencoba membuat file di bawah / tmp / data / .... Jadi yang dapat Anda lakukan adalah sebagai berikut:

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

Kemudian coba kueri Anda. Ini berfungsi untuk saya setelah berjam-jam men-debug masalah.

vimdude
sumber
Saya paling suka jawaban ini. Ini mudah, berfungsi, dan tidak mengharuskan Anda melakukan futures dengan apparmor. Cara lain untuk melakukannya dengan menggunakan pipa tidak bekerja dengan baik untuk ekspor besar karena semua buffering yang dilakukan.
Chris Seline
6

Masalah ini telah mengganggu saya sejak lama. Saya perhatikan bahwa diskusi ini tidak menunjukkan solusi pada RHEL / Fecora. Saya menggunakan RHEL dan saya tidak menemukan file konfigurasi yang sesuai dengan AppArmer di Ubuntu, tetapi saya memecahkan masalah saya dengan membuat SETIAP direktori di direktori PATH dapat dibaca dan diakses oleh mysql. Misalnya, jika Anda membuat direktori / tmp, dua perintah berikut membuat SELECT INTO OUTFILE dapat menampilkan file .sql AND .sql

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

Jika Anda membuat direktori di direktori home / home / tom, Anda harus melakukan ini untuk / home dan / home / tom.

fanchyna
sumber
3
Menggunakan / tmp sebagai contoh bukanlah ide yang baik, dan Anda benar-benar tidak ingin mengubah kepemilikan direktori / tmp (dalam banyak kasus).
sastorsl
Mengubah kepemilikan / tmp itu buruk, tetapi membuat folder temp di dalam / tmp dan chown mysql:mysqlmenyelesaikan masalah saya
Samuel Prevost
6

Kamu bisa melakukan ini :

mysql -u USERNAME --password=PASSWORD --database=DATABASE --execute='SELECT `FIELD`, `FIELD` FROM `TABLE` LIMIT 0, 10000 ' -X > file.xml
Navrattan Yadav
sumber
Terima kasih! Apakah mungkin untuk mengontrol keluaran sebagai CSV?
Hamman Samuel
4

Beberapa hal untuk dicoba:

  • adalah secure_file_privset variabel sistem? Jika ya, semua file harus ditulis ke direktori itu.
  • pastikan file tidak ada - MySQL hanya akan membuat file baru, tidak menimpa file yang sudah ada.
mdma
sumber
1
Saya juga akan menggunakan secure_file_priv. Jika file sudah ada, pesan errornya berbeda (bukan errcode 13).
Xavier Maillard
secure_file_priv saat ini tidak disetel, jadi seperti yang saya pahami, itu berarti saya tidak boleh dibatasi di mana saya dapat menulis file. Apakah saya salah paham dan apakah saya perlu secara eksplisit mengaturnya ke sesuatu seperti '/' jika saya ingin dapat menulis di mana saja di sistem file?
Ryan Olson
Juga, saya memeriksa bahwa file tersebut tidak ada sebelum menjalankan kueri.
Ryan Olson
Terima kasih untuk umpan baliknya. Berdasarkan temuan Anda, menurut saya tidak satu pun dari saran ini yang menyebabkan masalah Anda.
mdma
3

Saya memiliki masalah yang sama dan saya memperbaiki masalah ini dengan mengikuti langkah-langkah berikut:

  • Sistem operasi: ubuntu 12.04
  • lampu dipasang
  • misalkan direktori Anda untuk menyimpan file keluaran adalah: / var / www / csv /

Jalankan perintah berikut pada terminal dan edit file ini menggunakan editor gedit untuk menambahkan direktori Anda ke file keluaran.

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

  • sekarang file akan dibuka di editor, tambahkan direktori Anda di sana

    / var / www / csv / * rw,

  • juga saya telah menambahkan di file saya, seperti yang diberikan gambar berikut:

masukkan deskripsi gambar di sini

Jalankan perintah berikutnya untuk memulai ulang layanan:

sudo /etc/init.d/apparmor restart

Misalnya saya menjalankan kueri berikut ke pembuat kueri phpmyadmin untuk mengeluarkan data dalam file csv

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

Itu berhasil dilakukan dan menulis semua baris dengan kolom yang dipilih ke dalam file OUTPUT.csv ...

SM cerah
sumber
2

Dalam kasus saya, solusinya adalah membuat setiap direktori di jalur direktori dapat dibaca dan diakses oleh mysql( chmod a+rx). Direktori masih ditentukan oleh jalur relatifnya di baris perintah.

chmod a+rx /tmp
chmod a+rx /tmp/migration
etc.
Alsciende
sumber
2

Saya baru saja mengalami masalah yang sama. Masalah saya adalah direktori yang saya coba tempatkan tidak memiliki izin menulis untuk proses mysqld. SQL awal dump akan menulis tetapi penulisan file csv / txt akan gagal. Sepertinya sql dump berjalan sebagai pengguna saat ini dan konversi ke csv / txt dijalankan sebagai pengguna yang menjalankan mysqld. Jadi direktori membutuhkan izin tulis untuk kedua pengguna.

Matthew McMillan
sumber
1

Anda perlu memberikan jalur absolut, bukan jalur relatif.

Berikan jalur lengkap ke direktori / data yang Anda coba tulis.

Ike Walker
sumber
Itu tampak seperti jalan mutlak bagi saya. Bukan?
Pekka
2
Coba ini sebagai pengguna mysql untuk memverifikasi bahwa Anda dapat membuat file di luar mysql:touch /data/outfile.csv
Ike Walker
1
Pertama saya tidak bisa melakukannya karena shell pengguna mysql disetel ke / bin / false, jadi saya tidak bisa masuk sebagai mysql. Hanya untuk memastikan itu tidak berkontribusi pada masalah, saya mengatur shell mysql ke / bin / bash, su'd ke pengguna itu dan menyentuh file di / data. File berhasil dibuat, milik mysql.
Ryan Olson
3
Anda dapat menggugat ke akun meskipun itu menggunakan salah satu dari shell "nonaktifkan": su --shell=/bin/sh nameofaccount
Marc B
Terima kasih, saya tidak menyadarinya.
Ryan Olson
1

Apakah Ubuntu menggunakan SELinux? Periksa untuk melihat apakah itu diaktifkan dan diterapkan. /var/log/audit/audit.log mungkin membantu (jika di situlah Ubuntu menempelkannya - itulah lokasi RHEL / Fedora).

Charles
sumber
0

Saya mengalami masalah yang sama pada CentOs 6.7 Dalam kasus saya, semua izin telah ditetapkan dan kesalahan masih terjadi. Masalahnya adalah SE Linux berada dalam mode "memaksa".

Saya mengalihkannya ke "permisif" menggunakan perintah sudo setenforce 0

Kemudian semuanya berhasil bagi saya.

Stefan Bicher
sumber