RSS구독하기:SUBSCRIBE TO RSS FEED
즐겨찾기추가:ADD FAVORITE
글쓰기:POST
관리자:ADMINISTRATOR
'Web_developing/Mysql'에 해당되는 글 38
출처 블로그 > loves0508님의 블로그
원본 http://blog.naver.com/loves0508/2942328
mysql 이 웹에서 가장 많이 사용되는 RDBMS 라는 데는 의심의 여지가 없는 것 같다. 주로 Apache 와 PHP 와 연동해서 사용되어 지는데 (이 3가지 조합을 APM 이라고 한다), 간단한 카운터, 방명록에서 부터, 좀더 복잡한 쇼핑몰, 스케쥴관리, 게시판, 웹메일 등 거의 쓰이지 않는 곳이 없을 정도이다.
Mysql 이 PHP 와 함께 웹에서 사용하는게 가장 일반적인 용도이긴 하지만, 많은 경우 시스템레벨에서 직접 다루어야 하는경우도 생긴다. 이러한 경우를 위해서 mysql 은 Perl, Python, C, C++ 등 다양한 API를 제공하는데, 우선 C를 이용한 접근에 대해서 알아보도록 하겠다. (나중에 시간이 허락하면 C++ 을 이용한 mysql 접근에 대해서도 알아보도록 하겠습니다) 설명에 들어감에 앞서 이문는 여러분이 SQL과 RDBMS에 대한 개념과, mysql 의 설치 및 운영에 관련된 기본 사항은 알고 있다는 가정하에 쓰여졌으며, 설명을 위해 쓰인 코드들은 기능과 효율성에 염두를 둔 코드가 아닌 순수 스터디용 (돌아만가는)코드 임을 공지합니다. mysql과 SQL 에 대한 상세한 내용은 관련 서적이나 database.sarang.net을 참고하세요.

코드를 테스트 하기 전에 우선 여러분의 시스템에 mysql client 가 설치되어 있는지 확인을 해보바란다. 필자의 경우 mysql-3.23.46 이 설치되어 있으며, 인클루드 파일은 /usr/local/include/mysql 에 라이브러리 파일은 /usr/local/lib/mysql 설치되어 있다. 요즘 왠만한 Linux 배포판은 기본으로 mysql 이 설치되어 있으니, 위의 인클루드와, 라이브러리 경로가 어디에 있는지 확인만 하면 될것이다.
그럼 테스트를 위한 테이블을 만들고 테이블에 간단한 내용을 입력해보자, 테이블이 위치할 DB 는 test 이고 테이블의 이름은 address 이다.
CREATE TABLE address (  name varchar(25) default NULL,  address text,  tel varchar(25) default NULL);
이 테이블은 간단한 주소록인데, "이름", "주소", "전화번호" 를 저장하기 위해서 사용된다.
이제 테스트를 위해서 2개 정도의 data 를 입력하도록 하자.
INSERT INTO address VALUES ('홍길동','경기도 연천 연천아파트','02-500-5000');INSERT INTO address VALUES ('아무개','광주광역시 서구 현대 아파트','015-000-1111');
우리가 만들 프로그램을 테스트 하기 위한 환경이 갖추어 졌다면, 이제 본격적으로 코드를 작성해 보도록 하겠다.

예제 : mysql_test.c
#include <mysql.h>#include <string.h>#include <stdio.h>#define DB_HOST "127.0.0.1"#define DB_USER "root"#define DB_PASS "gkwlak"#define DB_NAME "test"#define CHOP(x) x[strlen(x) - 1] = ' '    int main(void){    MYSQL       *connection=NULL, conn;    MYSQL_RES   *sql_result;    MYSQL_ROW   sql_row;    int       query_stat;     char name[12];    char address[80];    char tel[12];    char query[255];        mysql_init(&conn);    connection = mysql_real_connect(&conn, DB_HOST,                                    DB_USER, DB_PASS,                                    DB_NAME, 3306,                                    (char *)NULL, 0);    if (connection == NULL)    {        fprintf(stderr, "Mysql connection error : %s", mysql_error(&conn));        return 1;    }    query_stat = mysql_query(connection, "select * from address");    if (query_stat != 0)    {        fprintf(stderr, "Mysql query error : %s", mysql_error(&conn));        return 1;    }        sql_result = mysql_store_result(connection);        printf("%+11s   %-30s   %-10s", "이름", "주소", "전화번호");    while ( (sql_row = mysql_fetch_row(sql_result)) != NULL )    {        printf("%+11s   %-30s   %-10s", sql_row[0], sql_row[1], sql_row[2]);    }    mysql_free_result(sql_result);    printf("이름 :");    fgets(name, 12, stdin);    CHOP(name);    printf("주소 :");    fgets(address, 80, stdin);    CHOP(address);    printf("전화 :");    fgets(tel, 12, stdin);    CHOP(tel);    sprintf(query, "insert into address values "                   "('%s', '%s', '%s')",                   name, address, tel);    query_stat = mysql_query(connection, query);    if (query_stat != 0)    {        fprintf(stderr, "Mysql query error : %s", mysql_error(&conn));        return 1;    }    mysql_close(connection);}
mysql 은 mysql 연결, query 결과 받아오기, 결과물의 Row 값을 저장등을 위한 몇개의 구조체가 존재한다.
MYSQL데이타 베이스에 연결했을때, 이 연결을 다루기 위해 사용되는 구조체 이다
MYSQL_RES(SELECT, SHOW, DESCRIBE, EXPLAIN)등의 쿼리를 내렸을때 그 결과를 다루기 위해 사용되는 구조체이다.
MYSQL_ROW이것은 데이타의 하나의 row 값을 가리킨다. 만약 row 값이 없다면 null 을 가르키게 된다.
MYSQL_FIELD이 구조체는 각 필드의 정보를 가지고 있다. 여기에는 필드의 이름, 타입, 크기 등의 정보를 가지게 된다. mysql 에서 DESC 쿼리를 내렸을때의 정보를 가지고 있다고 보면된다.
MYSQL_FIELD_OFFSETmysql 필드 리스트의 위치를 가진다.
이 프로그램이 하는 일은 최초 mysql DB에 연결을 한다음에 query 를 통하여 address 의 내용을 가져와서 화면에 출력시켜주고. 다음에 사용자 입력을 받아서 DB에 저장하는데까지다. 앞에서 말했듯이, 유저 인터페이스라든가 하는 기능적인 측면은 전혀 신경쓰지 않았다. 이러한 측면에 대해서는 나중에 curse 계열을 다루면서 연구하게 될것이다. 그럼 이제부터 소스를 분석해 보기로 하겠다.

mysql_init() 는 mysql DB에 연결하기 전에 가장 먼저 실행되며, mysql 연결 지시자를 초기화 하는 일을 한다. mysql_init()를 이용해서 mysql 연결을 초기화 하고 나서 mysql_real_connect 를 이용해서 mysql 서버에 실제로 접근하게 된다. 아규먼트로는 우리가 터미널에서 mysql 을이용해서 접근하는데 필요한, 호스트이름(DB_HOST), 유저계정(DB_USER), 계정에 대한 패스워드(DB_PASS), 접근 하고자 하는 DB이름(DB_NAME), 포트번호(DB_PORT) 등이 들어간다. 연결에 성공하면 connection 핸들 값을 넘겨주고 실패하게 되면 NULL 값을 넘겨 주게 된다. 어떤 이유로 실패했는지 자세한 내용을 알아보고 싶다면 mysql_error() 을 사용하라.
mysql 서버로의 연결까지 성공적으로 마쳤다면, 이제 query 를 이용해서 본격적인 작업에 돌입한다. mysql_query 를 통해서 필요한 query를 실행 시키면된다.
우리가 보통 사용하는 쿼리는 "SELECT, SHOW, DESC, EXPLAIN" 과 같이 쿼리에 그 결과 값(row)을 요청하는 것과, "INSERT, UPDATE, DELETE" 와 같이 그 결과 값이 필요 없는 명령어로 나누어 볼수 있다. row 값을 요청하지 않는 쿼리라면 필요가 없겠지만 row 값을 요청하는 쿼리라면 쿼리의 결과값을 저장해야 할것이다. 이럴때 mysql_store_result()를 이용해서 쿼리의 결과값을 되돌려 받을수 있다. mysql_store_result()를 통해서 쿼리의 결과값을 되돌려 받았다면, mysql_fetch_row()를 이용해서 row 단위로 결과 값을 가져올수 있다. 이 함수는 쿼리의 결과값에서 다음의 row 값을 가져오며, 더이상 가져올 row 값이 없다면 NULL 을 돌려준다.
가져온 row 에서의 각필드 값은 row[0] 에서 row[mysql_num_fields(result)-1] 에 저장되어 있으 므로, 해당 row 의 field 값을 쉽게 가져올수 있다.
mysql_store_result() 을 통해서 가져온 쿼리결과값을 더이상 사용할 필요가 없다면, 메모리를 되돌려줘야 하는데, mysql_free_result 를 통해서 되돌려주면 된다. mysql_store_result()를 사용했다면 반드시 mysql_free_result()를 사용해서 메모리를 해제 시켜줘야 한다. 그렇지 않으면 메모리 누수가 발생하게 된다.

mysql_free_result()까지 시켜주고 나서, fgets() 함수를 통하여서 "이름", "주소", "전화번호" 를 입력받아서, 입력받은 정보로 쿼리를 만들고 이를 mysql_query()를 이용해서 DB 에 적재하는 것을 마지막으로 예제의 설명이 끝났다.
누가 보더라도 이해하기 쉬운 코드일것이다. 이제 이 코드를 컴파일 해서 실행시켜 보는 일만 남았다.
gcc -o mysql_test mysql_test.c -I/usr/local/include/mysql                    -L/usr/local/lib/mysql -lmysqlclient
-I 과 -L 옵션을 이용해서 컴파일 시키는데 필요한 인클루드 파일과 라이브러리 파일이 있는 디렉토리를 명시해주면 된다. 위의 디렉토리는 필자가 가진 시스템의 경우이고, 위의 디렉토리는 시스템에 따라서 다를수 있으니 자신의 시스템 설정에 맞도록 옵션을 주고 컴파일 하기 바란다.

이상 간단하게 mysql API 를 살펴보았다. 위의 예제는 많은 mysql API 중의 극히 일부분만을 써서 꼭필요한 기능만 구현한것이다. 더 자세한 정보는 www.mysql.org 사이트를 참고하기 바란다
2006/09/08 11:00 2006/09/08 11:00
이 글에는 트랙백을 보낼 수 없습니다
출처 블로그 > 불행한 바보
원본 http://blog.naver.com/deepinheart/20006875024
byeok 2004-04-09 21:36:13.0
출처 :  http://www.okjsp.pe.kr/
ssweon@rtv.or.kr
mysql 4.1.1 alpha 에서 한글 제대로 설정하기

mysql이 4.1로 업그레이드 되면서 서브쿼리가 지원되게 되어

아마도 많은 사람들이 개발시점에서 한 번쯤은 mysql4.1을 사용할지

고민했으리라 생각합니다.

그러나 아직 제대로된 버전이 아닌관계로 버젓한 메뉴얼이 없어

변화된 localization셋팅때문에 많은 분들이 고생했을 것이라 예상합니다.


mysql4.1에서는 4.0에서처럼 default character set하나만 바꿔주면 끝나질

않습니다. 서버/데이터베이스/테이블/connection/ 심지어 필드

하나하나, 스트링 하나하나까지도 character set과 collation을 설정할 수

있게 되었습니다. 그래서 4.0에서 서비스하던 사이트를 4.1로

데이터를 옮기는 과정에서 한글이 깨지는 현상이 발생합니다.


쉽게 말씀드리면 4단계에 걸쳐서 각각 character set과 collation을

변경해주시면 됩니다. 우선 데이터베이스를 다음과 같이 새로 생성합니다.


>> create database DB_NAME character set euckr collation euckr_korean_ci


그리고 4.0의 데이터를 스크립트로 복사한 다음 각각의 테이블 끝에

붙어있는 character set을 euc-kr 이나 latin1에서 euckr로 변경해줍니다.

(4.1에서 한글의 character set이름이 euc-kr에서 euckr로 변경되었습니다.)


그런 다음 mysql 을 --default-character-set=euckr --default-collation=euckr_korean_ci 의 옵션을 주어 실행시키면서 자료를 덤프받습니다.


>> mysql -uroot -p --default-character-set=euckr --default-collation=euckr_korean_ci < DB_SCRIPT.SQL 

(DB_SCRIPT.SQL파일은 4.0에서 받은 데이터 스크립트파일이겠죠.)


그렇게 하면 일단 데이터베이스 어필리케이션(예를 들면 SQLyog같은 프로그램)에서는 정상적으로 데이터를 볼 수 있을 것입니다.

하지만 JDBC를 사용해서 접속하는 경우 connection characterset을  따로

설정해주지 않으면 한글이 깨질 것입니다.

저같은 경우 어플리케이션에서 connection을 얻어오는 즉시

해당 connection을 이용하여 "SET CHARACTER SET euckr"이란

SQL명령을 executeUpdate 시켰서 해결했습니다만 아마도 더 깔끔한

방법이 있을 줄 압니다.


그렇게 하면 mysql4.1.1알파에서도 한글을 문제없이 사용할 수 있습니다.

참고로 그냥 latin1으로 설정한 상태에서도 한글이 사용이 가능하긴 합니다만 order by나 일부 한글로의 검색시에 제대로 검색이 안되는 경우가 발생합니다. 그런 경우 해당 필드만 character set을 설정해서 사용할 수도 있습니다. 예를 들면 latin1으로 저장된 한글을 euckr의 코드셋 순서로 정렬하고 싶을 때 다음과 같이 하면 됩니다.


>> SELECT * FROM table_name ORDER BY k COLLATE euckr_korean_ci


그러면 한글 순서로 정렬이 됩니다.

이 말은 만약 이제까지 latin1으로 잘 써오신 분이라면 정렬을 위해서만 추가적으로 코드를 추가해줄 경우 문제없이 잘 정렬이 됨을 의미하는 것이니 데이터베이스를 통째로 수정할 필요가 없겠지요.


저도 초보라 고생끝에 알아낸 팁입니다. 유용하게 참고하셨으면 좋겠습니다.

2006/09/08 10:53 2006/09/08 10:53
이 글에는 트랙백을 보낼 수 없습니다
출처 블로그 > kukustyle
원본 http://blog.naver.com/inch772/100016274834

Mysql Replication을 구성하는 여러 구조의 예와 각각의 장단점을 정리한 문서

출처 : High Performance Mysql Ch7

(http://dev.mysql.com/books/hpmysql-excerpts/ch07.html)


Sample Configurations

Building on the four rules, let's begin by constructing simple replication configurations and discussing the types of problems they solve. We'll also look at the types of configurations that don't work because they violate the second rule. We'll use the simple configuration as a building block for arbitrarily complex architectures.

Each configuration is illustrated in a figure that includes the server ID of each server as well as its role: master, slave, or master/slave.

Master with slaves

The most basic replication model, a single master with one or more slaves, is illustrated in Figure 7-1. The master is given server ID 1 and each slave has a different ID.


Figure 7-1. Simple master/slave replication

This configuration is useful in situations in which you have few write queries and many reads. Using several slaves, you can effectively spread the workload among many servers. In fact, each of the slaves can be running other services, such as Apache. By following this model, you can scale horizontally with many servers. The only limit you are likely to hit is bandwidth from the master to the slaves. If you have 20 slaves, which each need to pull an average of 500 KB per second, that's a total of 10,000 KB/sec (or nearly 10 Mbits/sec) of bandwidth.

A 100-Mbit network should have little trouble with that volume, but if either the rate of updates to the master increases or you significantly increase the number of slaves, you run the risk of saturating even a 100-Mbit network. In this case, you need to consider gigabit network hardware or an alternative replication architecture, such as the pyramid described later.

Slave with two masters

It would be nice to use a single slave to handle two unrelated masters, as seen in Figure 7-2. That allows you to minimize hardware costs and still have a backup server for each master. However, it's a violation of the second rule: a slave can't have two masters.


Figure 7-2. A slave can't have two masters

To get around that limitation, you can run two copies of MySQL on the slave machine. Each MySQL instance is responsible for replicating a different master. In fact, there's no reason you couldn't do this for 5 or 10 distinct MySQL masters. As long as the slave has sufficient disk space, I/O, and CPU power to keep up with all the masters, you shouldn't have any problems.

Dual master

Another possibility is to have a pair of masters, as pictured in Figure 7-3. This is particularly useful when two geographically separate parts of an organization need write access to the same shared database. Using a dual-master design means that neither site has to endure the latency associated with a WAN connection.


Figure 7-3. Dual master replication

Furthermore, WAN connections are more likely to have brief interruptions or outages. When they occur, neither site will be without access to their data, and when the connection returns to normal, both masters will catch up from each other.

Of course, there are drawbacks to this setup. Section 7.7.3, later in this chapter, discusses some of the problems associated with a multi-master setup. However, if responsibility for your data is relatively well partitioned (site A writes only to customer records, and site B writes only to contract records) you may not have much to worry about.

A logical extension to the dual-master configuration is to add one or more slaves to each master, as pictured in Figure 7-4. This has the same benefits and drawbacks of a dual-master arrangement, but it also inherits the master/slave benefits at each site. With a slave available, there is no single point of failure. The slaves can be used to offload read-intensive queries that don't require the absolutely latest data.


Figure 7-4. Dual master replication with slaves

Replication ring (multi-master)

The dual-master configuration is really just a special case of the master ring configuration, shown in Figure 7-5. In a master ring, there are three or more masters that form a ring. Each server is a slave of one of its neighbors and a master to the other.


Figure 7-5. A replication ring or multi-master replication topology

The benefits of a replication ring are, like a dual-master setup, geographical. Each site has a master so it can update the database without incurring high network latencies. However, this convenience comes at a high price. Master rings are fragile; if a single master is unavailable for any reason, the ring is broken. Queries will flow around the ring only until they reach the break. Full service can't be restored until all nodes are online.

To mitigate the risk of a single node crashing and interrupting service to the ring, you can add one or more slaves at each site, as shown in Figure 7-6. But this does little to guard against a loss of connectivity.


Figure 7-6. A replication ring with slaves at each site

Pyramid

In large, geographically diverse organizations, there may be a single master that must be replicated to many smaller offices. Rather than configure each slave to contact the master directly, it may be more manageable to use a pyramid design as illustrated in Figure 7-7.


Figure 7-7. Using a pyramid of MySQL servers to distribute data

The main office in Chicago can host the master (1). A slave in London (2) might replicate from Chicago and also serve as a local master to slaves in Paris, France (4), and Frankfurt, Germany (5).


2006/09/08 10:53 2006/09/08 10:53
이 글에는 트랙백을 보낼 수 없습니다

예를 들면 아래와 같은 Table이 있다고 했을때 Korea를 America로, America를 Korea으로 바꾸려고 한다면.....

[Table Name] National
==========================
Field1      Field2
==========================
1           Korea
2           America
3           England
4           Japan
...         ...

예전에 내가 사용한 방법

update national set field2 = 'America' where field1 = 1;
update national set field2 = 'Korea' where field1 = 2;

Update 구문을 두번 사용했다. -,.-; 그나마 변경할 레코드가 2개일땐 그렇다 쳐도 변경할 레코드가 죠낸 많아진다면, update 구문을 죠낸 남발해야 하는 경우가 생기는 것이다.

게다가 위에 구문을 성공하고 난 후에, 아래의 쿼리가 실패하게 되면 죠낸 안습인 상황이 되게 되는 것이다. 레코드에 America만 두개가 되는 상황... -,.-;;;

이 방법을 어찌 해결할 방법이 없을까 "mysql.org"를 뒤지다가 알게된 "CASE"문.... 어둠속에서 한줄기 빛을 보게 된 느낌이다.

CASE문의 기본 문법은 다음과 같다.

CASE value WHEN [compare_value] THEN result [WHEN [compare_value] THEN result ...] [ELSE result] END

CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END

자.. 그럼 저 CASE문을 활용해서 UPDATE 구문을 하나로 바꿔보자....

UPDATE national set field2 = CASE
   WHEN field1 = 1 THEN "America"
   WHEN field1 = 2 THEN "Korea"
ELSE
  field2
END;

2개의 update 구문이 하나로 줄어들었다. 게다가 값을 바꾸는 SWAP같은 경우에도 문제없이 처리할 수 있게 되었다. 단 여기서 한가지 주의할게 있는데, ELSE 다음에 field2는 반드시 필요한 구문이다. 그렇게 해주지 않으면, WHEN 조건절에 해당하지 않게되는 레코드의 field2의 값은 null값이 입력되게 될테니 말이다.

여기에 추가로 해주는 작업이 WHERE 구문.... WHERE 구문을 통해 범위를 좁혀주면 완벽한 DATA SWAP이 이뤄지게 된다.

자.. 최종적으로 사용된 형태를 살펴볼까나?

UPDATE national set field2 = CASE
   WHEN field1 = 1 THEN "America"
   WHEN field1 = 2 THEN "Korea"
ELSE
  field2
END
WHERE field1 in (1, 2);
2006/09/08 10:52 2006/09/08 10:52
이 글에는 트랙백을 보낼 수 없습니다
출처 블로그 > ~(^0^)~ 유유자적 BABU
원본 http://blog.naver.com/solokimm/20010328180

create database japan4;


use japan4


create table abc (
aaa varchar(10),
bbb int(4)
);


INSERT INTO abc VALUES ('aaa', 100);
INSERT INTO abc VALUES ('bbb', 200);


delimiter //


create procedure kimsh (IN num int)
BEGIN
IF num > 0 THEN
UPDATE abc SET bbb = bbb - 50;
ELSE
UPDATE abc SET bbb = bbb + 100;
END IF;
END
//


delimiter ;


call kimsh(1);


SELECT * FROM abc;


call kimsh(-1);


SELECT * FROM abc;


##################################


create table person (
name varchar(20),
age int(4)
);


delimiter //


create procedure kim (IN a varchar(20), IN b int, OUT c varchar(30))
BEGIN
INSERT INTO person values (a, b);
SELECT CONCAT('Hello', a);
END
//


delimiter ;


call kim ('kimsh', 20, @kk);

2006/09/08 10:52 2006/09/08 10:52
이 글에는 트랙백을 보낼 수 없습니다
출처 블로그 > s1726c9966m님의 블로그
원본 http://blog.naver.com/s1726c9966m/100016925896
------------------Mysqli 확장 사용하기 1장 : 개괄과 미리준비된 문장

번역자
김영진(cogolda@hanmail.net)

--------------------------알아 두기
이 문서는 http://www.zend.com/php5/articles/php5-mysqli.php 를 제가 번역 수정한 내용입니다. 혹시 질문이나 의견 있으신 분은 코멘트나 이메일을 이용해 주시면 감사하겠습니다.  

대상독자
소개
* 주요 목적
* 주요 특징
* 왜 바꾸는가?
* 경고와 놀라움
소스 코드 보기
* 기본 사용
* 객체지향 인터페이스 사용하기
미리준비된(prepared) 문장
* 바운드(bound) 파라미터
* 바운드 결과(results)
* 바운드 파라미터와 바운드 결과를 같이 사용하기
요약

-------------------------대상 독자

이 기사는 php와 mysql의 사용 경험이 있는 독자를 위해 작성하였다. 그것은 데이터베이스와 프로그래밍의 기본적인 개념을 알고있고, php 스크립트 사용법과, mysql 서버 쿼리문을 보내는 법을 알고 있다고 가정했다.

Php와 mysql 설치법은 이 기사의 범위를 넘어선다

Php 5 설치에 관한 정보는, http://www.php.net/installation
이용 가능한 mysqli 확장에 관한 정보는,  http://www.php.net/mysqli
MySQL 4.1.2 이나 그 이상 버전의 설치에 관한 정보는,  http://www.mysql.com/doc/en/Installing.html

------------------------용어 설명
(원문에는 용어 설명이 맨 마지막에 있는데, 제가 위로 옮겼습니다.)

* Mysql/확장(ext/mysql) :: php의 구형 MySQL 확장(extension). MySQL version 4.1의 모든 기능을 지원하지 않는다.
* ext/mysqli :: php5의 새로운 MySQL 확장. MySQL 3.22 에서 5.0까지 모든 기능을 지원한다.
* MySQL 클라이언트 라이브러리 :: 프로그램이 RDBMS로 통신하기위하게 만드는 MySQL RDBMS의 컴퍼넌트
* MySQL 서버 :: 데이터베이스 안에서 디스크 수준의 표현을 관리하고, 처리작업과 요구를 하는 MySQL RDBMS의 컴포넌트.
(쉽게 말하자면 이 문서는 php5의 새로운 확장인 mysqli에 관한 내용입니다.)

----------------------------소개

90년대 중반 이후, mysql확장은 php와 mysql 사이에 주요 연결로서 서비스되었다. 비록 수년에 걸쳐서, 증가하는 불편함과 약간의 고생이 있었지만, 일반적으로 mysql확장은 좋은 성능을 가지고 있었고, php와 mysql 둘다 버전업을 하면서 보조를 맞추었다.

그렇지만, php5와 mysql 4.1의 소개 이후, 이런 변화는 다소 문제가 시작되고 있다는 것 보여준다. (아마도 mysql의 라이센스 문제때문이라고 보입니다.)

mysql확장에 있는 고생스러움은, 대부분 뚜렷하게도 mysql_pconnet()과 자동적이고 디폴트 커넥션이다. 추가적으로, mysql확장이 지원하는 특징과 mysql 클라이언트 라이브러리가 지원하는 특징 사이의 비호환성은 존재했었다.

이런 문제를 해결하는 노력으로서, 조지 리처는 mysql 4.1과 그 이상에서 새로운 특징을 지원 할 php5를 위한 새로운 mysql 확장을 만들었다.

이 확장은 mysqli확장(ext/mysqli)라고 부른다. I의 의미는 향상(improved), 연결(interface), 독창적인(ingenious), 비호환적인(incompatible), 미완성(incomplete) 이다.
(미완성이란 의미는 지금 개발중이라는 뜻으로 겸손한 입장에서 쓴걸로 보입니다.)

------------------------------주요 목표

새로운 확장의 주요 디자인 목표이다.

* 더 쉬운 관리 == mysql확장 소스코드는 다소복잡하고 조잡한했다. 다양한 특징을 요구하는 mysql의 기능에서 주요 개선은 클라이언트 라이브러리의 버전에 기반하여 사용가능하거나 사용불가능하게 되는 것이다.
* 보다 높은 호환성 == mysql 클라이언트 라이브러리에 보다 가깝게 편하기위해 필요했다. 그래서 그 앞으로 개선될 라이브러리에 대해 php 보다 쉽게 지원될 수 있다.
* 이전 버전과의 호환성 == 비록 mysql확장과 mysqli 사이에 호환성은 완벽하지 않다. 노력은 mysql확장에서 mysqli확장으로 간단히 포팅하는 쪽으로 할 것이다.

추가적으로, 이 확장은 추가적인 추적(additional tracing)와 디버깅, 로드 발란싱(load balancing), 복제기능을 지원한다.

---------------------------왜 바꾸는가?

Mysql 4.1+의 새로운 접근을 넘어서, 모든 사람이 mysqli확장을 사용하기를 원하는 이유가 무엇인가?

위에 언급한 기능에 추가로, mysqli 확장의  다음과 같은 장점이 있다.

* 놀라운 속도 == Ext/mysql과 비교하여 특정 조건에서는 40 가량 빠르다.
* 안전한 보안 == mysql RDBMS의 이전 버전에서 네트워크로부터 약간 패스워드 해쉬를 뽑아내기 위한 공격의 가능성이 존재했고, 그 다음에 사용자 패스워드를 재생성했다. 새로운 인증 절차는 보다 강하고 SSH같은 안전한 인증 절차이다.

--------------------------경고와 의외성

mysqli의 어떤 관점은 이전 확장과 아주 다르다.

* 디폴트 테이터베이스 커넥션 == 만약 여러분이 명시된 케녁션을 서버에 하지 않으면, mysqli는 여러분을 위해 접속하지 않을 것이다.
* 디폴트 링크 == 여러분이 사용하기 원하는 데이터베이스 서버 커넥션은 여러분이 절차 문맥을 통해 mysqli 확장을 사용할 때 명시적으로 참조될 것이다.

이 기사는 ‘world’ 테이터베이스를 사용하며 www.mysql.com에서 다운받을 수 있다.

-------------------기본적인 사용

여기 mysql 서버에 접속하고, 연결된 접속을 사용하여 서버에 쿼리문을 보내고 쿼리 결과를 보여주고 커넥션을 닫는 간단한 예제가 있다.

<?php

/* MySQL server에 접속 */
$link = mysqli_connect(
           'localhost',  /* The host to connect to */
           'user',       /* The user to connect as */
           'password',   /* The password to use */
           'world');     /* The default table to query */

if (!$link) {
  printf("Can't connect to MySQL Server. Errorcode: %s\n", mysqli_connect_error());
  exit;
}

/* 쿼리문을 서버에 보낸다 */
if ($result = mysqli_query($link, 'SELECT Name, Population FROM City ORDER BY Population DESC LIMIT 5')) {

   print("매우 큰 도시:\n");

   /* 쿼리문을 불러들이기 */
   while( $row = mysqli_fetch_assoc($result) ){
       printf("%s (%s)\n", $row['Name'], $row['Population']);
   }

   /* 결과를 파괴하고 그것에 사용된 메모리를 풀어준다 */
   mysqli_free_result($result);
}

/* 접속 닫기 */
mysqli_close($link);
?>

위의 스크립트는 다음과 같이 보여준다.

Very large cities are:

Mumbai (Bombay) (10500000)
Seoul (9981619)
S&atilde;o Paulo (9968485)
Shanghai (9696300)
Jakarta (9604900)

코드가 보여주듯이, mysqli확장과 mysql확장은 아주 비슷하다. 다만 주요 차이점은 절차적인 방식을 사용할 때, 약간 장황하다.

에러 체크를 없이, 위의 스크립트는 모든 핵심을 실패할 수 있고 에러 메시지를 보여줄 수 있다.

-----------------------객체 지향 인터 페이스 사용하기

* 우리는 명령을 위해 명시적 접속이 필요 치 않다. 접속 정보는 우리의 $mysqli와 $result 객체제 저장되고, 메소드를 호출할 때, 필요로서 접근된다
* fetch_assoc()를 사용하여 결과로부터 쿼리 테이터의 열(row)을 불러(fetching)들일 때, 우리는 그것을 사용하기 위해 명시적인 결과 처리를 하지 않아도 된다. 접속 정보로서, 결과 핸들링은 $result 객체에 저장된다.

<?php

/* MySQL 서버에 접속 */
$mysqli = new mysqli('localhost', 'user', 'password', 'world');

if (mysqli_connect_errno()) {
  printf("MySQL 서버에 접속할 수 없습니다. Errorcode: %s\n", mysqli_connect_error());
  exit;
}

/* 쿼리문을 서버에 보내기 */
if ($result = $mysqli->query('SELECT Name, Population FROM City ORDER BY Population DESC LIMIT 5')) {

   print("매우 큰 도시:\n");

   /* Fetch the results of the query */
   while( $row = $result->fetch_assoc() ){
       printf("%s (%s)\n", $row['Name'], $row['Population']);
   }

   /* 결과를 파괴하고 사용된 메모리를 풀어준다 */
   $result->close();
}

/* 접속 닫기 */
$mysqli->close();
?>


-------------------미리준비된 문장(Prepared Statements)

이제 우리는 이 확장의 기본 사용법을 봤다. 새로운 특징을 시험해 보자.

미리준비된 문장은 개발자에게 보다 안전하게 쿼리문을 작성할 수 있고 보다 성능이 높이 작서아기 보다 쉽게 만들어 준다.

그들은 두 양념이 있다.
바운드 파라미터 미리준비된 문장과 바운드 결과 미리준비된 문장.
Bound parameter parepared statements, and bound result prepared statements
(이걸 어떻게 번역해야 할 지, 도저히 감이 않오네요. 이상해도 이해바랍니다.)

--------------------------바운드 파라미터

바운드 파라미터 미리준비된 문장은 쿼리 템플릿을 만들고나서 MySQL 서버에 저장하게 한다. 쿼리문을 만들어야 하고, 템플릿에서 채우기 위한 데이터에서 mysql 서버에 보낸다. 그리고 완전한 쿼리는 형성되고나서 실행된다.

바운드 파라미터 미리 준비된 문장을 사용하고 만드는 기본 과정은 간단하다.

쿼리 템플릿은 만들어지고 mysql 서버에 보내진다. Mysql 서버는 쿼리 템플릿을 받는다. 잘 정의되었는지 검사하고 의미있는지 구분분석하고 특정 버퍼에 저장한다. 그것은 미리준비된 문장을 참고하기 위해 사용될 수 있게 특정 핸들을 반환한다.

만들어야 하는 쿼리가 필요할 때, 템플릿에서 채우기 위한 데이터는 MySQL 서버에 보내지고 완전한 쿼리는 형성되고 나서 실행된다.

이런 과정은 그것을 감싸는 대단히 중요한 동작이다.

쿼리문의 몸체(body)는 단지 MySQL 서버에 보내진다. 쿼리의 실행하기 위한 요청이 있으면, 단지 템플릿에서 채우기위한 대이테가 MySQL 서버에 보내게 되는 것이 필요하다.

쿼리가 실행되는 각각의 시간 대신에, 그런 쿼리문을 검사하고 분석하기 위해 필요한 작업의 대부분은 한번에 되는 것이 필요하다.

추가적으로, 작은 데이터를 포함하는 쿼리를 위해, 쿼리 전송 오버해드는 대단히 줄어든다. 예를 들면, 다음과 같은 쿼리가 있다면..

INSERT INTO City (ID, Name) VALUES (NULL, 'Calgary');

여러분이 쿼리를 실행하고 나서, 여러분은 60이나 그 이상 바이트 대신에, 단지 쿼리 데이터 16 바이트정보 보내는 것이 필요할 것이다.

쿼리를 위한 데이터는 SQL 인젝션 공격(SQL injection attcacks) 존재하지 않기 위해 mysql_real_string()같은 함수를 통하여 넘기는 것이 필요치 않다.

!!!!!!!!!!!!!!용어 설명시작
SQL 인젝션 공격은 데이터가 악의적인 방법으로 기대되지 않은 and/or를 동작하기 위해 쿼리문을 입력할 때 존재한다. 예를 들면 “DELETE FROM grades WHERE class_name=’test_$class’” 처럼 php 스크립트에서 간단한 쿼리를 주면, $class의 변수에 대해 제어 할 수 있는 공격자가, “oops’ or class_name LIKE ‘%’” 처럼 어떤 것을 $class의 변수를 바꿈으로서 발생을 위해 강제로 지울 수 있다.
!!!!!!!!!!!!!!!용어 설명끝

대신에, MySQL 클라이언트와 서버는 미리준비된 문장으로 결속되었을 때, 보낸 데이터가 안전하게 처리될수 있도록 한다.

INSERT INTO City (ID, Name) VALUES (?, ?);

'?' 위치는 literal 데이터를 가진 대부분의 위치에서 사용될 수 있고, 예를 들면from에서 변형 될 수 있다

SELECT Name FROM City WHERE Name = 'Calgary';

위 문장이 아래로 바뀔 수 있다.

SELECT Name FROM City WHERE name = ?;

여기 전체 과정을 설명하기 위한 보다 복잡한 예제가 있다.

<?php
$mysqli = new mysqli('localhost', 'user', 'password', 'world');

/* 접속 체크 */
if (mysqli_connect_errno()) {
   printf("Connect failed: %s\n", mysqli_connect_error());
   exit();
}

$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$stmt->bind_param('sssd', $code, $language, $official, $percent);

$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;

/* 미리준비된 문장 실행하기 */
$stmt->execute();

printf("%d Row inserted.\n", $stmt->affected_rows);

/* 문장과 접속 닫기 */
$stmt->close();

/* CountryLanguage 테이블을 지운다 */
$mysqli->query("DELETE FROM CountryLanguage WHERE Language='Bavarian'");
printf("%d Row deleted.\n", $mysqli->affected_rows);

/* 접속 닫기 */
$mysqli->close();
?>

bind_param() 이 처음 파라미터로서 짧은문장이 가지고 있는걸 주목하여라. 이것은 바운드 변수에서 데이터가 어떻게 처리되는지 알려주기 위해 사용되는 형식 문자열이다.

위의 스크립트 경우에서 ‘sssd’는 네번째 파라미터 $percent가 double 또는 float 변수를 포함하는 반면에, 처음 세개의 파라미터 $code, $language, $official가 문자열로서 보내질 것을 지적한다.

!!!!!!!!!용어 설명 시작
계가 bound parameter를 계속 바운드 파라미터라고 번역 했는데, 한글로 번역하자면, 결속 인자라고 할 수 있습니다. Bound는 bind의 과거분사로서 결합된, 결속된, 묶인 그런 의미가 있고, 우리가 포장할 때 상자를 끈으로 묶는(bound)는 의미가 있습니다.
!!!!!!!!!용어설명 끝

bind_param()에서, 각각의 바운드 변수는, 형식 문자열에서, 변수가 어떻게 핸들링되는 명세하는 다른 문자가 될 것이다.

예를 들면

$stmt->bind_param('s', $foo);
$stmt->bind_param('si', $foo, $bar);
$stmt->bind_param('sid', $foo, $bar, $baz);

바인트 타입은 mysqli 확장이 효육성을 위해 그것이 보내는 데이터를 어떻게 인코드(encode)하는지 알게 해준다.

결속(bind) 타입은 매우 간결하다. 데이터는 바운드 변수에서 정수(integer) 변수나 double 변수나 문자열(string)으로서 처리 될것이다.

MySQL 서버에 보내지는 long blobs 같은 특별한 타입도 있다
다음과 같은 데이블은 그 사용을 보여준다.

----------------------------
BIND    |  TYPE COLUMN TYPE
i        |  All INT types
d        |  DOUBLE and FLOAT
b        |  BLOBs
s        | All other types
--------------------------------

---------------------------바운드 결과

바운드 결과 미리준비된 문장은 php에서 가변 변수가 쿼리 결과들에서 데이터 필드 변수에 묶이게 되게 해준다.

이런 결속설정하는 과정이다.

* 쿼리 생성
* 쿼리를 미리준비하게 위해 MySQL 서버에 요청
* 미리준비된 쿼리에서 PHP 변수를 컬럼(columns)에 결속(bind)한다
* 새로운 데이터의 열이 바운드 변수로 적재되도록 요청한다.

여기  이 과정을 상세설명하는 짧은 코드가 있다.

<?php
$mysqli = new mysqli("localhost", "user", "password", "world");

if (mysqli_connect_errno()) {
   printf("Connect failed: %s\n", mysqli_connect_error());
   exit();
}

/* 미리 준비된 문장 */
if ($stmt = $mysqli->prepare("SELECT Code, Name FROM Country ORDER BY Name LIMIT 5")) {
   $stmt->execute();

   /* 변수를 미리준비된 문장에 결속한다 */
   $stmt->bind_result($col1, $col2);

   /* 값을 불러들인다 */
   while ($stmt->fetch()) {
       printf("%s %s\n", $col1, $col2);
   }

   /* 문장을 닫는다 */
   $stmt->close();
}
/* 접속을 닫는다 */
$mysqli->close();

?>


-----------------------바운드 파라미터와 바운드 결과를 같이 사용하기

이것은 바운드 파라미터와 바운드 결과를 함께 쓰는 법을 설명하는 보다 복잡한 예제이다.


<?php
$mysqli = new mysqli("localhost", "user", "password", "world");

if (mysqli_connect_errno()) {
   printf("Connect failed: %s\n", mysqli_connect_error());
   exit();
}

/* 미리 준비된 문장 */
if ($stmt = $mysqli->prepare("SELECT Code, Name FROM Country WHERE Code LIKE ? LIMIT 5")) {

   $stmt->bind_param("s", $code);
   $code = "C%";

   $stmt->execute();

   /* 변수를 미리 준비된 문장에 결합, bind variables to prepared statement */
   $stmt->bind_result($col1, $col2);

   /* fetch values */
   while ($stmt->fetch()) {
       printf("%s %s\n", $col1, $col2);
   }

   /* 문장 닫기 */
   $stmt->close();
}
/* 접속 닫기 */
$mysqli->close();

?>
/* 제가 보니 잘만 사용하면 대단히 효율적일 것 같다는 생각이 듭니다. 일종의 템플릿 같은 거라고 생각하시면 될 듯 싶습니다. */

---------------------------요약

이 기사는, 우리가 그 개발 과정의 빠른 요약과 함께 mysqli확장의 특징과 설계의 개요를 제공했다. 여러분은 MySQL의 미리준비된 문장과 그것의 장점을 이해했고 어떻게 사용하는지 알았고 Mysql 확장에 객체지향 인터페이스를 편하게 사용할 수 있을 것이다.

---------------------------번역자에 관하여

집에서 놀고 있는 백수


2006/09/08 10:51 2006/09/08 10:51
이 글에는 트랙백을 보낼 수 없습니다

Many changes have been made to temporal — DATE, TIME, DATETIME, and TIMESTAMP — functions in MySQL 4.1. This includes support for microseconds and time zones.

In this article, a time value is one of either: TIME, DATETIME, or TIMESTAMP. A date value is one of either: DATE, DATETIME, or TIMESTAMP. A datetime value is one of any of the date or time value types.

Changed Functions

Several existing functions had their functionality extended in MySQL 4.1:

ADDDATE(temporal_expression, number_of_days)
SUBDATE(temporal_expression, number_of_days)

ADDDATE and SUBDATE accept a slightly modified syntax beginning with version 4.1.1. They still operate on a date value, but now also accept a second, numeric argument.

The second argument specifies a number of days that should be added to (or subtracted from) the date value. As always, if either argument resolves to NULL, ADDDATE and SUBDATE returns NULL.

mysql> select adddate('2004-10-01',15), subdate('2004-10-01',15);+--------------------------+--------------------------+| adddate('2004-10-01',15) | subdate('2004-10-01',15) |+--------------------------+--------------------------+| 2004-10-16               | 2004-09-16               |+--------------------------+--------------------------+1 row in set (0.20 sec)
DATE_ADD(temporal_expression, INTERVAL interval_expression interval_constant)
DATE_SUB(temporal_expression, INTERVAL interval_expression interval_constant)
EXTRACT(interval_constant FROM temporal_expression)

The DATE_ADD, DATE_SUB, and EXTRACT functions accept five new interval constants — DAY_MICROSECOND, HOUR_MICROSECOND, MINUTE_MICROSECOND, SECOND_MICROSECOND, and MICROSECOND.

mysql> SELECT DATE_ADD('1992-12-31 23:59:59.000002',INTERVAL '1.999999' SECOND_MICROSECOND);+--------------------------------------------------------------------------------+| DATE_ADD('1992-12-31 23:59:59.000002', INTERVAL '1.999999' SECOND_MICROSECOND) |+--------------------------------------------------------------------------------+| 1993-01-01 00:00:01.000001                                                     |+--------------------------------------------------------------------------------+1 row in set (0.02 sec)
DATE_FORMAT(temporal_expression, format_string)
TIME_FORMAT(time_expression, format_string)

The DATE_FORMAT and TIME_FORMAT functions got a new option in MySQL 4.1.1 too. One can now use %f in the format string, to return microseconds in the range from 000000 (6 zeros) to 999999 (6 nines).

mysql> select date_format(current_timestamp,'%f');+-------------------------------------+| date_format(current_timestamp,'%f') |+-------------------------------------+| 000000                              |+-------------------------------------+1 row in set (0.02 sec)mysql> select time_format(current_time,'%f');+--------------------------------+| time_format(current_time,'%f') |+--------------------------------+| 000000                         |+--------------------------------+1 row in set (0.02 sec)

New Functions

About twenty new temporal functions were added. Many of them are implementations of similar functions from other database systems, such as MaxDB and Oracle.

ADDTIME(temporal_expression, time_expression)
SUBTIME(temporal_expression, time_expression)

The ADDTIME and SUBTIME functions provide the ability to do time arithmetic. They accept two arguments, the first of which must resolve to a time value, and the second of which must resolve to a TIME value. ADDTIME adds the time argument to the first expression and returns the result, and as you may expect, SUBTIME subtracts the time argument from the first expression and returns the result. Both functions returns NULL if either argument resolves to NULL.

mysql> select addtime('10:15:30','02:10:00'), subtime('2004-10-15 10:15:30','02:10:00');+--------------------------------+-------------------------------------------+| addtime('10:15:30','02:10:00') | subtime('2004-10-15 10:15:30','02:10:00') |+--------------------------------+-------------------------------------------+| 12:25:30                       | 2004-10-15 08:05:30                       |+--------------------------------+-------------------------------------------+1 row in set (0.20 sec)
DATEDIFF(temporal_expression, temporal_expression)

The DATEDIFF function returns the number of days between its two arguments, which must both resolve to a date value. The function returns NULL if either argument resolves to NULL.

mysql> select datediff('2004-10-20','2004-10-10');+-------------------------------------+| datediff('2004-10-20','2004-10-10') |+-------------------------------------+|                                  10 |+-------------------------------------+1 row in set (0.02 sec)
TIMEDIFF(temporal_expression, temporal_expression)

The TIMEDIFF function is another new function that provides time arithmetic functionality. This function returns the amount of time elapsed between the two temporal arguments. Both arguments must resolve to the same type of time value. TIMEDIFF returns NULL if either argument resolves to NULL.

mysql> select timediff('10:30:15','02:10:00');+---------------------------------+| timediff('10:30:15','02:10:00') |+---------------------------------+| 08:20:15                        |+---------------------------------+1 row in set (0.02 sec)
DATE(temporal_expression)
TIME(temporal_expression)

The DATE function returns the DATE portion of a date value. It returns NULL if its argument resolves to NULL.

The TIME function complements the DATE function; it takes a time value and returns its TIME portion. TIME returns NULL if its argument resolves to NULL.

mysql> select date('2004-10-01 10:15:30'), time('2004-10-01 10:15:30');+-----------------------------+-----------------------------+| date('2004-10-01 10:15:30') | time('2004-10-01 10:15:30') |+-----------------------------+-----------------------------+| 2004-10-01                  | 10:15:30                    |+-----------------------------+-----------------------------+1 row in set (0.02 sec)
MAKEDATE(year, day_of_year)
MAKETIME(hour, minute, second)

The MAKEDATE function returns the date that results from the combination of its arguments. Both arguments must resolve to a positive integer; the first specifies a YEAR value and the second specifies a given day in that year. The function returns NULL if either argument resolves to NULL. MAKEDATE also returns NULL if the day_of_year value is less than or equal to 0 (zero).

The MAKETIME function takes three arguments — an HOUR value, a MINUTE value, and a SECOND value — and returns the time that results by combining them. Each of the arguments must resolve to an integer. The function returns NULL if any of the arguments resolve to NULL.

mysql> select makedate(2004,152), maketime(10,15,30);+--------------------+--------------------+| makedate(2004,152) | maketime(10,15,30) |+--------------------+--------------------+| 2004-05-31         | 10:15:30           |+--------------------+--------------------+1 row in set (0.02 sec)
TIMESTAMP(temporal_expression)
TIMESTAMP(date_expression, time_expression)

The TIMESTAMP function has two possible formats.

In the first format, the function takes a date value and returns it as a TIMESTAMP value.

mysql> select timestamp('2004-10-15');+-------------------------+| timestamp('2004-10-15') |+-------------------------+| 2004-10-15 00:00:00     |+-------------------------+1 row in set (0.02 sec)

In the second format, TIMESTAMP accepts two arguments: a date value and a TIME value. The TIME value is added to the first expression and TIMESTAMP returns the result as a TIMESTAMP value.

mysql> select timestamp('2004-10-15','10:15:30');+------------------------------------+| timestamp('2004-10-15','10:15:30') |+------------------------------------+| 2004-10-15 10:15:30                |+------------------------------------+1 row in set, 1 warning (0.02 sec)

In each case, the function returns NULL if an argument resolves to NULL.

And now, a short digression. The TIMESTAMP data type itself was changed slightly in MySQL 4.1. Recall that in earlier versions of MySQL, TIMESTAMP includes an optional display width parameter, that lets one specify the size of a TIMESTAMP column when it is displayed, like this.

mysql> create table xy (col1 timestamp(8));Query OK, 0 rows affected (0.41 sec)mysql> insert into xy values('2004-10-01 10:15:30');Query OK, 1 row affected (0.01 sec)

With 4.0:

mysql> select * from xy;+----------+| col1     |+----------+| 20041001 |+----------+1 row in set (0.02 sec)

Although this syntax is still accepted, the option is no longer operative beginning with MySQL 4.1. From the 4.1.0 release on, a TIMESTAMP value is always returned as a string with the format 'YYYY-MM-DD HH:MM:SS' and different timestamp lengths are not supported.

Same definition, with 4.1:

mysql> select * from xy;+---------------------+| col1                |+---------------------+| 2004-10-01 10:15:30 |+---------------------+1 row in set (0.02 sec)
DAY(date_expression)

The DAY function is a synonym for DAYOFMONTH(). It returns the day portion of its date value argument. DAY returns NULL if the argument resolves to NULL.

mysql> select day('2004-10-01');+-------------------+| day('2004-10-01') |+-------------------+|                 1 |+-------------------+1 row in set (0.02 sec)
LAST_DAY(date_expression)

The LAST_DAY function takes a date value and returns the corresponding value for the last day of the given month. LAST_DAY returns NULL if the argument resolves to an invalid value (e.g. '2004-10-32') or if the argument is NULL.

mysql> select last_day('2004-10-01');+------------------------+| last_day('2004-10-01') |+------------------------+| 2004-10-31             |+------------------------+1 row in set (0.02 sec)
MICROSECOND(time_expression)

The MICROSECOND function takes a time value as an argument, and returns the microsecond portion of that value. MICROSECOND returns NULL if the argument resolves to NULL.

mysql> select microsecond('2004-10-15 10:15:30.999999');+-------------------------------------------+| microsecond('2004-10-15 10:15:30.999999') |+-------------------------------------------+|                                    999999 |+-------------------------------------------+1 row in set (0.03 sec)
WEEKOFYEAR(temporal_expression)

The WEEKOFYEAR function calculates the calendar week of its date value argument and returns the week number. The result always falls into the range from 1 (first week of the year) to 53 (last week of the year). Note that the first week of the year is the first week that has a Thursday in that year (or put another way, the week that contains January 4th). WEEKOFYEAR returns NULL if its argument resolves to NULL.

mysql> select weekofyear('2004-10-15'), weekofyear('2000-01-01');+--------------------------+--------------------------+| weekofyear('2004-10-15') | weekofyear('2000-01-01') |+--------------------------+--------------------------+|                       42 |                       52 |+--------------------------+--------------------------+1 row in set (0.01 sec)
STR_TO_DATE(temporal_string, format_string)

The STR_TO_DATE function converts its temporal_string argument into a DATE, TIME, DATETIME, or TIMESTAMP value with the format specified by its format_string argument.

The format_string argument accepts the same formats as the DATE_FORMAT function; the temporal_string given must be a temporal value written in the same format. STR_TO_DATE returns NULL if the temporal_string is an invalid value for the given format, or if either argument resolves to NULL.

mysql> select str_to_date('2004-10-15 10:15:30','%Y-%m-%d %H:%i:%s');+--------------------------------------------------------+| str_to_date('2004-10-15 10:15:30','%Y-%m-%d %H:%i:%s') |+--------------------------------------------------------+| 2004-10-15 10:15:30                                    |+--------------------------------------------------------+1 row in set (0.02 sec)mysql> select str_to_date('2004-10-15 10:15:30','%d.%m.%y %H.%i');+-----------------------------------------------------+| str_to_date('2004-10-15 10:15:30','%d.%m.%y %H.%i') |+-----------------------------------------------------+| NULL                                                |+-----------------------------------------------------+1 row in set (0.02 sec)
GET_FORMAT(temporal_constant, format_string_constant)

The GET_FORMAT function returns a format string, like the ones we're used to using as arguments for the DATE_FORMAT and TIME_FORMAT functions. The temporal_constant argument has four possible values: DATE, TIME, DATETIME, and TIMESTAMP (but not until 4.1.4 for TIMESTAMP). The format_string_constant argument has five possible values, which must be enclosed in single quotes: 'EUR', 'USA', 'JIS', 'ISO', and 'INTERNAL'.

mysql> select get_format(timestamp,'iso');+-----------------------------+| get_format(timestamp,'iso') |+-----------------------------+| %Y-%m-%d %H:%i:%s           |+-----------------------------+1 row in set (0.02 sec)

The combination of valid values for GET_FORMAT's two arguments gives us up to 20 possible returns from the function: five for DATE, five for TIME, five for DATETIME, and five more for TIMESTAMP. When used with TIMESTAMP as the temporal constant, GET_FORMAT returns the same values as shown for DATETIME.

Function CallResult
GET_FORMAT(DATE,'USA')'%m.%d.%Y'
GET_FORMAT(DATE,'JIS')'%Y-%m-%d'
GET_FORMAT(DATE,'ISO')'%Y-%m-%d'
GET_FORMAT(DATE,'EUR')'%d.%m.%Y'
GET_FORMAT(DATE,'INTERNAL')'%Y%m%d'
GET_FORMAT(DATETIME,'USA')'%Y-%m-%d-%H.%i.%s'
GET_FORMAT(DATETIME,'JIS')'%Y-%m-%d %H:%i:%s'
GET_FORMAT(DATETIME,'ISO')'%Y-%m-%d %H:%i:%s'
GET_FORMAT(DATETIME,'EUR')'%Y-%m-%d-%H.%i.%s'
GET_FORMAT(DATETIME,'INTERNAL')'%Y%m%d%H%i%s'
GET_FORMAT(TIME,'USA')'%h:%i:%s %p'
GET_FORMAT(TIME,'JIS')'%H:%i:%s'
GET_FORMAT(TIME,'ISO')'%H:%i:%s'
GET_FORMAT(TIME,'EUR')'%H.%i.%S'
GET_FORMAT(TIME,'INTERNAL')'%H%i%s'

These formats came from how MaxDB defines its date and time formats.

The MySQL Reference Manual shows two examples of GET_FORMAT used in conjunction with the DATE_FORMAT and STR_TO_DATE functions, which I'll repeat here.

mysql> SELECT DATE_FORMAT('2003-10-03',GET_FORMAT(DATE,'EUR'));    -> '03.10.2003'mysql> SELECT STR_TO_DATE('10.31.2003',GET_FORMAT(DATE,'USA'));    -> 2003-10-31
UTC_DATE
UTC_DATE()
UTC_TIME
UTC_TIME()
UTC_TIMESTAMP
UTC_TIMESTAMP()

These functions, which can be written either with or without the parentheses, are niladic functions — they take no arguments.

UTC_DATE returns the current UTC (or Universal Coordinated Time) date as a value in either 'YYYY-MM-DD' or YYYYMMDD form (depending on whether the function is used in a string or numeric context). By the way, most people still call UTC time "Greenwich Mean Time".

The UTC_TIME function returns the current UTC time as a value in 'HH:MM:SS' or HHMMSS form (depending on whether the function is used in a string or numeric context).

The UTC_TIMESTAMP function returns the current UTC date and time as a value in 'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS form (depending on whether the function is used in a string or numeric context).

mysql> select utc_date(), utc_date+1;+------------+------------+| utc_date() | utc_date+1 |+------------+------------+| 2004-09-14 |   20040915 |+------------+------------+1 row in set (0.02 sec)mysql> select utc_time(), utc_time+1;+------------+------------+| utc_time() | utc_time+1 |+------------+------------+| 16:09:12   |     160913 |+------------+------------+1 row in set (0.03 sec)mysql> select utc_timestamp(), utc_timestamp+1;+---------------------+-----------------+| utc_timestamp()     | utc_timestamp+1 |+---------------------+-----------------+| 2004-09-14 16:12:36 |  20040914161237 |+---------------------+-----------------+1 row in set (0.02 sec)

Time Zone Handling

MySQL 4.1 includes increased support for manipulating temporal values based on the time zone in which they exist.

For example, beginning with MySQL 4.1.3, the CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP(), FROM_UNIXTIME(), LOCALTIME, LOCALTIMESTAMP, NOW, SYSDATE, and UNIX_TIMESTAMP() functions return values in the connection's current time zone, while the UTC_DATE(), UTC_TIME(), and UTC_TIMESTAMP() functions return values in Universal Coordinated, or UTC, time.

In addition, the new CONVERT_TZ function provides the ability to convert a DATETIME or TIMESTAMP value from one time zone to another.

Finally, data values of the TIMESTAMP data type are automatically interpreted as values belonging to the connection's current time zone. TIMESTAMP values thus behave the way they do in Oracle's TIMESTAMP WITH LOCAL TIME ZONE data type — that is, values stored in a TIMESTAMP column are normalized towards UTC and converted back to the current connection time zone at SELECT time. This gives MySQL the ability to provide the "current" TIMESTAMP value, even if the database is moved to a different location.

This brings up another point about changes to the TIMESTAMP data type.

The internal representation of TIMESTAMP values in InnoDB tables was changed between version 4.0 and 4.1, and then back again in version 4.1.4. This change will result in incorrect values in TIMESTAMP columns belonging to InnoDB tables after an upgrade.

To correct this problem, the course of action, when upgrading from MySQL 4.1.3 or earlier to version 4.1.4, is to use mysqldump to save, and then restore, all InnoDB tables that contain TIMESTAMP columns.

Now, back to time zones. Recall that in previous versions of MySQL, the time zone that is relevant for the server can be set either with the --timezone=timezone_name option to mysqld_safe or with the TZ environment variable when starting mysqld. That changed in MySQL 4.1.3.

Here's what happens now:

Beginning with MySQL 4.1.3, the MySQL server maintains several time zone settings: the system time zone, the server's current time zone, and a connection time zone for each client.

The system time zone.

When the server starts, it looks for the time zone of the host machine and uses that value to automatically set the system_time_zone system variable.

This variable replaces the old timezone system variable, which has been removed. So users migrating from an earlier version of MySQL will need to ensure that they replace all instances of the timezone system variable with references to system_time_zone instead.

The server's current time zone.

The dynamic global time_zone system variable specifies the time zone in which the server is running. Its initial value is 'SYSTEM', which simply means that the server time zone and the system time zone are the same.

This initial value can be explicitly set with the --default-time-zone=timezone option. Users with the SUPER privilege can also set the global value at runtime, with the SET GLOBAL time_zone statement, as shown here.

mysql> SET GLOBAL time_zone = timezone;

To get the current global time zone value, SELECT the @@global.time_zone variable:

mysql> SELECT @@global.time_zone;
The connection time zone for each client.

Each client that connects to MySQL has its own time zone setting, specified by the dynamic session time_zone variable. The initial value of this variable is the same as the global time_zone variable, but can be reset at runtime with the SET time_zone statement.

mysql> SET time_zone = timezone;

To get the current session time zone value, SELECT the @@session.time_zone variable:

mysql> SELECT @@session.time_zone;

You'll notice the = timezone argument in the SET GLOBAL time_zone and SET time_zone statements, as well as the same argument in the --default-time-zone server option. The values for these arguments can be given in one of three ways:

  1. As a string that specifies an offset from UTC, in the form '[+|-]HH:MM', for example '-7:00', to indicate the time zone that is seven hours earlier than UTC, Mountain Time. This method is always possible, regardless of which operating system MySQL is running under and whether or not the MySQL time zone tables have been populated.
  2. As a string that provides a full time zone name, for example 'Mountain Daylight Time'.
  3. Or as a string that provides an abbreviation for a full time zone name, for example, 'MDT', which is the abbreviation for 'Mountain Daylight Time'. By the way, the names I've used here are not universally accepted, since time zone names and abbreviations are operating system specific.

These last two methods work only on Unix-based systems and only if the time zone-related tables in the mysql database have been created and populated.

Now, it's important to remember that, although installing MySQL 4.1.3 or higher creates the time zone tables, the procedure does not also populate them. This last step must be done manually.

Also, users who are migrating from an earlier version of MySQL need to create the time zone tables separately, by upgrading the mysql database. If they don't, they won't be able to take advantage of the new time zone features.

So there's two things to do to ensure a smooth transition between MySQL 4.0 (or earlier) and 4.1.3 (and higher).

Step 1: Only if migrating from 4.1.2 or earlier:

Create the correct time zone tables, by running the mysql_fix_privilege_tables script.

Step 2: For all users running MySQL 4.1.3 or later on a Unix-based system (recall this doesn't work on Windows systems yet):

Populate the time zone tables.

To do so, run the mysql_tzinfo_to_sql program, provided with the MySQL distribution. mysql_tzinfo_to_sql reads the operating system time zone files and generates SQL statements from them. The SQL statements are then processed by mysql, to load the time zone tables.

To run mysql_tzinfo_to_sql successfully, one needs to know where the server machine's operating system time zone files are stored; check for a directory with a name similar to /usr/share/zoneinfo. Pass the directory name on the command line to mysql_tzinfo_to_sql, and send the output into the mysql program. Here's an example.

shell> mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql

mysql_tzinfo_to_sql can also be used to generate leap second information. An installation that needs to account for leap seconds within the database can initialize the leap second information by passing the name of a file holding the required information to the mysql program, as shown here.

shell> mysql_tzinfo_to_sql --leap file-name | mysql -u root mysql

Finally, there's one new function that makes use of the time zone tables to convert a datetime value between two timezones:

CONVERT_TZ(temporal_expression, from_timezone, to_timezone)

The CONVERT_TZ function takes three arguments. The first argument must resolve to a DATETIME or TIMESTAMP value, while the others must each resolve to a time zone in the form '[+|-]HH:MM' or a named time zone identifier, such as 'GMT' or (on some systems) 'Greenwich Mean Time'. Named time zones can only be used if the time zone tables are properly set up.

CONVERT_TZ assumes that the first argument is a datetime value that belongs to the time zone given in the from_timezone argument. The function converts that value into a datetime value belonging to the time zone given in the to_timezone argument.

In effect, you get the same datetime value, but from the point of view of a different time zone. The function returns NULL if any of the arguments are invalid, and also if any of the arguments resolve to NULL.

mysql> select convert_tz('2004-10-01 10:15:30','+01:00','+07:00');+-----------------------------------------------------+| convert_tz('2004-10-01 10:15:30','+01:00','+07:00') |+-----------------------------------------------------+| 2004-10-01 16:15:30                                 |+-----------------------------------------------------+1 row in set (0.02 sec)

Fractional Seconds

Fractional seconds support is simple. We have very little of it with 4.1, but the foundation has been laid for adding more support in later versions.

At this time, MySQL does not provide the ability to define a fractional-seconds precision for a time value column, although it is planned to add this ability to the TIMESTAMP data type in a future version. In fact, the syntax is accepted, but nothing is done with the fractional-seconds definition.

The reason the syntax is accepted, of course, is due to the fact that in previous versions of MySQL, one could define a display width for the TIMESTAMP data type, as I alluded to earlier.

It is possible to INSERT a TIMESTAMP value that includes a fractional-seconds portion into a TIMESTAMP column without getting an error. But it isn't possible to get the complete value, or even just the microseconds portion, back out because the microseconds are just chopped off at INSERT time.

mysql> create table xy(tscol timestamp);Query OK, 0 rows affected (0.09 sec)mysql> insert into xy (tscol) values ('2004-10-15 10:15:30.999999');Query OK, 1 row affected (0.01 sec)mysql> select * from xy;+---------------------+| tscol               |+---------------------+| 2004-10-15 10:15:30 |+---------------------+1 row in set (0.04 sec)mysql> select extract(microsecond from tscol) from xy;+---------------------------------+| extract(microsecond from tscol) |+---------------------------------+|                               0 |+---------------------------------+1 row in set (0.00 sec)

Nor do the niladic temporal functions that could include fractional seconds — CURRENT_TIME, CURRENT_TIMESTAMP, LOCALTIME, LOCALTIMESTAMP, NOW, SYSDATE, and so on — return values that include a fractional-seconds portion.

So, what do we do with microseconds?

Well, MySQL 4.1 can do temporal arithmetic that takes microseconds into account. As I said earlier, both the DATE_ADD and the DATE_SUB functions will now accept an INTERVAL qualifier of either MICROSECOND, SECOND_MICROSECOND, MINUTE_MICROSECOND, HOUR_MICROSECOND, or DAY_MICROSECOND — and will add (or subtract, respectively) the given value to or from a given temporal value. The same is true for temporal arithmetic done with the INTERVAL keyword.

mysql> select current_timestamp + INTERVAL 1.999999 second_microsecond;+----------------------------------------------------------+| current_timestamp + INTERVAL 1.999999 second_microsecond |+----------------------------------------------------------+| 2004-09-16 16:28:45.999999                               |+----------------------------------------------------------+1 row in set (0.02 sec)

The new ADDTIME and SUBTIME functions also do time arithmetic that includes microseconds. So does the TIMEDIFF function. The DATE_FORMAT, TIME_FORMAT and STR_TO_DATE functions now accept format strings with the ability to properly display temporal values that include a fractional-seconds portion. The EXTRACT and MICROSECOND functions can now return the fractional-seconds portion of a temporal value. And the TIME and TIMESTAMP functions can return values that include a fractional-seconds portion.

To summarize: MySQL's fractional-seconds support beginning with version 4.1 allows one to manipulate temporal values that include microseconds, but does not allow one to actually store such values in the database.

2006/09/08 10:48 2006/09/08 10:48
이 글에는 트랙백을 보낼 수 없습니다
출처 블로그 > 폴라리스
원본 http://blog.naver.com/neodays/20018207957

mysql 4.0 --> mysql 4.1 업그레이드시 확인사항


# 항목앞에 (*) 는 Incompatible Change(호환되지 않는 변경) 입니다.. 주의요망!!

# 이글을 작성당시 4.1 최신버전은 4.1.10 입니다.

# 이글은 mysql document 중 Upgrading from Version 4.0 to 4.1 을 번역한 겁니다.


- 글자셋 지원이 향상되었다. 서버는 다중 글자셋을 지원한다.

- 4.1 은 테이블명,컬럼명을 UTF8 형식으로 저장한다. standard 7-bit US-ASCII 가 아닌 문자로 된 테이블명, 컬럼명이 있을때는 dump & restore 를 사용하라.

그렇지 않으면(직접 복사,이전한 경우) 테이블을 사용할 수 없을 것이며 table not found 에러가 발생할 것이다. 이 경우에는 4.0 으로 다운그레이드 하면 다시 사용할 수 있다.

- 권한테이블의 password 필드가 길어졌다. mysql_fix_privilege_tables 를 사용하여 수정하라.

- Berkeley DB table handler 의 포멧이 더 길어졌다. 4.0 으로 다운그레이드 해야할 경우 mysqldump 를 사용하여 백업하고 4.0 서버를 시작하기 전에 모든 log.XXXXXXXXXX 파일을 삭제한 후 데이타를 로드하라.

- 커넥션별 타임존을 지원한다. 이름으로 타임존을 사용하려면 time zone 테이블을 생성해야 한다.

- 오래된 DBD-mysql module (Msql-MySQL-modules) 을 사용한다면 새 버전(DBD-mysql 2.xx 이상)으로 업그레이드하라. 업그레이드하지 않으면 몇몇 메소드(DBI->do() 와 같은..)가 에러상태를 정확히 판단하지 못할 것이다.

- --defaults-file=option-file-name 옵션은 옵션파일이 없다면 에러를 낼 것이다.

- 4.0.12 이상의 버전이라면 4.1 의 변화를 미리 적용해 볼 수 있다. --new 옵션을 사용하여 mysqld 를 실행하라. 또한 SET @@new=1 명령으로도 동작시킬수 있으며 SET @@new=0 으로 중단할 수있다.

몇가지 4.1 의 변화가 (업그레이드시) 문제가 될 수 있다고 생각되면 업그레이드하기 전에 --new 옵션을 사용해 미리 적용해 보길 권한다. 옵션파일에 아래와 같이 추가하여 적용해 볼 수 있다.

[mysqld-4.0]
new


[Server Changes]

1. 모든 테이블과 컬럼들이 글자셋을 가진다. 글자셋은 SHOW CREATE TABLE 을 사용해 확인할 수 있으며 mysqldump 에서도 글자셋 설정이 추가되었다.(4.0.6 이상의 버전에서는 이 새로운 형식의 덤프를 이해할 수 있지만 그 이전버전에서는 이해할 수 없다.) 단일글자셋을 사용하는 환경에서는 아무런 영향이 없다.( 즉 이전버전에서는 mysqldump 의 글자셋 설정이 아무 의미가 없다는 뜻..)

2. 4.1에서 직접 지원하는 글자셋을 사용한 4.0 데이타는 그대로 사용이 가능하다. 또한 4.1 에서 DB명, 테이블명, 컬럼명은 기본 글자셋이 무엇이든 상관없이 유니코드(UTF8) 로 저장된다.

(*)3. 4.1.0 ~ 4.1.3 버전에서 InnoDB 테이블에 TIMESTAMP 컬럼을 사용했다면 Dump & Restore 해야한다. 해당 버전의 TIMESTAMP 컬럼의 저장방식이 잘못되었다. 4.0 버전이거나 4.1.4 이후 버전이라면 문제가 없다.

(*)4. 4.1.3 부터 InnoDB 는 latin1 이 아니고 BINARY 가 아닌 문자열의 비교에 글자셋 비교함수를 사용한다. 이것으로 공백문자와 ASCII(32) 보다 작은 코드값의 문자들은 글자셋 내에서 정렬순서에 변화가 생겼다. InnoDB 는 latin1 과 BINARY 문자열에 대해서는 여전히 문자열 끝에 공백을 추가하여 비교하는 방식을 사용한다. 만약 4.1.2 혹은 그 이전 버전에서 latin1 이 아닌 컬럼에 인덱스가 있거나 테이블에 CHAR/VARCHAR/TEXT 등의 BINARY 가 아닌 컬럼에 ASCII(32) 보다 작은 코드값의 문자가 있다면 4.1.3 으로 업그레이드 후 ALTER TABLE 이나 OPTIMIZE TABLE 을 사용하여 인덱스를 재구성하라. 또한 이런 경우 MyISAM 테이블도 재구성하거나 수정하여야 한다.

(*)5. 4.1.0 ~ 4.1.5 의 버전에서 UTF8 형식의 컬럼이나 다른 멀티바이트 글자셋 컬럼에 prefix index 를 사용하였다면 4.1.6 혹은 그 이상 버전으로 업그레이드 하기 위해서는 테이블을 재구성해야 한다.

(*)6. 4.1 이전 버전에서 DB명, 테이블명, 컬럼명 등에 액센트 문자(128 ~225 코드값) 를 사용하였다면 4.1 버전으로 곧장 업그레이드 할 수 없다. (4.1 버전은 메타데이타 저장에 UTF8 을 사용하기 때문에..) RENAME TABLE 을 사용하여 UTF8 에서 지원되는 테이블명,DB명,컬럼명으로 변경하라.

(*)7. CHAR(N) 은 N 개의 글자를 의미한다. 이전 버전에서는 N 바이트를 의미했다. 1바이트 글자셋에서는 문제가 없으나 멀티바이트 글자셋을 사용한다면 문제가 된다.

8. 4.1 에서 frm 파일의 포멧이 변경되었다. 4.0.11 이후의 버전은 새 형식을 사용할 수 있지만 그 이전 버전에서는 사용할 수 없다. 4.1 에서 그 이전 버전으로 테이블을 이전하려면 Dump & Restore 를 사용하라.

9. 4.1.1 이나 그 이상의 버전으로 업그레이드하면 4.0 이나 4.1.0 으로 다운그레이드 하는것은 어렵다.

이전 버전에서는 InnoDB 의 다중 테이블스페이스를 인식하지 못한다.

(*)10. 4.1.3 의 커넥션별 타임존 지원기능에서 타임존 시스템 변수명은 system_time_zone 으로 변경되었다.

11. 윈도우 서버는 --shared-memory 옵션을 사용하여 공유메모리를 사용한 로컬 클라이언트 접속을 지원한다. 하나의 윈도우 머신에서 다수의 서버를 운영한다면 각각의 서버에 --shared-memory-base-name 옵션을 사용하라.

12. 통계 UDF 함수 인터페이스가 조금 변경되었다. 이제 각각의 XXX() 통계함수에 xxx_clear() 함수를 선언해야 한다.


[Client Changes]

mysqldump 에 --opt 와 --quote-names 옵션이 디폴트로 활성화되었다. --skip-opt 와 --skip-quote-names 옵션으로 비활성화 할 수 있다.


[SQL Changes]

(*)1. 4.1.2 부터 SHOW TABLE STATUS 출력내용중 Type 이 Engine 으로 변경되었다.

(TYPE 옵션은 4.x 버전에선 계속 지원되지만 5.1 버전에서는 사라질것이다.)

(*)2. 문자 비교는 SQL 표준을 따른다. 비교전에 문자열 끝공백을 제거하는 대신에 짧은 문자열을 공백을 추가하여 늘리는 방식을 사용한다. 이와 관련된 문제는 'a' > 'a\t' 라는 것이다.(이전 버전에서는 'a' = 'a\t' 이었다.) 만약 ASCII(32) 보다 작은 코드값의 문자로 끝나는 CHAR 나 VARCHAR 컬럼이 있다면 REPAIR TABLE 이나 myisamchk 를 사용하여 수정하라.

3. multiple-table DELETE 를 사용할때 삭제하려는 테이블의 별칭(Alias) 를 사용해야 한다.

DELETE test FROM test AS t1, test2 WHERE ...

Do this:

DELETE t1 FROM test AS t1, test2 WHERE ...

이것은 4.0 버전에서 발생하던 문제를 수정하기 위함이다.

(*)4. TIMESTAMP 는 이제 'YYYY-MM-DD HH:MM:SS' 형식의 문자열로 리턴된다. (4.0.12 부터 --new 옵션이 이와같이 동작하도록 지원한다.)

만약 4.0 의 방식처럼 숫자로 리턴되길 원한다면 +0 를 붙여서 출력하라.

mysql> SELECT ts_col + 0 FROM tbl_name;

TIMESTAMP 컬럼의 길이는 더이상 지원하지 않는다. TIMESTAMP(10) 에서 (10) 은 무시된다.

이것은 SQL 표준 호환성을 위해 필요했다. 차기 버전에서는 하위호환을 가지도록 timestamp 의 길이가 초단위의 일부분을 출력하도록 할것이다.

(*)5. 0xFFDF 와 같은 이진값은 해당값의 문자로 간주된다. 이것은 문자를 이진값으로 입력할때 글자셋과 관련된 문제를 해결한다. 숫자값으로 사용하기 위해서는 CAST() 를 사용하라.

mysql> SELECT CAST(0xFEFF AS UNSIGNED INTEGER) < CAST(0xFF AS UNSIGNED INTEGER);
-> 0

CAST() 를 사용하지 않는다면 해당값의 문자에 대한 비교가 될것이다.

mysql> SELECT 0xFEFF < 0xFF;
-> 1

이진값을 숫자형식에 사용하거나 = 연산에 대해 사용할때도 위와 동일하다.(4.0.13 부터 --new 옵션으로 4.0 서버에서 이러한 동작을 반영해볼 수 있다.)

6. DATE, DATETIME, TIME 값을 다루는 함수를 위해 클라이언트에 리턴되는 값은 임시적인 형식으로 고정되었다. 가령 4.1 버전에서 다음과 같은 값을 리턴한다.

mysql> SELECT CAST('2001-1-1' AS DATETIME);
-> '2001-01-01 00:00:00'

4.0 에서는 결과형식이 다르다.

mysql> SELECT CAST('2001-1-1' AS DATETIME);
-> '2001-01-01'

7. AUTO_INCREMENT 컬럼에 DEFAULT 를 명시할 수 없다.(4.0 에서는 무시되었으나 4.1 에서는 에러를 발생한다.)

8. LIMIT 는 음수를 인자로 받지 않는다. (-1 대신에 큰 정수숫자를 사용하라.)

9. SERIALIZE 는 sql_mode 변수값을 위한 모드값이 아니다. 대신에 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 를 사용하라. 또한 SERIALIZE 는 --sql-mode 옵션의 유효한 값이 아니며

대신 --transaction-isolation=SERIALIZABLE 를 사용하라.


[C API Changes]

(*)1. 4.1.3 에서 mysql_shutdown() 함수의 인자(SHUTDOWN-level)가 추가되었다. 이전에 사용한 mysql_shutdown(X) 을 mysql_shutdown(X,SHUTDOWN_DEFAULT) 로 수정해야 한다.

2. mysql_real_query() 와 같은 몇몇 API 들이 에러발생시 -1 이 아닌 1 을 리턴한다. 만약 아래와 같은 코드를 사용하였다면 수정해야 한다.

if (mysql_real_query(mysql_object, query, query_length) == -1)
{
printf("Got error");
}

Non-Zero 값을 체크하도록 수정하라.

if (mysql_real_query(mysql_object, query, query_length) != 0)
{
printf("Got error");
}


[Password-Handling Changes]

- 보안을 강화하기 위해 패스워드 해시 방식이 변경되었다. 4.0 이나 그 이전의 라이브러리를 사용한 클라이언트를 사용시에 문제가 발생할 수 있다.(아직 4.1로 업그레이드 하지 않은 클라이언트가 리모트 접속을 시도할때 발생할 수 있다.) 다음 항목은 이 문제 해결에 대한 전략을 제공한다. 이것은 낡은 클라이언트와 보안성의 사이에서 타협안을 제시한다.

1. 클라이언트만 4.1 라이브러리를 사용하도록 업그레이드한다. (몇가지 API 의 리턴값을 제외하고) 어떤 변화도 필요하지 않지만 Server/Client 어느쪽에서도 4.1의 새로운 기능을 사용할 수 없을것이다.

2. 4.1로 업그레이드 후 mysql_fix_privilege_tables 스크립트를 실행하여 password 컬럼의 길이를 수정한다. 그러나 서버 시작시 --old-passwords 옵션을 사용하여 하위호환성을 유지한다. 그러다가 모든 클라이언트가 4.1로 업그레이드 하면 --old-passwords 옵션 사용을 중지할 수 있다. 또한 패스워드를 새 형식에 맞도록 수정할수도 있다.

3. 4.1로 업그레이드 후 mysql_fix_privilege_tables 스크립트를 실행하여 password 컬럼의 길이를 수정한다. 모든 클라이언트가 4.1로 업그레이드 되었다면 --old-passwords 옵션을 사용하지 않고 서버를 실행한다. 대신에 모든 계정에 대해 패스워드를 새 형식에 맞도록 수정한다.

4. Netware 환경에서 4.0 에서 4.1 로 업그레이드 할때 Perl 과 PHP 버전을 업그레이드 하라.


2006/09/08 10:46 2006/09/08 10:46
이 글에는 트랙백을 보낼 수 없습니다
Web_developing/Mysql  2006/09/08 10:45
출처 블로그 > badajoa2002님의 블로그
원본 http://blog.naver.com/badajoa2002/14377724

1.   트렌젝션이란 무엇인가? (What is transaction ?)

트렌젝션이란, 중단없이 시작에서부터 종료까지 한번에 수행되어야 하는 하나의 작업단위를 이야기한다. 수행이 끝난후에는 중간에 작업이 실패되었을 경우에는 작업 수행전의 상태로 그대로 돌아가야 한다.

이해를 돕기위해서 쉽게 예를 들어서 설명하도록 하자, A계좌에서 B계좌로 1,000원을 계좌 이체를 한다고 가정하자. 작업은 다음과 같은 순서로 이루어지게 된다.

1)       A계좌에서 1,000원을 인출한다.

2)       B 계좌에 1,000원을 더한다.

만약 위의 작업을 수행하던 도중 A계좌에서 1,000원이 인출된 후에, 은행 시스템의 오류로 인해서 B계좌에 1,000원이 더해지지 않는다면, 중간에 1,000원이라는 돈은 공중에서 증발해 버린것이 된다. 이럴때는 다시 계좌이체를 수행하기 이전의 상태로 되돌려서 A계좌에로부터 1,000원을 인출하지 말아야 한다.

그래서 위의 1),2) 작업은 한꺼번에 이루어져야 한다. 계좌이체 작업과 같이 한번에 이루어져야 하는 작업을 트렌젝션이라고 부른다.

이처럼 트렌젝션은 쇼핑몰의 주문 결제나,예매와 같이 Mission Critical 작업 있어서 필수적인 개념이라고 있다.

2.  트렌젝션의 기본속성 ACID (Transaction attribute “ACID” )

트렌젝션은 크게 4가지 특성을 가지는데 Atomicity,Consistency,Isolation,Durability, 네가지를 줄여서 ACID라고 부른다.

그럼 이제 부터 ACID속성 각각에 대해서 상세하게 알아보도록 하자.

Atomicity (원자성)

Database modifications must follow an all or nothing.

원자성이란, 하나의 트렌젝션이 하나의 단위로만 처리가 되어야 한다는것이다. 하나의 트렌젝션안에 여러가지 step 트렌젝션이, 하나로 처리가 되어야한다. 위의 계좌 이체처럼, 계좌에서 돈을 빼고, 돈을 다른 계좌에 넣는 것과 같이 두개이상의 step으로 구성되어 있더라도, 계좌 이체라는 하나의 트렌젝션으로 처리가 된다.

그래서, 어느 step에서라도 트렌젝션이 실패가 되었을 경우에는 모든 상태가 트렌젝션 상태 전으로 rolled back되서, 이전 상태를 유지해야 한다.

트렌젝션의 원자성은 트렌젝션이 완전히 수행되거나, 아무것도 수행되지 않은 All or Nothing 이미를 가지게 된다.

Consistency (일관성)

states that only valid data will be written to the database

트렌젝션이 종료된후에 저장되는 데이타는 오류없는 데이타만 저장되어야 한다.

다시 풀어서 이야기하자면 계좌이체 과정에서, 인출은 되었는데, 다른 계좌로 돈이 안넘어갔다던지, 트렌젝션이 끝난후에, 잘못된 데이타 값으로 변경되었던지, 데이타베이스 constraint 깨졌던지 했을때, Consistency 잘못되었다고 이야기하고, 이런경우에 트렌젝션 내용을 저장하지 말고, 이전 상태로rollback되어야 한다.

Isolation (격리성)

Multiple transactions occurring at the same time not impact each other execution

격리성이란, 트렌젝션중에 의해서 변경된 내용이 트렌젝션이 완료되기전까지는 다른 트렌젝션에 영향을 주어서는 안된다는 이야기이다.

Tx A라는 트렌젝션 수행중 EMP 테이블의 값을 변경했을때, Tx A 완료되지 않은 상태에서 Tx B EMP 테이블의 값을 참고할 경우에, Tx A 의해 변경된 값을 참고하는것이 아니라(아직 TxA 완료되지 않았기 때문에) 기존의 값을 참고하게 해야한다.

Durability (지속성)

Ensures that any transaction committed to the database will not be lost.

지속성이랑, 트렌젝션이 완료된후에의 값이 영구저장소에 제대로 기록이 되어야한다는 의미이다. 트렌젝션이 완료되었는데, 디스크 IO에러,네트워크 등으로 값이 제대로 기록이되지 않거나 해서는 안된다는 이야기다.

2006/09/08 10:45 2006/09/08 10:45
이 글에는 트랙백을 보낼 수 없습니다
Web_developing/Mysql  2006/09/08 10:44
숫자 관련 함수
ABS(숫자) : 절대값 출력.
   select abs(123);
CEILING(숫자) : 값보다 큰 정수 중 가장 작은 수.
  --양수일 경우는 소숫점 자리에서 무조건 반올림(4.0과 같은 소숫점 자리 0 값은 제외)
  --음수일 경우는 소숫점 자리를 무조건 버림
   select ceiling(4.0);
   select ceiling(4.1);
   select ceiling(4.9);
FLOOR(숫자) : 값보다 작은 정수 중 가장 큰 수[실수를 무조건 버림(음수일 경우는 제외)].
  --음수일 경우는 [.0/.00/.000/...] 을 제외하고 무조건 소숫점을 버리고 반내림(?)
   select floor(4.0);
   select floor(4.1);
   select floor(4.9);
   select floor(-4.6789);
ROUND(숫자,자릿수) : 숫자를 소수점 이하 자릿수에서 반올림.(자릿수는 양수,0,음수를 갖을 수 있다.)
   --자릿수를 생략하면 소숫점이 5 이상일 때 반올림/자릿수를 지정하면 지정한 자리수에서 반올림
   select round(4.5);
   select round(4.55);
   select round(-4.5);
   select round(4.556);
   select round(4.556,0);
   select round(4.556,1);
   select round(4.556,2);
   select round(45.556,-1);
   select round(455.556,-2);
TRUNCATE(숫자,자릿수) : 숫자를 소수점 이하 자릿수에서 버림.
  ==>만일 자릿수를 소숫점 이전으로 정하면 소숫점이하는 버리고 나머지 값은 0 값으로 처리
     / 예) truncate(9999,-3) --> 9000
  ==>또는 자릿수를 소숫점이하로 정하며, 해당숫자가 자릿수보다 소숫점이 모자랄경우 0 값으로 대치
     / 예) truncate(999,3) --> 999.000
  --반드시 자릿수를 명시해주어야 한다
  --음수일 경우는 해당자릿수에서 소숫점을 버리면서 무조건 반올림
  ==>(자릿수 숫자에서 이후 숫자가 0 일 경우는 제외 / 예)-4.0,0/-400,-2/-4.1230,4)
  ==>음수 역시 자릿수를 소숫점이하로 정하며, 해당숫자가 자릿수보다 소숫점이 모자랄경우 0 값으로 대치
  ==>또한 자릿수를 소숫점 이전으로 정하면 소숫점이하는 버리고 나머지 값은 역시 0 값으로 처리
POW(X,Y) 또는 POWER(X,Y) : XY
  --소숫점이 있는 경우도 실행, 단 음수는 양수로 승처리
  select pow(-2.5,2);
  select pow(1.5,2);
MOD (분자, 분모) : 분자를 분모로 나눈 나머지를 구한다.(연산자 %와 같음)
  select mod(12,5);    ==> 2
  select 12%5;           ==> 2
GREATEST(숫자1,숫자2,숫자3...) : 주어진 수 중 제일 큰 수 리턴.
  select greatest(100,101,90);
LEAST(숫자1,숫자2,숫자3...) : 주어진 수 중 제일 작은 수 리턴.
  select least(100,101,90);
INTERVAL(a,b,c,d.....) : a(숫자)의 위치 반환
  --두 번째 이후는 오름차순 정렬이 되어야 함
  예) INTERVAL(5,2,4,6,8) ==> 2
       5는 4와 6사이에 존재, 4~6사이의 위치가 앞에서 2번째
  select interval(4,1,2,3,5,6);
문자 관련 함수
ASCII(문자) : 문자의 아스키 코드값 리턴.
  SELECT ASCII('문자');
  select ascii('A');
CONCAT('문자열1','문자열2','문자열3'...) : 문자열들을 이어준다.
  select concat('ASP,','PHP,','SQL',' WEB STUDY');
INSERT('문자열','시작위치','길이','새로운문자열') : 문자열의 시작위치부터 길이만큼 새로운 문자열로 대치
  '시작위치' 와 '길이'는 문자열이 아니므로 작은따옴표로 굳이 묶어주지 않아도 된다.
  select insert('MySql web study','7','3','offline');
  select insert('MySql web study',7,3,'offline');
REPLACE('문자열','기존문자열','바뀔문자열') : 문자열 중 기존문자열을 바뀔 문자열로 바꾼다.
  select replace('MySql web study','web','offline');
INSTR('문자열','찾는문자열') : 문자열 중 찾는 문자열의 위치값을 출력
  --값이 존재하지 않으면 0값 리턴
  select instr('MySql web study','s');
  select instr('MySql web study','S');
LEFT('문자열',개수) : 문자열 중 왼쪽에서 개수만큼을 추출.
  select left('MySql web study',5);
  select left('MySql web study','5');
RIGHT('문자열',개수) : 문자열 중 오른쪽에서 개수만큼을 추출.
  select right('MySql web study',5);
  select right('MySql web study','5');
MID('문자열',시작위치,개수) : 문자열 중 시작위치부터 개수만큼 출력
  select mid('MySql web study',7,3);
  select mid('MySql web study','7','3');
SUBSTRING('문자열',시작위치,개수) : 문자열 중 시작위치부터 개수만큼 출력
  select substring('Mysql web study',11,5);
  select substring('Mysql web study','11','5');
LTRIM('문자열') : 문자열 중 왼쪽의 공백을 없앤다.
  select ltrim('          web study');
RTRIM('문자열') : 문자열 중 오른쪽의 공백을 없앤다.
  select rtrim('web study          ');
TRIM('문자열') : 양쪽 모두의 공백을 없앤다.
  select trim('     web study      ');
LCASE('문자열') 또는 LOWER('문자열') : 소문자로 바꾼다.
  select lcase('MYSQL');
  select lower('MySQL');
UCASE('문자열') 또는 UPPER('문자열') : 대문자로 바꾼다.
  select ucase('mySql');
  select upper('mysql');
REVERSE('문자열') : 문자열을 반대로 나열한다.
  예) REVERSE('abcde') ==> edcba
  select reverse('lqSyM');
논리 관련 함수, 집계함수
--논리 관련 함수
IF(논리식,참일 때 값,거짓일 때 값)
  논리식이 참이면 참일 때 값을 출력하고 논리식이 거짓이면 거짓일 때 출력한다.
IFNULL(값1,값2)
값1이 NULL 이면 값2로 대치하고 그렇지 않으면 값1을 출력

--집계 함수
COUNT(필드명)
  NULL 값이 아닌 레코드 수를 구한다.
SUM(필드명)
  필드명의 합계를 구한다.
AVG(필드명)
  각각의 그룹 안에서 필드명의 평균값을 구한다.
MAX(필드명)
  최대값을 구한다.
MIN(필드명)
  최소값을 구한다.
날짜 관련 함수
NOW() 또는 SYSDATE() 또는 CURRENT_TIMESTAMP()
  현재 날짜와 시간 출력
  ※ 함수의 상황이 숫자인지 문자열인지에 따라
     YYYYMMDDHHMMSS 또는
     'YYYY-MM-DD HH:MM:SS' 형식으로 반환한다.
  예)
  select now();
  ==> '2001-05-07 09:10:10'
  select now() + 0;
  ==> 20010507091010
CURDATE() 또는 CURRENT_DATE()
  현재 날짜 출력
  ※ 함수의 상황이 숫자인지 문자열인지에 따라
     YYYYMMDD 또는
     'YYYY-MM-DD 형식으로 반환한다.
  예)
  select curdate();
  ==> '2001-05-07'
  select curdate() + 0;
  ==> 20010507
CURTIME() 또는 CURRENT_TIME()
  현재 시간 출력
  ※ 함수의 상황이 숫자인지 문자열인지에 따라
  HHMMSS 또는 'HH:MM:SS' 형식으로 반환한다.
  예)
  select curtime();
  ==> '09:10:10'
  select curtime() + 0;
  ==> 091010
DATE_ADD(날짜,INTERVAL 기준값)
  날짜에서 기준값 만큼 더한다.
※ 기준값 : YEAR, MONTH, DAY, HOUR, MINUTE, SECOND
  예)
  select date_add(now(), interval 2 day);
  ==> 오늘보다 2일 후의 날짜와 시간 출력.
  select date_add(curdate(), interval 2 day);
  ==> 오늘보다 2일 후의 날짜 출력.
DATE_SUB(날짜,INTERVAL 기준값)
  날짜에서 기준값 만큼 뺸다.
※ 기준값 : YEAR, MONTH, DAY, HOUR, MINUTE, SECOND
  select date_sub(now(),interval 2 day);
  ==> 오늘보다 2일 전의 날짜와 시간 출력.
  select date_sub(curdate(), interval 2 day);
  ==> 오늘보다 2일 전의 날짜 출력.
YEAR(날짜) : 날짜의 연도 출력.
  select year('20000101');
  select year(20000101);
  select year('2000-01-01');
  select year(now());
  select year(curdate());
  select year(date_add(now(),interval 2 year));
  select year(date_sub(curdate(),interval 2 year));

MONTH(날짜) : 날짜의 월 출력.
  select month('20001231');
  select month(20001231);
  select month('2000-12-31');
  select month(now());
  select month(curdate());
  select month(date_add(now(),interval 2 month));
  select month(date_sub(curdate(),interval 2 month));

MONTHNAME(날짜) : 날짜의 월을 영어로 출력.
  select monthname(20021221);
  select monthname('20000721');
  select monthname('2000-08-10');
  select monthname(now());
  select monthname(curdate());
  select monthname(date_add(now(),interval 17 month));
  select monthname(date_sub(curdate(),interval 11 month));

DAYNAME(날짜) : 날짜의 요일일 영어로 출력.
  select dayname(20000121);
  select dayname('20010123');
  select dayname('2001-06-22');
  select dayname(now());
  select dayname(curdate());
  select dayname(date_add(now(),interval 21 day));
  select dayname(date_sub(curdate(),interval 333 day));

DAYOFMONTH(날짜) : 날짜의 월별 일자 출력.
  select dayofmonth(20030112);
  select dayofmonth('20011231');
  select dayofmonth('2001-12-23');
  select dayofmonth(now());
  select dayofmonth(curdate());
  select dayofmonth(date_add(now(),interval 56 day));
  select dayofmonth(date_sub(curdate(),interval 33 day));

DAYOFWEEK(날짜) : 날짜의 주별 일자 출력(월요일(0),화요일(1)...일요일(6))
  select dayofweek(20011209);
  select dayofweek('20001212');
  select dayofweek('2003-03-21');
  select dayofweek(now());
  select dayofweek(curdate());
  select dayofweek(date_add(now(),interval 23 day));
  select dayofweek(date_sub(curdate(),interval 31 day));

WEEKDAY(날짜) : 날짜의 주별 일자 출력(월요일(0),화요일(1)...일요일(6))
  select weekday(20000101);
  select weekday('20030223');
  select weekday('2002-10-26');
  select weekday(now());
  select weekday(curdate());
  select weekday(date_add(now(),interval 23 day));
  select weekday(date_sub(curdate(),interval 33 day));

DAYOFYEAR(날짜) : 일년을 기준으로 한 날짜까지의 날 수.
  select dayofyear(20020724);
  select dayofyear('20001231');
  select dayofyear('2002-01-01');
  select dayofyear(now());
  select dayofyear(curdate());
  select dayofyear(date_add(curdate(),interval 44 year));
  select dayofyear(date_sub(now(),interval 25 month));
  select dayofyear(date_add(now(),interval 55 day));
  select dayofyear(date_sub(curdate(),interval 777 hour));
  select dayofyear(date_add(now(),interval 999999 minute));

WEEK(날짜) : 일년 중 몇 번쨰 주.
  select week(now());
  select week(date_sub(curdate(),interval 12 month));

FROM_DAYS(날 수)
  --00년 00월 00일부터 날 수 만큼 경과한 날의 날짜 출력.
     ※ 날 수는 366 이상을 입력 그 이하는 무조건 '0000-00-00' 으로 출력.
  --또한 9999-12-31 [from_days(3652424)] 까지의 날짜가 출력가능 하다고는 하나
     정확히 말하면 0000-03-15 [from_days(3652499)] 까지의 날짜가 출력가능함.
  --따라서 날 수는 366 이상 3652424[3652499] 이하가 되어야 한다.
  select from_days(3652424);
  select from_days('3652499');

TO_DAYS(날짜)
  --00 년 00 월 00일 부터 날짜까지의 일자 수 출력.
  --from_days와 비교해 볼 때 정확한 날짜범위는 3652424 일 수 까지임을 알 수 있다.
  select to_days('99991231');
  select to_days('0000-03-15');
  응용 예제1) 자신이 살아 온 날수
  select to_days(now()) - to_days('본인생일자');
  select to_days(now()) - to_days('1970-10-10');
  응용 예제2) 살아 온 날수를 이용하여 자신의 나이를 만으로 구하기
  select (to_days(now())-to_days('1970-10-10'))/365;
  select floor((to_days(now())-to_days('19701010'))/365);

DATE_FORMAT(날짜,'형식') : 날짜를 형식에 맞게 출력
DATE타입구분기호설명구분기호설명
년도%Y4자리 연도%y2자리 년도
%M
%b
긴 월 이름 (January, ...)
짧은 월 이름(Jan, ...)
%m
%c
숫자의 월 (01...12)
숫자의 월 (1...12)
요일%W긴 요일 이름 (Sunday, ...)%a짧은 요일 이름 (Sun, ...)
%D
%w
월 내에서 서수 형식의 일(1th, ...)
숫자의 요일 (0=Sunday, ...)
%d
%e
%j
월 내의 일자 (01...31)
월 내의 일자 (1...31)
일년 중의 날수 (001...366)
%l
%h
%I
12시간제의 시 (1...12)
12시간제의 시 (01...12)
12시간제의 시 (01...12)
%k
%H
12시간제의 시 (0...23)
12시간제의 시 (00...23)
%i숫자의 분 (00...59)
%S숫자의 초 (00...59)%s숫자의 초 (00...59)
시간%r12시간제의 시간 (hh:mm:ss AM 또는 PM)%T24시간제의 시간 (hh:mm:ss)
%U일요일을 기준으로 한 주 (0...52)%u월요일을 기준으로 한 주 (0...52)
기타%%문자 '%'%pAM 또는 PM

  ☞ 예)
  select date_format(now(),'%Y:%M:%p');
  ==> 2001:May:PM

▶ DATABASE() : 현재의 데이터베이스 이름을 출력한다.

▶ PASSWORD('문자열')
: 문자열을 암호화한다.

▶ FORMAT(숫자,소수이하자리수) : 숫자를 #,###,###.## 형식으로 출력
  --임의의 소수점자릿수를 생성한다./소숫점을 필요한 만큼 취한다.
  --소숫점을 만들어 같은 길이로 한다음 동일하게 프로그램에서 불러와서 소숫점을 버리고
     필요한 곳에 출력하는 등에 응용할 수 있다.
  select format(123,5);
  select format(123.12345600123,9);
  select format(123.123,-3);
  ※ 소숫점이하자리수가 0 이나 음수값은 해당이 안됨
2006/09/08 10:44 2006/09/08 10:44
이 글에는 트랙백을 보낼 수 없습니다
웅쓰:웅자의 상상플러스
웅자의 상상플러스
전체 (379)
게임 (5)
영화 (2)
기타 (23)
맛집 (5)
영어 (2)
대수학 (3)
형태소 (5)
Hacking (9)
Linux (112)
HTML (48)
Application_developing (48)
Web_developing (102)
Window (11)
«   2024/11   »
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
  1. 2016/01 (1)
  2. 2015/12 (3)
  3. 2015/10 (3)
  4. 2015/03 (2)
  5. 2015/01 (4)