sudo apt install mariadb-server
sudo apt install mariadb-client
sudo mysql_secure_installation
sudo mysql -u root -p
설치 완료.
포트번호도 확인해보자. 기본 설정은 3306번
show global variables like 'PORT';
설치한DB 버전도 확인해보자.
mysql -V;
또는 mysql -Version;
DB에서 확인하려면
select version();
라이브러리 설치
sudo apt-get install libmysqlclient-dev
테스트 코드 작성 (Client 버전 확인)
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("MySQL Client Version: %s\n", mysql_get_client_info());
exit(0);
}
🤦♂️ 저같은 오류가 나오시는분들...
command-line error: langauge modes specified are incompatible
😥 삽질한 방법 1
gcc -o version version.c $(mysql_config --libs)
또는
gcc -o version version.c -lmysqlclient
-> 이렇게 하면 라이브러리만 찾고 mysql.h 헤더파일은 당연히 어디 있는지 모를 것이다.
😥 삽질한 방법 2
find /usr/ -name 'mysql.h'
헤더파일 위치 찾기.
- /usr/include/mysql/mysql.h
vi ~/.bashrc
열고- 아래 내용 추가 하기!
-> LD_LIBRARY_PATH는 응용프로그램이 공유 라이브러리를 사용할때 어느 경로에 있는지 알려주는 환경 변수로
리눅스는 사용자가 만든 공유 라이브러리가 어느 디렉토리에 있는지 모르기 때문에 LD_LIBRARY_PATH에 등록해주어야 합니다.
공유 라이브러리가 아니니까 당연히 안 된다.😥 삽질한 방법 3
include path에 직접 작성
-> 이 방법은 왜 안되는지 잘 모르겠습니다!
😊 해결한 방법 😊
c99 -I/usr/include/mysql/ -o myfile myfile.c -lmysqlclient
#1. -I/usr/include/mysql/
include 하려는 파일이 표준 경로에 없다면 컴파일러가 찾을 수 있도록
해당 파일의 위치를 넘겨줘야 한다.
find /usr/ -name 'mysql.h'
를 했을 때
/usr/include/mysql/mysql.h
이 경로에 있으므로다른 경로에 설치된 라이브러리를 사용하려면 -I 옵션을 추가해야 한다.
- -I 옵션 (대문자 아이) = 헤더 파일이 위치한 directory를 컴파일러에게 알려줌
- (-I 옵션 생략) = gcc의 기본 include 경로 = /usr/include
- /usr/include = C에서 범용적으로 필요한 헤더파일들이 저장되어 있음
#2. -lmysqlclient
링크 명령에서 -l 옵션을 사용하여 MySQL 클라이언트를 링크해야 한다.
- -l 옵션(소문자 엘) = 라이브러리 파일의 이름을 지정해줌.
- 일반적으로 lib접두사와 .so나 .a 같은 확장자는 제외함
- -L 옵션 = 라이브러리 파일이 위치한 directory를 지정함
📌 VScode 빨간 메시지 해결(?)
다음과 같이 설정하면 오류를 끌?수 있다.
ctrl+shift+P / Configuration Provider / none
https://zetcode.com/db/mysqlc/
위 페이지의 내용을 순서대로 실습
MySQL DB 서버에 접속하고 testdb라는 DB를 만드는 코드
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
if (mysql_real_connect(con, "localhost", "root", "root_passwd", NULL, 0, NULL, 0) == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
if (mysql_query(con, "CREATE DATABASE testdb"))
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
mysql_close(con);
exit(0);
}
📝 코드 설명
MYSQL *con = mysql_init(NULL);
if (mysql_real_connect(con, "localhost", "root", "root_passwd",
NULL, 0, NULL, 0) == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
mysql_connect()
함수 대신 mysql_real_connect를 사용해야 한다.
mysql_real_connect( )
의 마지막 인자는 Client Flag 인데, if (mysql_query(con, "CREATE DATABASE testdb"))
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
mysql_close(con);
👀 실행 결과
CREATE USER [name]@localhost IDENTIFIED BY '[password]';
GRANT ALL ON testdb.* to [name]@localhost;
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
if (mysql_real_connect(con, "localhost", "abcde", "abcde",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "DROP TABLE IF EXISTS cars")) {
finish_with_error(con);
}
if (mysql_query(con, "CREATE TABLE cars(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), price INT)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(1,'Audi',52642)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(2,'Mercedes',57127)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(3,'Skoda',9000)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(4,'Volvo',29000)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(5,'Bentley',350000)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(6,'Citroen',21000)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(7,'Hummer',41400)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(8,'Volkswagen',21600)")) {
finish_with_error(con);
}
mysql_close(con);
exit(0);
}
📝 코드 설명
finish_with_error(con)
👀 실행 결과
c99 -I/usr/include/mysql/ -o create_populate create_populate.c -lmysqlclient
./create_populate
sudo mysql -u root -p
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "abcde", "abcde",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "SELECT * FROM cars"))
{
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
int num_fields = mysql_num_fields(result);
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\n");
}
mysql_free_result(result);
mysql_close(con);
exit(0);
}
📝 코드 설명
MYSQL_RES *result = mysql_store_result(con);
앞에서 SELECT * FROM Cars
결과를 가져옵니다.
MYSQL_ROW 는 테이블의 한 줄(Row)의 데이터를 담고 있습니다.
👀 실행 결과
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "abcde", "abcde",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "DROP TABLE IF EXISTS writers"))
{
finish_with_error(con);
}
char *sql = "CREATE TABLE writers(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255))";
if (mysql_query(con, sql))
{
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO writers(name) VALUES('Leo Tolstoy')"))
{
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO writers(name) VALUES('Jack London')"))
{
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO writers(name) VALUES('Honore de Balzac')"))
{
finish_with_error(con);
}
int id = mysql_insert_id(con);
printf("The last inserted row id is: %d\n", id);
mysql_close(con);
exit(0);
}
📝 코드 설명
mysql_insert_id(con)
char *sql = "CREATE TABLE writers(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255))";
👀 실행 결과
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "abcde", "abcde",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "SELECT * FROM cars LIMIT 3"))
{
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
int num_fields = mysql_num_fields(result);
MYSQL_ROW row;
MYSQL_FIELD *field;
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
if (i == 0)
{
while(field = mysql_fetch_field(result))
{
printf("%s ", field->name);
}
printf("\n");
}
printf("%s ", row[i] ? row[i] : "NULL");
}
}
printf("\n");
mysql_free_result(result);
mysql_close(con);
exit(0);
}
📝 코드 설명
👀 실행 결과
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
int status = 0;
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "abcde", "abcde",
"testdb", 0, NULL, CLIENT_MULTI_STATEMENTS) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "SELECT name FROM cars WHERE id=2;\
SELECT name FROM cars WHERE id=3;SELECT name FROM cars WHERE id=6"))
{
finish_with_error(con);
}
do {
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
MYSQL_ROW row = mysql_fetch_row(result);
printf("%s\n", row[0]);
mysql_free_result(result);
status = mysql_next_result(con);
if (status > 0) {
finish_with_error(con);
}
} while(status == 0);
mysql_close(con);
exit(0);
}
📝 코드 설명
CLIENT_MULTI_STATEMENTS
값을 세팅해야 한다.👀 실행 결과
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
FILE *fp = fopen("test.jpg", "rb");
if (fp == NULL)
{
fprintf(stderr, "cannot open image file\n");
exit(1);
}
fseek(fp, 0, SEEK_END);
if (ferror(fp)) {
fprintf(stderr, "fseek() failed\n");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
int flen = ftell(fp);
if (flen == -1) {
perror("error occurred");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
fseek(fp, 0, SEEK_SET);
if (ferror(fp)) {
fprintf(stderr, "fseek() failed\n");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
char data[flen+1];
int size = fread(data, 1, flen, fp);
if (ferror(fp)) {
fprintf(stderr, "fread() failed\n");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "abcde", "abcde",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
char chunk[2*size+1];
mysql_real_escape_string(con, chunk, data, size);
char *st = "INSERT INTO images(id, data) VALUES(1, '%s')";
size_t st_len = strlen(st);
char query[st_len + 2*size+1];
int len = snprintf(query, st_len + 2*size+1, st, chunk);
if (mysql_real_query(con, query, len))
{
finish_with_error(con);
}
mysql_close(con);
exit(0);
}
※ 예제 실행을 하려면 test.jpg 파일이 같은 디렉토리에 있어야 하고,
CREATE TABLE images(id INT PRIMARY KEY, data MEDIUMBLOB);
위와 같이 images 테이블을 생성해야 한다.
📝 코드 설명
이미지는 Binary Data이며 MySQL에서는 BLOB(Binary Large Object) 라는 특수한 데이터 타입을 사용한다.
위 예제에서는 MEDIUMBLOB 타입으로 최대 16MB 크기의 이미지까지 저장할 수 있다.
fseek
와 ftell
함수를 통해 이미지 파일의 크기를 알아낸다.mysqL_real_escape_string(con, chunk, data, size)
:snpritnf
: 설정한 format으로 buffer에 출력하는 함수인데,mysql_real_query()
?mysql_query()
는 NULL로 끝나는 문자열 쿼리를 실행하는데,👀 실행 결과
c99 -I/usr/include/mysql -o insert_image insert_image.c -lmysqlclient
엄청난 양의 바이너리가 DB에 저장된다.
3-7에서 DB에 넣은 이미지(test.jpg)를 test2.jpg로 출력해보자.
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
FILE *fp = fopen("test2.jpg", "wb");
if (fp == NULL)
{
fprintf(stderr, "cannot open image file\n");
exit(1);
}
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "abcde", "abcde",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "SELECT data FROM images WHERE id=1"))
{
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
MYSQL_ROW row = mysql_fetch_row(result);
unsigned long *lengths = mysql_fetch_lengths(result);
if (lengths == NULL) {
finish_with_error(con);
}
fwrite(row[0], lengths[0], 1, fp);
if (ferror(fp))
{
fprintf(stderr, "fwrite() failed\n");
mysql_free_result(result);
mysql_close(con);
exit(1);
}
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
mysql_free_result(result);
mysql_close(con);
exit(0);
}
📝 코드 설명
MYSQL_ROW row = mysql_fetch_row(result)
unsigned long *lengths = mysql_fetch_lengths(result);
👀 실행 결과
귀여운 펭귄 이미지가 복사되었다 😊
https://zetcode.com/db/mysqlc/
https://stackoverflow.com/questions/14604228/mysql-h-file-cant-be-found
https://blogger.pe.kr/885/
https://it.gwangtori.com/42
https://blog.naver.com/PostView.nhn?blogId=xenostream&logNo=120197609525
https://devanix.tistory.com/215
http://www.innodbcluster.com/?depth=23080401
http://www.innodbcluster.com/?depth=230806
https://dev.mysql.com/doc/c-api/8.0/en/mysql-real-connect.html