해당 라인의 처음으로 커서이동 : ctrl + a
해당 라인의 끝으로 커서이동 : ctrl + e


by 뭔일이여 2013. 3. 9. 02:30

테이블별 컬럼의 모든 정보보기

링크 - http://dev.mysql.com/doc/refman/5.0/en/show-columns.html

SHOW [FULL] COLUMNS {FROM | IN} tbl_name [{FROM | IN} db_name]
    [LIKE 'pattern' | WHERE expr]



by 뭔일이여 2012. 8. 20. 17:33

준비

안드로이드 SDK 와 Chrome브라우저가 PC에 설치되어있어야함.

- 모바일에도 Chrome브라우저가 설치돼있어야함(아이스크림 샌드위치에만 지원됨)


시작

1. 모바일에서 크롬브라우저를 실행하고 메뉴버튼 클릭해서 설정-개발자도구에서 USB웹 디버깅 사용에 체크

2. 시작-실행을 클릭해 cmd창을 열고 안드로이드 SDK가 설치된 경로로 가서 platform-tools 폴더로 들어간다.  그 후 다음 명령어를 실행한다.

adb forward tcp:9222 localabstract:chrome_devtools_remote

3. 데스크탑에서 크롬브라우저를 실행하고 주소창에 localhost:9222 를 입력한다. 그러면 모바일 크롬에서 떠있는 창이 썸네일이미지처럼 나오는데 그걸 클릭하면 크롬 개발자도구와 똑같은 웹페이지가 실행된다.

4. 디버깅 시작~


출처 - https://developers.google.com/chrome/mobile/docs/debugging?hl=ko-KR

by 뭔일이여 2012. 4. 18. 11:56

환경 - phonegap, jquery mobile, code igniter

phonegap에서 외부페이지(http://~)를 초기에 로드하도록 설정하고 해당 페이지의 링크를 클릭했을때

주소 끝에 / 가 들어가는 경우 prompt창이 뜨고 이동이 안되는 현상 발생

간단히 초기 로드할 주소의 끝부분에 / 를 없애면 해당현상 해결


by 뭔일이여 2012. 4. 3. 14:17
개요
모바일웹을 개발하면서 첨부파일 다운로드를 php의 header로 처리
모든기기에서 테스트하진 않았지만 안드로이드와 아이폰(팟)에서 테스트해본결과
아이폰계열에서는 이미지를 바로 보여준 후 오류가 발생
확인결과 header설정에서 Content-Disposition: attachment 일경우에 발생

증상
아이폰계얼에서 첨부파일 클릭 시 다운로드되지 않고 바로 보여주는데 이미지의 경우
브라우저에서 바로 보여주는 방식으로 처리됨
이미지를 보고난 후 뒤로가기를 눌러서 웹페이지로 이동하면 javascript에러가 발생
ajax통신 등 크로스도메인에서 주로 발생하는 SECURITY_ERR: DOM Exception 18 에러 발생
이 에러가 발생하면 브라우저를 닫고 다시 열기전까지는 계속 오류 발생

해결
첨부파일 다운로드 시 아이폰계열이고 이미지형식일 경우 header의 Content-Disposition 에
attachment 대신 inline 을 입력해주면 아이폰에서도 첨부파일이 보여진 후 에러발생하지 않음
이 방법으로 해결은 했지만 다른이유로 인해 SECURITY_~ 에러가 발생한다면 처리불가

by 뭔일이여 2012. 3. 22. 15:55
스타일에서 클래스를 지정해서 사용할때 앞쪽 대상뒤의 클래스를 입력할 때 공백이 있을 경우와 없을경우의 차이가 있다.
공백이 있을경우는 해당 대상의 하위객체에 해당 클래스가 있으면 해당 스타일을 적용하라는 뜻이다.

<style type="text/css">
<!--
div .aa {
color: #ddd;
}
-->
</style>
<div class="aa">
no style
<span class="aa">color : #ddd</span>
</div>

위와같이 div 뒤에 공백이 있고 그 뒤에 .aa 라고 클래스를 지정했을 경우는 div 안에서 다른 태그에 aa라는
클래스를 지정했을 때만 컬러가 적용된다. 그래서 'no style' 텍스트는 aa 스타일이 적용되지 않고 보여진다.

하지만 스타일을 정의할때 div.aa 라고  적용을 했다면 'no style' 텍스트에도 스타일이 적용될것이다.
즉 div태그에 aa클래스가 선언되어있으면 해당 태그 하위 모든 텍스트에 똑같이 스타일을 적용한다는 뜻이다.


by 뭔일이여 2011. 11. 1. 10:28
by 뭔일이여 2011. 4. 28. 10:46

출처 :: http://blog.naearu.com/2982717/trackback/

 

- ASCII(str) : 해당 인저의 아스키 값을 반환한다. 문자열이 한글자 이상일 경우는 첫번째 문자에 해당하는 아스키 값을 반환한다.  문자열에 대해서는 0, NULL 에 대해서는 NULL 을 반환한다.
 : select ASCII('2');

- CONCAT(X,Y,...) : 해당 인자들을 연결한 
문자열을 반환한다. 인자중 하나가 NULL 일 경우는 NULL 을 반환한다.
 : select CONCAT('My', 'S', 'QL');

- LENGTH(str) : 문자열의 
길이를 반환한다.
- 예 : select LENGTH('text');

- OCTET_LENGTH(str) : 
LENGTH(str) 와 동일하다.

- CHARACTER_LENGTH(str) : LENGTH(str) 와 동일하다.

- LOCATE(substr,str) : 첫번째 인자에서 두번째 인자가 있는 위치를 반환한다. 없을경우 0 을 반환한다.
- 예 : select LOCATE('bar', 'foobarbar');

POSITION(substr IN str) : LOCATE(substr,str) 와 동일하다.

- LOCATE(substr,str,pos) : 
두번째 인자에서 세번째 인자의 자리수부터 검색을 하여 첫번째 인자가 발견되는 위치를 반환한다. 
- 예 : select LOCATE('bar', 'foobarbar',5);

- INSTR(str,substr) : 
LOCATE(substr,str) 와 동일한 기능을 하며, 차이점은 첫번째 인자와 두번째 인자가 바뀐것 뿐이다. 
- 예 : select INSTR('foobarbar', 'bar');

- LPAD(str,len,padstr) : 
첫번째 인자를 두번째 인자만큼의 길이로 변환한 문자열을 반환한다. 모자란 공간은 왼쪽에 세번째 인자로 채운다.
- 예 : select LPAD('hi',4,' ');

RPAD(str,len,padstr) : LPAD 와 반대로 오른쪽에 빈공간을 채운다.
- 예 : 
select RPAD('hi',5,'?');

- LEFT(str,len) : 첫번째 문자열에서 두번째 길이만큼만을 반환한다.
- 예 : select LEFT('foobarbar', 5);

- RIGHT(str,len) : LEFT(str,len) 
 동일하다. 차이점은 해당 길이만큼 오른쪽에서부터 반환한다.
- 예 : select 
RIGHT('foobarbar', 4);
select SUBSTRING('foobarbar' FROM 4);

- SUBSTRING(str,pos,len) : 첫번째 인자의 문자열에서 두번째 인자의 위치부터 세번째 인자의 길이만큼 반환한다.
- 예 : select 
SUBSTRING('Quadratically',5,6); 

- SUBSTRING(str FROM pos FOR len) : SUBSTRING(str,pos,len) 과 
동일하다. 

- MID(str,pos,len) : SUBSTRING(str,pos,len) 과 동일하다.

- SUBSTRING(str,pos) 
: 첫번째 인자의 문자열에서 두번째 인자로부터의 모든 문자열을 반환한다.
- 예 
: select SUBSTRING('Quadratically',5);

- SUBSTRING(str FROM pos) : SUBSTRING(str,pos) 와 
동일하다. 

- SUBSTRING_INDEX(str,delim,count) : 첫번째 인자인 문자열을 두번째 문자로 구분하여 
세번째 인자 수의 위치만큼 반환한다. 예를들어 select SUBSTRING_INDEX('www.mysql.com', '.', 2) 은 'www.mysql' 을 반환한다. 세번째 인자가 음수일경우는 반대로 오른쪽에서부터 검색하여 결과를 반환한다.
- 예 : select SUBSTRING_INDEX('www.mysql.com', '.', -2);

- LTRIM(str) : 
왼쪽에 있는 공백문자를 제거한 문자열을 반환한다.
- 예 : select LTRIM(' 
barbar'); 

- RTRIM(str) : 오른쪽에 있는 공백문자를 제거한 문자열을 반환한다.
- 예 : select RTRIM('barbar ');

- TRIM([[BOTH | LEADING 
| TRAILING] [remstr] FROM] str)
- 예 : select TRIM(' bar 
'); 
select TRIM(LEADING 'x' FROM 'xxxbarxxx');
select TRIM(BOTH 'x' FROM 'xxxbarxxx');
select TRIM(TRAILING 'xyz' FROM 'barxxyz');

- REPLACE(str,from_str,to_str) : 문자열은 치환한다.
- 예 : select REPLACE('www.mysql.com', 'www', 'ftp');

- REVERSE(str) : 
문자열을 뒤집는다. 예를들어, select REVERSE('abc') 은 'cba' 를 반환한다.

LCASE(str) : 문자열을 소문자로 변환한다.
- 예 : select LCASE('QUADRATICALLY');

- LOWER(str) : LCASE(str) 와 동일하다.

- UCASE(str) : 문자열을 
대문자로 변환한다.
- 예 : select UCASE('Hej');

- UPPER(str) : 
UCASE(str) 와 동일하다.

by 뭔일이여 2010. 9. 28. 10:14
VI에서 파일 인코딩을 변환하여 저장하거나 불러오려면 다음의 명령을 이용한다.

인코딩을 변환하여 불러오기.
:e ++enc=euc-kr

그리고 아래 명령으로 인코딩을 변환한 다음 저장한다.
:set fileencoding=utf-8

리눅스에서 파일의 인코딩을 확인하려면 file 명령어를 이용할 수 있다.
사용자 삽입 이미지











file 명령어에서 나타나는 내용은 /etc/magic 에 정의되어 있는 메타 정보를 이용한다.

by 뭔일이여 2010. 9. 17. 10:25

function xml2array($xml_obj) {
$sxi = new SimpleXmlIterator($xml_obj); // read from xml string
//$sxi = new SimpleXmlIterator($xml_obj, null, true); // read from filename
return sxiToArray($sxi);
}

function sxiToArray($sxi) {
$a = array();
for( $sxi->rewind(); $sxi->valid(); $sxi->next() ) {
if(!array_key_exists($sxi->key(), $a)) {
$a[$sxi->key()] = array();
} else if(!isset($a[$sxi->key()][0])) {
$exists_value = $a[$sxi->key()];
$a[$sxi->key()] = array();
$a[$sxi->key()][] = $exists_value;
}

if($sxi->hasChildren()) {
if(isset($a[$sxi->key()][0])) {
$a[$sxi->key()][] = sxiToArray($sxi->current());
} else {
$a[$sxi->key()] = sxiToArray($sxi->current());
}
} else {
if(isset($a[$sxi->key()][0])) {
$a[$sxi->key()][] = strval($sxi->current());
} else {
$a[$sxi->key()] = strval($sxi->current());
}
}
}
return $a;
}

사용상 편의를 위해 약간 수정했음

by 뭔일이여 2010. 7. 22. 10:37
사이트 제작 중 쿠키로 세션을 체크하는데 새로고침을 하면 계속 세션이 풀리는 현상이 발생했다.
크롬과 사파리에서만...
참고로 이 사이트는 codeigniter를 사용해서 제작했다.
그리고 http://도메인/그룹아이디 로 접속을 해서 그룹아이디를 쿠키로 굽고 그 쿠키를 가지고 로그인체크를 하는 구조를 가지고 있었다.

원인을 찾아보다 쿠키값을 찍어보니 favicon.ico라는 값이 찍히면서 쿠키값이 변경되는것이었다.
왜 저 값이 찍히는지 찾아보는데 아무리 소스를 들여봐도 해당 단어는 없었다.
그러다 codeigniter로 작성했다는걸 생각하면서 혹시 http://도메인/favicon.ico라는 접속이 이뤄지는것이 아닐까 라는 생각을 하게 되었다.
그래서 소스에서 저런 접속이 있으면 끝내도록 수정을 하니 이 문제가 사라졌다.
확인은 해봐야겠지만 원인은 밝혀졌다.

크롬과 사파리에서는 새로고침 시 
http://도메인/favicon.ico 에 접속을 해서 파비콘을 확인하는것이었다.

크롬과 사파리에서 파비콘을 확인하면서 접속했을때 favicon.ico를 그룹아이디로 인식하게 만들어버리기 때문이다.
이는 codeigniter를 사용하면서 서버에서 rewrite모듈을 사용했기때문이다.
즉 특수한 경우에 발생하는 현상인 것이다.

by 뭔일이여 2009. 6. 30. 17:53
정수 변경하기
10 나누기 2 는 5 나머지 0
5 나누기 2 는 2 나머지 1
2 나누기 2 는 1 나머지 0
1 나누기 2 는 0 나머지 1

제일 마지막에 나온 나머지 부터 위로 순서대로 나열 -> 1010

소수점 아래 수 변경하기
0.35 곱하기 2 는 0.7, 0.7 에서 정수 부분 0 을 뺌
0.7 곱하기 2 는 1.4, 1.4 에서 정수부분 1 을 뺌
0.4 곱하기 2 는 0.8, 0.8 에서 정수부분 0 을 뺌
0.8 곱하기 2 는 1.6, 1.6 에서 정수부분 1 을 뺌
0.6 곱하기 2 는 1.2, 1.2 에서 정수부분 1 을 뺌
0.2 곱하기 2 는 0.4, 0.4 에서 정수부분 0 을 뺌
0.4 곱하기 2 는 0.8, 0.8 에서 정수부분 0 을 뺌
0.8 곱하기 2 는 1.6, 1.6 에서 정수부분 1 을 뺌
0.6 곱하기 2 는 1.2, 1.2 에서 정수부분 1 을 뺌
0.2 곱하기 2 는 0.4, 0.4 에서 정수부분 0 을 뺌
0.4 곱하기 2 는 0.8, 0.8 에서 정수부분 0 을 뺌
0.8 곱하기 2 는 1.6, 1.6 에서 정수부분 1 을 뺌
................................
이후는 무한반복(2를 곱해서 나온수가 정수 1일경우 1을 뱉어내고 거기서 끝)
제일 위쪽부터 뺀 정수를 순서대로 나열 -> 0.010110011001100.....

소수점아래의 수는 이진수로 완벽하게 변경되지 않음

십진수 11.75 를 이진수로 변환
정수 변환
11 ÷ 2 = 5 나머지 1
5 ÷ 2 = 2 나머지 1
2 ÷ 2 = 1 나머지 0
1 ÷ 2 = 0 나머지 1
결과 : 1011(2진) = 11(10진)

소수점 아래 변환
0.75 × 2 = 1.50 => 1
0.50 × 2 = 1.00 => 1
결과 : 0.11(2진) => 0.75(10진)

11.75(10진) = 1011.11(2진)
by 뭔일이여 2009. 5. 13. 11:02

<?php
$string = floatVal(3300);
$float = 3000 * 1.1;
if($string === $float) {
    echo 'String '.$string.' 은 Float '.$float.' 와 같다';
} else {
    echo 'String '.$string.' 은 Float '.$float.' 와 다르다';
}
echo '<br />';
var_dump($string);
echo '<br />';
var_dump($float);
exit();
?>
////////////////결과값////////////////////
String 3300 은 Float 3300 와 다르다
float(3300)
float(3300)
///////////////////////////////////////////

<?php
$string = floatVal(5500);
$float = 5000 * 1.1;
if($string === $float) {
    echo 'String '.$string.' 은 Float '.$float.' 와 같다';
} else {
    echo 'String '.$string.' 은 Float '.$float.' 와 다르다';
}
echo '<br />';
var_dump($string);
echo '<br />';
var_dump($float);
exit();
?>
////////////////결과값////////////////////
String 5500 은 Float 5500 와 같다
float(5500)
float(5500)
///////////////////////////////////////////


위와같이 1.1에 3000을 곱하면 결과값은 같지만 비교연산을 해보면 다르다고 값이 나온다.
여러가지 방법으로 알아보니 이진연산을 하는 컴퓨터 프로그래밍이라서 그런것이라고 한다.
십진수의 소수점 아래 수는 완벽하게 이진수로 변경되지 않는다.
1.1을 이진수로 변환하면 1.000100010001... 이처럼 0001 이 반복된다.
그래서 곱하기를 하면 보이지는 않지만 미묘하게 다른 값이 나오는것이다.
근데 왜 3000을 곱하면 다르고 5000은 같을까? 제길...

꼼수로 해결을 하자면 소수점 자리만큼 10의 제곱을 곱한 후 계산하고 다시 곱한 수로 나누는 방법이 있다.
by 뭔일이여 2009. 5. 12. 17:28

# 항목앞에 (*) 는 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 버전을 업그레이드 하라.

출처 - 데이터베이스 사랑넷

by 뭔일이여 2007. 4. 18. 10:30
mySQL manual 한글번역(260k) (1999/01/07) Mysql

2007/02/21 11:01

http://blog.naver.com/pusankjs/40034629677

## 원본 : mysql 3.21 Reference Manual PostScript 매뉴얼
(현재 최신 매뉴얼은 3.22 레퍼런스 매뉴얼이며 3.22.14b-gamma입니다.)

5, 6, 9, 10, 11, 12, 13, 15, 17, 18장 번역 : 문태준(taejun@hitel.net)
18장 중 C-API 부분 번역 : 권용찬 (golmong@cre.co.kr)


이메일 : taejun@hitel.net, taejun@taejun.pe.kr
웹 : http://taejun.pe.kr (Mysql 관련 자료가 모아져 있습니다)

자료를 공유하기 편하도록 홈페이지를 열었습니다.
많이 애용해주시면 감사~하겠습니다.


개인적인 질문은 각 통신망의 리눅스 동호회나 인터넷을 참고하세요.

**로 묶인 것은 제가 주를 단 것입니다.

설치와 관련된 부분은 kldp.org의 database 항목에서 관련된 정보가 있으므로 참고하시면 됩니다.



0. 목차
1. MySQL 일반 정보
2. MySQL 메일링 리스트 및 질문 요청 방법, 에러(버그) 알리기
3. 라이센싱 / mysql에 지불해야 할 경우
4. mysql 설치
5. mysql의 표준 호환성
6. mysql 접근 권한 시스템
7. mysql 언어 레퍼런스
8. SQL 질의 예제
9. mysql 서버 기능
10. mysql의 최대 성능 향상 방법
11. mysql 벤치마크
12. mysql 유틸리티
13. 테이블 유지보수 및 파손 복구에 isamchk 사용하기
14. mysql에 새로운 기능 추가
15. mysql ODBC 지원
16. 일반적인 문제 및 에러
17. 일반적인 문제 해결 방법
18. mysql 클라이언트 툴과 API
19. 다른 데이터베이스와 비교

부록 A ; MYSQL 사용자
부록 B ; 개발 프로그램
부록 C ;MYSQL 개발자
부록 D ; MYSQL 버전업 역사
부록 E ; MYSQL의 알려진 에러 및 설계에서 부족한 부분
부록 F ; MYSQL에 장래 추가할내용(The TODO)
부록 G ; 다른 시스템에 포팅하기
부록 H ; MYSQL 정규표현식 설명
부록 I ; Unireg 설명
부록 J ; 비MS 운영체제에서 MYSQL 서버 라이센스
부록 K ; MS 운영체제에서 MYSQL 라이센스
SQL 명령, 타입, 함수 인덱스
개념 인덱스

1. MySQL 일반 정보
1.1 MYSQL은 무엇인가?
1.2 매뉴얼에 관하여
        1.2.1 매뉴얼에서 쓰인 규정
1.3 MYSQL 역사
1.4 주요특징
1.5 안정성
1.6 2000년 문제
1.7 일반적인 SQL 정보 및 참고자료
1.8 관련 링크

2. MySQL 메일링 리스트 및 질문 요청 방법, 에러(버그) 알리기
2.1 mysql 메일링 리스트
2.2 질문하기, 버그 알리기
2.3 버그나 문제를 알리는 방법
        2.3.1 mysql이 손상되었을때
2.4 메일링리스트에서 질문 답변에 대한 안내

3. 라이센싱 / mysql에 지불해야 할 경우
3.1 mysql 비용
3.2 상업적인 지원 방는 방법
        3.2.1 기본 이메일 지원
        3.2.2 확장 이메일 지원
        3.2.3 login 지원
        3.2.4 확장 login 지원

3.3 라이센싱이나 지원에 지불하는 방법
3.4 라이센싱/지원 관련 정보 담당자
3.5 사용자 저작권 관련
3.6 mysql에 요금을 내지 않고 상업적으로 판매하는 경우
3.7 mysql을 사용해야 설정할 수 있는 제품을 판매하는 경우
3.8 mysql을 사용하여 상업적인 웹 서버를 운영하는 경우
3.9 상업용 Perl/Tcl/PHP/기타 애플리케이션을 판매하는 경우
3.10 앞으로의 라이센싱 변화

4. mysql 설치
4.1 mysql 구하기
4.2 mysql에서 지원하는 운영체제
4.3 사용할 수 있는 mysql 버전
4.4 업데이트 방법 및 시기
4.5 설치 개괄
4.6 바이너리로 설치하기
        4.6.1 클라이언트 프로그램 만들기
        4.6.2 시스템 관련 참고사항
                4.6.2.1 리눅스
                4.6.2.2 HP-UX
4.7 소스로 설치하기
        4.7.1 빠른 설치
        4.7.2 패치 적용하기
        4.7.3 일반 설정 옵션
4.8 컴파일에서 문제점이 생길때
4.9 MIT-pthreads 주의사항
4.10 펄 설치
        4.10.1 펄 DBI/DBD 인터페이스 사용시 문제점
4.11 시스템 관련 참고사항
        -솔라리스, 솔라리스 x86, 선OS4, 알파-DEC-유닉스, 알파-DEC-OSF1,
         SGI-IRIX, FreeBSD, BSD/OS 2, SCO, SCO Unixware 7.0, IBM-AIX, HP-UX
        -리눅스 : 리눅스-x86, 레드햇 5.0/5.1, 리눅스-스팍,리눅스-알파,MkLinux
         리눅스 RPM
4.12 TcX 바이너리
4.13 Win32 관련사항
4.14 설치후 셋업 및 테스트
        4.14.1 mysql_install_db 실행시 문제점
        4.14.2 mysql 서버 실행시 문제점
        4.14.3 자동 시작/정지 시키기
        4.14.5 옵션 파일
4.15 업그레이드/다운그레이드할때의 주의사항
        4.15.1 3.21에서 3.22로 업그레이드
        4.15.2 3.20에서 3.21로 업그레이드
        4.15.3 다른 아키텍쳐로 업그레이드

5. mysql의 표준 호환성
5.1 mysql의 ANSI SQL92 확장 부분
5.2 mysql에서 빠진 기능
        5.2.1 sub-selects
        5.2.2 SELECT INTO TABLE
        5.2.3 트랜잭션
        5.2.4 저장 프로시져/트리거
        5.2.5 외래키
                5.2.5.1 외래키 사용하지 않는 이유
        5.2.6 뷰
        5.2.7 '--' 로 주석문 시작
5.3 mysql에서 따르고 있는 표준
5.4 BLOB/TEXT 타입의 제한사항
5.5 COMMIT-ROLLBACK 없이 사용하는 방법

6. mysql 접근 권한 시스템
6.1 접근 권한 시스템이란 무엇인가
6.2 mysql 서버에 연결하기
        6.2.1 비밀번호를 안전하게 유지하기
6.3 mysql에서 제공하는 권한
6.4 권한 시스템 작동 방식
6.5 접근 제어 1 : 연걸 인증
6.6 접근 제어 2 : 요청 인증
6.7 권한변경시 적용 방법
6.8 초기 mysql 권한 설정
6.9mysql에 새로운 사용자 권한 추가
6.10 비밀번호 설정 방법
6.11 접근 금지 에러가 나는 이유
6.12 크랙커에 대비하여 mysql을 안전하게 만드는 방법

7. mysql 언어 레퍼런스
7.1 문자 : 문자열과 숫자 기록하기
        7.1.1 문자열
        7.1.2 숫자
        7.1.3 NULL 값
        7.1.4 데이터베이스, 테이블, 인덱스, 컬럼, 알리아스 이름
                7.1.4.1 이름에서 대소문자 구별
7.2 컬럼 타입
        7.2.1 컬럼 타입 저장 요구량
        7.2.2 숫자 타입
        7.2.3 날짜/시간 타입
                7.2.3.1 DATETIME, DATE, TIMESTAMP 타입
                7.2.3.2 TIME 타입
                7.2.3.3 YEAR 타입
        7.2.4 문자열 타입
                7.2.4.1 CHAR, VARCHAR 타입
                7.2.4.2 BLOB, TEXT 타입
                7.2.4.3 ENUM 타입
                7.2.4.4 SET 타입
        7.2.5 컬럼에 적절한 타입 고르기
        7.2.6 컬럼 인덱스
        7.2.7 다중 컬럼 인덱스
        7.2.8 다른 데이터베이스 엔진의 컬럼 타입 사용
7.3 SELECT 와 WHERE 문에서의 함수(functions)
        7.3.1 그룹(Group)으로 묶는 기능
        7.3.2 산술연산자
        7.3.3 비트(Bit) 함수
        7.3.4 논리(logical) 연산자
        7.3.5 비교 연산자
        7.3.6 문자열 비교 함수
        7.3.7 흐름 제어(control flow) 함수
        7.3.8 산술 함수
        7.3.9 문자열 함수
        7.3.10 날짜/시간 함수
        7.3.11 기타 함수
        7.3.12 GROUP BY 문에서 사용하는 함수
7.4 CREATE DATABASE
7.5 DROP DATABASE
7.6 CREATE DATABASE
        7.6.1 자동 컬럼 변환
7.7 ALTER TABLE
7.8 OPTIMIZE TABLE
7.9 DROP TABLE
7.10 DELETE
7.11 SELECT
7.12 JOIN
7.13 INSERT
7.14 REPLACE
7.15 LOAD DATA INFILE
7.16 UPDATE
7.17 USE
7.18 FLUSH(캐쉬 삭제)
7.19 KILL
7.20 SHOW(테이블, 컬럼 정보 얻기)
7.21 EXPLAIN(SELECT 관련 정보 얻기)
7.22 DESCRIBE(컬럼 정보 얻기)
7.23 LOCAK TABLES/UNLOCK TABLES
7.24 SET OPTION
7.25 GRANT / REVOKE
7.26 CREATE INDEX(호환성 기능)
7.27 DROP INDEX(호환성 기능)
7.28 주석
7.29 CREATE FUNCTION/DROP FUNCION
7.30 예약된 문자 사용하는 경우

8. SQL 질의 예제
        8.1 twin project에서의 질의
                8.1.1 Find all non-distributed twins
                8.1.2 Show a table on twin pair status

9. mysql 서버 기능
        9.1 mysql에서 지원하는 언어
                9.1.1 데이터와 정열에 사용하는 문자 셋
                9.1.2 새로운 문자셋 추가
                9.1.3 멀티바이트 문자 지원
        9.2 업데이트 로그
        9.3 mysql 테이블 최대 크기

10. mysql의 최대 성능 향상 방법
10.1 버퍼 크기 조정
10.2 메모리 상용 방법
10.3 속도 향상에 영향을 미치는 컴파일/링크 방법
10.4 인덱스 사용방법
10.5 WHERE 문에서 최적화하기
10.6 테이블 열고 닫는 방법
        10.6.1 데이터베이스에서 많은 수의 테이블을 만들때의 단점
10.7 많은 테이블을 여는 이유
10.8 데이터베이스와 테이블에서 심볼링 링크 사용
10.9 테이블에 락 거는 방법
10.10 테이블을 빠르고 작게 배열하는 방법
10.11 INSERT 문에서 속도에 영향을 미치는 부분
10.12 DELETE 문에서 속도에 영향을 미치는 부분
10.13 mysql에서 최대 속도를 얻는 방법
10.14 로우 포맷과 다른 점은 무엇인가? 언제 VARCHAR/CHAR을 사용해야 하는가?

11. mysql 벤치마크

12. mysql 유틸리티
        12.1 서로 다른 mysql 프로그램 개괄
        12.2 텍스트 파일에서 데이터 가져오기
        12.3 mysql 압축 읽기 전용 테이블 생성기

13. 테이블 유지보수 및 파손 복구에 isamchk 사용하기
        13.1 isamchk 명령어 사용법
        13.2 isamchk 메모리 사용법
        13.3 테이블 유지보수 설정
        13.4 테이블에서 정보 얻기
        13.5 파손 복구에 isamchk 사용하기
                13.5.1 에러가 났을때 테이블 점검 방법
                13.5.2 테이블 복구 방법
                13.5.3 테이블 최적화하기

14. mysql에 새로운 기능 추가
        14.1 새로운 사용자 정의 기능 추가
                14.1.1 UDF calling sequences
                14.1.2 Argument processing
                14.1.3 Return values and error handling
                14.1.4 사용자 정의 기능 컴파일 및 설치하기

        14.2 새로운 native 기능 추가

15. mysql ODBC 지원
        15.1 MyODBC가 지원하는 운영체제
        15.2 MyODBC에 문제가 있을때
        15.3 MyODBC와 작동하는 프로그램
        15.4 ODBC 관리자 프로그램 설정 방법
        15.5 ODBC에서 AUTO_INCREMENT 컬럼의 값 가져오기

16. 일반적인 문제 및 에러
        16.1 mysql 사용시 일반적인 에러
                16.1.1 mysql 서버가 맛이 간 경우
                16.1.2 local mysql 서버에 접속이 안되는 경우
                16.1.3 Host '...' is blocked 에러
                16.1.4 Out of Memory 에러
                16.1.5 Packet too large 에러
                16.1.6 The table is full 에러
                16.1.7 Commands out of sync 에러(클라이언트)
                16.1.8 Ignoring user 에러
                16.1.9 Table 'xxx' doesn't exist 에러
        16.2 mysql에서 디스크가 꽉 찼을때
        16.3 텍스트 파일에서 SQL 문장 실행하기
        16.4 mysql에서 임시 파일을 저장하는 곳
        16.5 /tmp/mysql.sock을 지워지지 않도록 보호하는 방법
        16.6 Access denied 에러
        16.7 일반 사용자로 mysql 실행하기
        16.8 파일 퍼미션 문제
        16.9 File not found
        16.10 DATE 컬럼 사용할때 문제
        16.11 검색에서 대소문자 구별
        16.12 NULL 값에서 문제
        16.13 alias에서 문제
        16.14 관련된 테이블에서 레코드를 지웠을때
        16.15 해당하는 레코드가 없을때 문제 해결
        16.16 ALTER TABLE 에서 문제

17. 일반적인 문제 해결 방법
        17.1 데이터베이스 복사
        17.2 데이터베이스 백업
        17.3 같은 머신에서 여러개의 mysql 서버 실행하기

18. mysql 클라이언트 툴과 API
        18.1 mysql C API
        18.2 C API 테이타타입
        18.3 C API 함수 개괄
        18.4 C API 함수 설명
                **생략**
                18.4.47 mysql_query()가 성공했는데도 mysql_store_result()
                        가 NULL을 반환하는 경우
                18.4.48 질의에서 결과 얻는 방법
                18.4.49 마지막으로 입력된 unique ID 얻는 방법
                18.4.50 C API와 링크할때 문제점
                18.4.51 thread-safe 클라이언트 만들기
        18.5 mysql perl API
                18.5.1 DBI with DBD :: mysql
                        18.5.1.1 dbi 인터페이스
                        18.5.1.2 DBI/DBD 추가 정보
        18.6MYSQL 자바 연결(JDBC)
        18.7 mysql PHP API
        18.8 MYSQL C++ API
        18.9 mysql Python API
        18.10 Mysql TCL API

19. 다른 데이터베이스와 비교
        19.1 mSQL과의 비교
                19.1.1 mSQL 툴을 mysql로 옮기기
                19.1.2 msql과 mysql 클라이언트/서버 통신 프로토콜의 차이점
                19.1.3 msql 2.0과 mysql의 SQL 문 차이점
        19.2 PostgreSQL과의 비교


부록 A ; MYSQL 사용자
부록 B ; 개발 프로그램
부록 C ;MYSQL 개발자
부록 D ; MYSQL 버전업 역사
부록 E ; MYSQL의 알려진 에러 및 설계에서 부족한 부분
부록 F ; MYSQL에 장래 추가할내용(The TODO)
부록 G ; 다른 시스템에 포팅하기
부록 H ; MYSQL 정규표현식 설명
부록 I ; Unireg 설명
부록 J ; 비MS 운영체제에서 MYSQL 서버 라이센스
부록 K ; MS 운영체제에서 MYSQL 라이센스
SQL 명령, 타입, 함수 인덱스
개념 인덱스
5. mysql의 표준 호환성

5.1 mysql의 ANSI SQL92 확장부분
mysql에는 다른 sql 데이터베이스에서 찾을 수 없는 확장된 부분이 있다. 이런 부분을 사용
하는 경우 주의해야 한다. 왜냐면  mysql에서 사용한 코드가 다른  SQL 서버에 포팅할 수
없을 수도 있기 때문이다. 어떤 경우에는 /*! ... */ 형식의 주석문을 사용한 MYSQL 확장을
이용해 포팅가능한 코드를 만들 수 있다. 예를 들어보자:

SELECT /*! STRAIGHT_JOIN */ col_name from table1,table2 WHERE ...

MYSQL의 확장 부분은 다음과 같다:
- 필드타입 MEDIUMINT, SET, ENUM , 그리고 다른 BLOB 와 TEXT 타입.
- 필드속성 AUTO_INCREMENT, BINARY, UNSIGNED and ZEROFILL.
- 모든 문자열 비교는 기본적으로  대소문자를 구별하지 않으며 현재의  문자셋(기본적으로
ISO-8859-1 Latin1)에 의해 정렬 순서가 결정된다. 이것을 원하지 않으면  컬럼을 BINARY
속성으로 정의해야 하며 이런 경우에는 mysql 서버 호스트가 사용하는 ASCII 순서에 따라
문자열을 비교한다.
- MYSQL은 데이터베이스를 디렉토리로 만들고 테이블은 파일이름으로 만든다. 이것은 두
가지를 함축하고 있다:
    ㅇ 파일이름의 대소문자를 구별하는 (대부분의  유닉스 시스템. 리눅스도 마찬가지겠지
     용~) 운영  시스템에서는 MYSQL의 데이터베이스 이름과  테이블 이름은 대소문자를
     구별한다. 테이블 이름을 기억하는데 문제가 있다면 모든 것을 소문자로 만들자.
    ㅇ 테이블의 백업, 이름바꾸기, 옮기기, 삭제,  복사를 위해 표준 시스템 명령을  사용할
     수 있다. 예를 들어 테이블의 이름을 바꾸려면  해당하는 테이블의 `.ISD', `.ISM' and
     `.frm' 파일의 이름을 바꾸면 된다.
- SQL문에서 db_name.tbl_name 문을 이용하여  다른 데이터베이스의 테이블에 접근할  수
있다. 일부 SQL 서버는 같은 기능을 지원하지만 이것을 User space라고 부른다. MYSQL은
다음과  같은  TABLESPACES를  지원하지  않는다  :  create  table  ralph.my_table...IN
my_tablespace.
- 수치(숫자형) 컬럼에서 LIKE를 사용할 수 있다.
- SELECT문에서   INTO OUTFILE  과  STRAIGHT_JOIN  을 사용할   수 있다.  7.11
[SELECT] 참고.
-EXPLIAN SELECT는 테이블에서 어떻게 조인이 되었는지에 대한 정보를 보여준다.
- Use of index names, indexes on a subpart of a field, and use of INDEX or KEY in a
CREATE TABLE statement. 7.6 [CREATE TABLE] 참고.
- ALTER TABLE에서 CHANGE col_name, DROP col_name 또는 DROP INDEX 를 사용
한다. 7.7 [ALTER TABLE] 참고.
- ALTER TABLE 문에서 IGNORE 사용.
- ALTER TABLE 문에서 다중 ADD, ALTER, DROP or CHANGE 사용
- IF EXISTS 키워드를 이용한 DROP TABLE 사용.
- 한 테이블 이상에서 DROP TABLE 사용.
- LOAD DATA INFILE 사용. 대부분의 경우 이 문장은  오라클의 LOAD DATA INFILE
과 호환된다. 7.15 [LOAD DATA INFILE] 참고.
(** 많은 양의 데이터를 한꺼번에 입력할 때 일일이 INSERT 문을 하는  것보다 속도가 빠
르다. **)
- OPTIMIZE TABLE 문 사용.
- 문자열은 ''' 만이 아니라 '"' 또는 ''' 로 닫을 수 있다.
- escape `\' 문자 사용.
- SET OPTION 문. 7.24 [SET OPTION] 참고.
- GROUP BY 부분에서 모든 컬럼을 사용할 필요가 없다. 이러한  기능은 일반적인 질의가
아닌 특정한 질의에서 성능을 향상시킨다. 7.3.12 [GROUP BY Functions] 참고.
(** ANSI SQL에서는 여러 테입믈을 이용하여 GROUP  BY를 사용할 때 사용하고자 하는
모든 컬럼에 GROUP BY를 지정해 주어야 한다. 이렇게 되는 경우 불필요한 연산이 수행될
수 있는데 MYSQL에서는 이러한 것을 없앤 것이다. 7.3.12를 참고한다 **)
- 다른 SQL 환경을 사용했던 사용자를 위해 MYSQL은 많은  기능에서 알리아스를 지원한
다. 예를 들어 모든 문자 펑션은 ANSI SQL 과 ODBC 구문을 지원한다.
- MYSQL은 C 프로그래밍 언어와 같은 논리적인 OR 과 AND를 의미하는 || 와 && 를 인
식한다. MYSQL에서는 || 와 OR 는 같은 말이며 && 와 AND 도 마찬가지이다. 이러한 미
묘한 구문때문에 MYSQL은 string  concatenation(문자열 연관, 연결?)을 위한  ANSI SQL
오퍼레이터인 || 을 지원하지 않는다. 대신 CONCAT()를 사용한다. CONCAT() 는 많은 인
자가 있어서 MYSQL 에서 || 오퍼레이터의 사용을 변환하기 쉽다.

MySQL understands the || and && operators to mean logical OR and AND, as in the C
programming language. In  MySQL, ||  and OR are  synonyms, as  are &&  and AND.
Because of this  nice syntax,  MySQL doesn't support  the ANSI  SQL operator  || for
string concatenation; use  CONCAT() instead.  Since CONCAT() takes  any number  of
arguments, it's easy to convert use of the || operator to MySQL.

- 포팅이 가능하도록 SQL CODE에서  STRAIGHT_JOIN같은 MYSQL만의 키워드 사용을
지원하기 위해 이런 키워드를 /* */ 주석안에 내장할 수 있다. 주석문안의 내용은 '!' 로 시
작한다. 이런 경우  MYSQL에서는 주석문을 다른  MYSQL 구문과 같이  해석하지만 다른
SQL 서버에서는 이러한 확장기능을 사용하지 않고 건너띌 수 있다. 예를 보자:

SELECT /*! STRAIGHT_JOIN */ * from table1,table2 WHERE ...

- 다음의 기능이나 명령 사용:
    ㅇ CREATE DATABASE or DROP DATABASE. 7.4 [CREATE DATABASE] 참고.
    ㅇ MOD() 대신에 % 사용. %는 C 프로그래머를 위해 지원하며 또한 PostgresSQL과의
     호환성을 위해 지원한다.
    ㅇ 컬럼 문에서 =, <>, <= ,<, >=,>, <<, >>, AND, OR, LIKE 사용.
    ㅇ LAST_INSERT_ID(). 18.4.49 [mysql_insert_id()] 참고.
    ㅇ REGEXP or NOT REGEXP.
    ㅇ 하나나 하나 이상의 인자를 사용한 CONCAT() 나 CHAR(). MYSQL에서 이러한 펑
     션은 여러개의 인자를 가질 수 있다.
    ㅇ  BIT_COUNT(),   ELT(),  FROM_DAYS(),   FORMAT(), IF(),   PASSWORD(),
     ENCRYPT(), PERIOD_ADD(), PERIOD_DIFF(), TO_DAYS(), or WEEKDAY().
    ㅇ 서브스트링을 없애는 데 TRIM()  사용.(Use of TRIM() to trim  substrings) ANSI
     SQL 에서는 단일 문자 제거만 지원한다.
(** 꺼어억~ 트림이 술먹고 하는 트림은 아니랍니다... **)
ㅇ 그룹 펑션에서 STD(), BIT_OR() and BIT_AND()
ㅇ DELET + INSERT 대신 REPLACE 사용. 7.14 [REPLACE] 참고.
ㅇ FLUSH flush_option 명령.


5.2 MYSQL에서 빠진 기능
다음의 기능들은 현재 버전의 MYSQL에  빠져있다. 다음 버전에서의 우선권을 확인하라면
MYSQL TODO 목록을  참고하자(http://www.mysql.com/Manual_split/manual_Todo.html).
이것이 가장 최신 버전의 TODO 목록이다. 부록 F [TODO] 참고.

5.2.1 Sub-selects
다음은 Mysql에서 작동하지 않는다:

SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);

Mysql에서는 오직 INSERT ... SELECT ... and  REPLACE ... SELECT ... 만을 지원한다.
독립적인 서브-select 문은 3.23.0에서 아마도 사용할 수 있을 것이다.  그대신 현재 IN() 펑
션을 사용할 수 있다.

5.2.2 SELECT INTO TABLE
Mysql은 아직  SELECT ...  INTO TABLE  ....을 지원하지  않는다. 현재,  Mysql은 오직
SELECT ... INTO OUTFILE ..., 만을 지원하며 기본적으로는 동일하다.

5.2.3 트랜잭션(Transactions)
트랜잭션은 지원되지  않는다. Mysql은  곧 atomic(원자성?)  오퍼레이션을 지원할  것이며
atomic 오퍼레이션은 rollback이 없는 트랜잭션과 비슷하다.  atomic 오퍼레이션을 사용하며
insert/select/모든 명령의 그룹을 실행할 수 있으며 어떤 스레드도 충돌하지 않을 수 있도록
보장해준다. 이 문맥에서 일반적으로 롤백(rollback)은  필요없다. 현재 LOCK TABLES  와
UNLOCK TABLES 명령을  이용하여 다른  스레드가 충돌하는 것을  막을 수  있다. 7.23
[Lock Tables] 참고.

5.2.4 저장 프로시저와 트리거
저장 프로시저는 서버에서 컴파일되고 저장될 수 있는 SQL 명령 세트이다. 이런 기능이 수
행되면 클라이언트는 전체 질의를 다시 할 필요가 없고 또한 저장 프로시저를 참조할 수 있
다. 이런 기능이 있으면 질의는  한번만 해석되고 서버와 클라이언트간의  주고받아야 하는
데이터가 줄어들므로 속도가 향상된다. 또한 서버의  펑션 라이브러리를 가짐으로서 개념적
인 단계를 향상시킬  수 있다. (???  You can also  raise the conceptual  level by  having
libraries of functions in the server.)

트리거는 특별한 이벤트가 발생했을 때 생기는 저장 프로시져이다.  예를 들어 트랜잭션 테
이블에서 레코드가 삭제되고 모든 트랜잭션이 지워질 때 상응하는 테이블을 삭제할 수 있는
저장 프로시저를 설치할 수 있다.

앞으로는 저장 프로시저를 지원할 예정이지만 트리거는 아니다. 트리거는 필요하지 않은 경
우에도 사용될 수 있어서 일반적으로 속도가 느려진다.

언제 저장 프로시저를 사용하게  될지는 앞으로 Mysql에 추가할  목록인 부록 F를 참고하
자.(The TODO)

(** 전반적으로 트랜잭션 처리와 트리거 등은 데이터베이스의 속도를 저하시킵니다. Mysql
은 이렇게 속도에 영향을 미칠 수 있는 부분을 제거하여  빠른 속도를 내는 것이지요. 이러
한 부분이 자기가 사용하는 데이터베이스에서 얼마나 중요한가 판단을 해 보아야 할 것입니
다. 보통 소형 DBMS에서는 회복과 병행수행을 지원하지 않는 경우가 많다. 즉 병행수행은
발생하지 않으며, 회복은 사용자의 문제로 생각한다. 그러므로 사용자가 데이터베이스의  예
비 사본을 준비하며, 고장이 발생하면 작업을 다시 해야 한다. 트리거같은 경우는 자료의 무
결성을 보장하기 위해 필요한 것이다. **)

5.2.5 외래키(Foreign Keys)
SQL 문에서 외래키는 테이블을 조인할 때  사용하지 않지만 대부분 참조 무결성을 확인할
때 사용한다. SELECT 문에서 다중 테이블에서 자료를 가져오길 원하면 테이블을 조인해서
처리할 수 있다.

SELECT * from table1,table2 where table1.id = table2.id

7.12 [JOIN] 참고.

Mysql에서 외래키(FOREIGN KEY) 문은 다른 SQL 제품의 CREATE TABLE 명령과의 호
환성 때문에   존재한다: 외래키는   아무것도 하지  않는다.  ON  DELETE  ...  가  없는
FOREIGN KEY 구문은 대부분 문서적인  목적으로 사용한다. 일부 ODBC  애플리케이션은
이것을 자동적인 WHERE 문을 만들 때 사용할 것이다. 그렇지만 이것은 대부분 생략(무시)
하고 넘어가기 쉽다. 외래키는 때로는 제약조건 체크(constraint check)로 사용을 하지만 이
러한 체크는 데이터가 테이블에 정확한 순서로 들어갈때는 불필요하다. Mysql은 일부 애플
리케이션에서 외래키가 존재하는 것을 필요로 하기 때문에(제대로 작동하든  안하든 상관없
이) 지원하는 것일 뿐이다.

Mysql에서 외래키를 가진 테이블의 레코드를  삭제할 때 애플리케이션에 적절한 DELETE
문을 추가하여 ON DELETE ... 가 수행되는 것을  막음으로써 문제를 해결할 수있다. 경험
상 이렇게 하는 것이 외래키를 사용하는 것과 같이 빠르며(어떤  경우에는 더 빠름) 포팅하
기가 더 좋다.

가까운 시일안에 우리는 외래키 기능을 확장할 것이다. 그래서 최소한 mysqldump와 ODBC
에서 정보가 저장되고 검색할 수 있도록 할 것이다.


5.2.5.1 외래키를 사용하지 않는 이유

외래키를 사용할 때 어디에서 출발해야 할지 모르는 많은 문제가 있다:

- Foreign key들은 상황을 매우 복잡하게 만든다. 왜냐하면, foreing key의 정의가 database에
담겨야 하고, foreign key를 구현하는 것은 "자연스런" File 사용법(data file들을 옮기고,
복사하고, 삭제하는 등...)을 제한한다.
(** 문태준님 역주: 번역이 이상한데 외래키가 있으면 참조 무결성 규칙을 위해 여러 가지
보상  연산을 하게 된다. 이것을 뜻하고 있는 듯하다. **)

- INSERT 와 UPDATE 문은 속도에 많은 영향을  끼친다. 그리고 이런 경우 보통 올바른
순서로 올바른 테이블에 레코드를 삽입하기 때문에 대부분 모든 외래키 체크는 사용할 필요
없다.

- 한쪽의 영향이 전체 데이터베이스에 연쇄 작용을 하기 때문에 테이블에서 업데이트를 할
때 매우 많은 테이블에서 락을 사용해야 한다. 한 테이블에서 먼저 레코드를 삭제하고 그후
에 다른 테이블에서 레코드를 삭제하는 것이 훨씬 빠르다.

- Table를 완전히 지우고, (backup이나 새로운 source로부터) 모든 record들을 다시 복구하는
방법으로 Table을 복구할 수 없다.

- Foreign key를 사용한다면, table을 dump(backup)하고 (그 dump한 자료를) restore하는 데
있어 그 일련의 순서를 적절하게 지켜야 한다.

- 각각의 table의 정의가 쓸모있고 적절하더라도, (각 Table들이 상호참조하게 된다면) 단순한
create문으로는 재생성이 불가능한 circular definition(순환정의)가 쉽게 발생한다.
(역자주: A라는 Table이 B의 자료를 참조하는 foreign key를 담고 있고,
         B는 C에 대한 foreign key를, C는 A에 대한 foreign key를 담도록 table이 구성된다면
         한번에 A,B,C table을 생성할 수 없다. A,B,C를 만든다음 각각의 foreign key를 지정해
         주는 방법을 쓰게 된다.)

외래키의 좋은 점은 단지 다음와 같다. ODBC와  특정한 다른 클라이언트 프로그램에서 어
떻게 테이블이 연결되어 있는지를 볼 수 있고 연결 다이어그램을 보는데 사용하며 애플리케
이션을 만드는데 돕는 점이다.
(역자주: 이 글은 foreign key에 대해서 매우 비판적이다. 하지만, 이것은 foreign key의
         일부 기능일뿐이다. 무엇보다도 client가 각 Table내 DATA의 연관관계에 대해서
         빼먹었는지에 대해서 일일이 신경쓰지 않게 하고, 항상 자료의 무결성(정합성[?])을
         보장한다는 것은 매우 중요하다.

         특히, Table이 1~20개가 아닌 100단위가 넘어간다면, client에서 일일이 신경쓰며
         programing하는 것도 힘들지만, debugging도 예상보다 힘들어진다.
         각 table간의 연결관계를 잘 문서화한다면 programmer들이 foreign key로 고통받기
         보다는 관련 Table을 check해야 되는 수고를 덜게된다.

         foreign key가 기피되는 주된 이유는 table내의 Data를 수정하는 것이 쉽지 않기
         때문이다. 현장 실무자의 논리에 어긋나는 요청을 처리하는 데 있어서
         foreign key만큼 거추장스런 놈도 없으리라. )

Mysql에서는 곧 외래키 정의를 저장할 수 있도록 해서 클라이언트가 어떻게 원래의 연결이
만들어졌는지에 대해서 질문하고 답을 받을 수 있도록 할 것이다. 현재의  '.frm' 파일 포맷
은 아직 이것을 지원하지 못하고 있다.


5.2.6 뷰

Mysql은 뷰를 지원하지 않는다. 그렇지만 TODO(이후 개선 목록)에 있다.
MySQL doesn't support views, but this is on the TODO.

5.2.7 `--'을 사용한 주석

일부 다른 SQL 데이터베이스는 '--'  로 주석을 시작한다. mysql 명령  라인 도구가 '--'로
시작하는 모든 줄을 제거할 지라도 Mysql은  '#'을 주석 문의 시작으로 사용한다.  사용자는
또한 C 명령  스타일인 /*  this is  a comment  */ 를  mysql에서 사용할  수 있다.  7.28
[Comment] 참고.

Mysql은 '--'를 지원하지  않을 것이다;  '--'은 퇴보한  주석문 형태로 자동으로  생성되는
SQL 질의에서 많은 문제를 발생시킨다. 다음의 예제를 보자. 우리는 자동적으로 payment를
!payment! 의 값으로 입력하도록 하고 있다 :

UPDATE tbl_name SET credit=credit-!payment!

payment의 값이 음수일 때 어떤 일이 생길 것이라 생각하는가?

1--1은 합당한 SQL문이기 때문에 '--'가 주석문의 시작을 의미하는 것을 꺼리는 것이다.

'--' 주석을 포함하는 텍스트 파일의 SQL 프로그램을 가졌다면 다음과 같이 사용해야 한다:

shell> replace " --" " #" < text-file-with-funny-comments.sql \
         | mysql database

instead of the normal(정상적인 경우 대신???):

shell> mysql database < text-file-with-funny-comments.sql

명령 파일로 '--' 주석을 '#' 주석으로 바꿀 수 있다:

shell> replace " --" " #" -- text-file-with-funny-comments.sql

다음의 명령으로 원래대로 돌려놓자:

shell> replace " #" " --" -- text-file-with-funny-comments.sql

(** 일부 SQL에서 사용하는 --  주석문에서 문제가 생길 수 있으므로  MYSQL에서는 #을
주석문으로 사용한다는 말이다 **)

5.3 Mysql이 따르고 있는 표준은 무엇인가?

Entry level SQL92. ODBC level 0-2.


5.4 BLOB 와 TEXT 타입의 제한
BLOB 나 TEXT 필드에서 GROUP BY 나 ORDER BY를 사용하길 원하면 그 필드를 고정
길이 객체로 만들어야 한다. 이렇게  하는 표준적인 방법은 SUBSTRING  펑션을 사용하는
것이다. 예를 보자:

mysql> select comment from tbl_name order by SUBSTRING(comment,20);

이렇게 하지 않으면 정렬할 때  오직 첫 번째 max_sort_lengths  (기본값=1024)만을 고려된
다.

BLOB 와 TEXT 는 기본값을 가질 수 없으며 또한 언제나 NULL 컬럼일 것이다.

BLOB and  TEXT cannot   have DEFAULT values   and will also  always  be NULL
columns.

5.5 COMMIT-ROLLBACK 없이 어떻게 대치할 수 있을까?
Mysql은 COMMIT-ROLLBACK 을 지원하지 않는다. 문제는 COMMIT-ROLLBACK을 효
과적으로 다루기 위해서는 Mysql에서 현재 사용하는 것과 완전히 다른 테이블 설계가 필요
하다는 것이다. Mysql은 또한 테이블을 자동  클린업하는 추가적인 스레드와 더 많은 디시
크를 사용할 수 있는 기능이 필요하다. 이러한  기능은 현재보다 mysql을 2-4배 느리게 만
든다. Mysql은 대부분의  다른 SQL 데이터베이스보다  훨씬 더 빠르다.  (전형적으로 최소
2-3대 빠름) 이러한 이유는 Mysql에 COMMIT-ROLLBACK이 없기 때문이다.

당분간은 우리는   SQL 서버  언어의  성능을  향상시키는데 더   주력할 것이다.  대부분
COMMIT-ROLLBACK 기능이 정말로 필요한 경우는 드물다. 또한 이렇게 하는 것이 더 좋
은 성능을 낼 수 있다.

일반적으로 트랜잭션이 필요한 루트는 LOCK TABLES를 사용해 코드를 짤  수 있다. 또한
레코드를 업데이트할 때 커서를 사용할 필요가 없다.

우리는 트랜잭션과 커서를 TODO에 넣었지만  우선권이 높은 것은 아니다.  이러한 기능을
수행한다면 CREATE TABLE 의 옵션으로 될 것이다. 이것은 옵션으로 지정한 테이블에서
만 작동하며 그 테이블은 느리게 될 것이라는 것을 의미한다.

우리는   100%   보편적인   데이터보다는   정말로   빠른    데이터베이스가   필요하다.
COMMIT-ROLLBACK 기능을 수행하더라도 속도에 손상이 없다면  우리는 그것을 지원할
것이다. 당분간은 더 중요하게 해야할 일들이  많이 있다. 우리가 어떤 것에 우선권을  두고
있는지는 TODO를 참고하자. 상위 단계의 지원을 받는 고객은 이것을 바꿀 수 있으며 우선
권이 변경될 수도 있다.

현재의 문제는 실제로 ROLLBACK 이다. 롤백없이 LOCK TABLES을 이용하여 여러 종류
의 COMMIT를 사용할 수 있다. 롤백을 지원하기  위해 Mysql은 업데이트가 된 모든 예전
레코드를 저장하고 롤백이 일이났을 때 시작 시점으로 돌아갈 수 있도록 바꾸어야 한다. 예
를 들어 이러한 것은 전혀 어렵지 않다.(현재의 isamlog 는 이런 경우를 위해 사용할 수 있
다) 그러나 ALTER/DROP/CREATE TABLE에서 롤백을 수행하는 것은 무척 어렵다.

롤백 사용을 피하기 위해 다음의 전략을 사용할 수 있다:

1. 접근하기 원하는 모든 테이블에 락을 사용. LOCK TABLES ... 
2. 조건 테스트(Test conditions)
3. 모든 것이 제대로 된다면 업데이트를 한다.
4. UNLOCK TABLES

일반적으로 가능한 롤백을 이용해 트랜잭션을 사용하는 것보다는 이러한 방법이 훨씬 더 빠
르다. 그렇지만 항상 사용가능한 것은 아니다. 이러한 방법으로 해결할 수 없는 유일한 상황
은 업데이트중 누군가가 스레드를 죽였을 때이다. 이런 경우 모든 락은 해제가 된다. 그렇지
만 업데이트의 일부는 실행되지 않을 것이다.

물론 단일 오퍼레이션에서 레코드를 업데이트하는 펑션을 사용할 수 있다. 다음의 테크닉을
사용하며 매우 효율적인 애플리케이션을 만들 수 있다:

- 현재 값과 관련되어 있는 필드를 수정
- 실제로 변화가 생겼을때만 필드를 업데이트

예를 들어, 어떤 고객 정보를 업데이트 할 때 오직 바뀐 데이터만 업데이트를 한다. 그리고
For example, when we are doing updates on some customer information, we update only
the customer data that have  changed and test only  that none of the changed  data, or
data that depend on the changed data, have changed compared to the original row.
변화된 데이터의 테스트는 UPDATE 문에서  WHRE 절을 사용하여 할 수  있다. 레코드가
업데이트되지 않았다면 클라이언트에 다음과 같은 메시지를 준다:  "당신이 바꾼 데이터 일
부가 다른 사용자에 의해  바뀌었습니다". 그러고나서 우리는  윈도우에서 예전의 레코드와
현재의 레코드를 비교하여 보여준다. 그러면  사용자는 어떤 고객 정보  레코드를 사용할지
결정할 수 있다.

이렇게 하면 "컬럼 라킹"과 비슷하다. 그렇지만 실제로는 더 빠르다.  왜냐하면 현재의 값과
관련되어 있는 값의 컬럼만 업데이트하기 때문이다.  이렇나 전형적인 업데이트문은 다음과
비슷할 것이다:

UPDATE tablename SET pay_back=pay_back+'relative change';

UPDATE customer
  SET
    customer_date='current_date',
    address='new address',
    phone='new phone',
    money_he_owes_us=money_he_owes_us+'new_money'
  WHERE
    customer_id=id AND address='old address' AND phone='old phone';

지금 보듯이   이렇게 하면  매우  효율적이며  설사 다른   클라이언트가 pay_back   이나
money_he_owes_us 컬럼의 값을 바꾸었을 때라도 제대로 작동한다.

대부분의 경우, 사용자는 테이블에서 유일한 값(identifiers)을 관리하기 위해 롤백과  테이블
락을 사용하고 싶어한다. 이것은  AUTO_INCREMENT 컬럼과 SQL  LAST_INSERT_ID() 
펑션, 또는 mysql_insert_id() 의 C API 펑션을 사용하여 더욱  효율적으로 사용할 수 있다. 
18.4.49 [mysql_insert_id()] 참고.

TcX에서는 언제나 이런 문제를 해결할  수 있기 때문에 결고 low-level  락을 필요로 하지
않는다. 어떤 경우에는 정말로 로우-락이 필요하다. 그렇지만 이런 경우는 극소수이다. 로우
-레벨 락을 원하면 테이블에서 플래그 컬럼을 사용할 수 있다. 다음과 같다:

UPDATE tbl_name SET row_flag=1 WHERE id=ID;

만약 row가 발견되고 row_flag가 원래의  row에서 이미 1이 아니라면  영향을 받은 row의
숫자로서 1일 반환한다.

MySQL returns 1 fro the number of  affected rows if the row was found  and row_flag
wasn't already 1 in the original row.

6. Mysql 접근 권한 시스템

mysql 은 진보적이지만 비표준적인 보안/권한 시스템을 가지고 있다. 이번 장에서는 이것이
어떻게 작동하는지를 설명하고 있다.

6.1 권한 시스템이란 무엇인가?
Mysql 권한 시스템의 주요 기능은 데이터베이스에서 select, insert, update, delete 권한
을 호스트의 사용자 이름과 관련짓는 것이다.

추가적인 기능에는 익명 사용자  기능과 LOAD DATA INFILE 과 관리자 오퍼레이션과 같은 my
sql만의  특수한 권한을 허용하는 부분이 포함되어 있다.


Mysql에서 인증을 목적으로 사용하는 사용자 이름은 유닉스 사용자 이름(로그인 이름)이나
위도우 사용자 이름고는 전혀 관계가 없다는 것!을 기억하자. 대부분 mysql 클라이언트는 m
ysql 사용자 이름으로 현재의 유닉스 사용자 이름을 사용하여 접속하려 할 것이다. 그렇지
만 이건 오직 편의를 위해서이다. 클라이언트 프로그램은 -u 나 --user 옵션으로 지정한 다
른 이름을 허용한다. 이것은 mysql 사용자 이름에 비밀번호를 설정하지 않으면 데이터베이
스의 보안에 문제가 생길 수 있다는 것을 의미한다. 어떤 이름을 사용하여 서버에 접속하려
고 하는 사람은 각 이름에 비밀번호가 설정되어 있지 않다면 접속에 성공할 것이다.

유닉스 사용자 이름이 일반적으로 8글자로 제한되어 있는 것과 다르게 mysql 사용자 이름은
16글자까지 사용할 수 있다.

mysql 비밀번호는 유닉스의 비밀번호와 아무 관련이 없다. 유닉스 머신에 로그인할 때 사용
하는 비밀번호와 데이터베이스에 접속할 때 사용하는 비밀번호는 전혀 관련이 없다. 또한 m
ysql은 유닉스 로그인 프로세스에서 사용하는 것과 다른 알고리즘으로 비밀번호를 암호화한
다.


6.2 mysql 서버에 접속하기

mysql 클라이언트 프로그램은 일반적으로 연결 패러미터(매개 변수)가 필요하다.: 연결할
호스트, 사용자 이름, 비밀번호. 예를 들어 mysql 클라이언트는 다음과 같이 시작할 수 있
다. (선택 인자는 [ ] 로 닫는다)

shell>; mysql [-h host_name] [-u user_name] [-pyour_pass]


-p와 뒤에 붙은 비밀번호 사이에는 공간이 없다는 것을 기억하자.

-h, -u, -p를 대체할 수 있는 형식으로는 --host=host_name, --user=user_name and --passw
ord=your_pass  이 있다.

mysql은 커맨드 라인에서 연결 매개변수가 빠져있을 때는 기본 값을 사용한다. 기본 호스트
이름은 localhost 이고 기본 사용자 이름은 유닉스 로그인 이름이다.(-p 가 빠져있으면 비
밀번호는 사용하지 않는다) 그래서 만약 유닉스 사용자 이름이 joe 라면 다음의 명령은 동
일하다.:

shell> mysql -h localhost -u joe
shell> mysql -h localhost
shell> mysql -u joe
shell> mysql


다른 mysql 클라이언트도 비슷하게 작동한다.

유닉스 시스템에서 연결을 할 때 사용할 수 있는 기본 값이 있어서 클라이언트 프로그램을
사용할 때마다 명령행에서 옵션을 사용하지 않아도 된다:

ㅇ 홈 디렉토리의 '.my.cnf' 설정 파일의 [client]  섹션에서 연결 변수를 설정할 수 있다.
파일에서 이와 연관된 섹션은 다음과 같다:
[client]
host=host_name
user=user_name
password=your_pass

4.14.4 [option files] 참고.

ㅇ 환경 변수를 사용하여 연결 변수를 지정할 수 있다. 호스트는 MYSQL_HOST 로 지정할 수
있다. Mysql  사용자 이름은 USER, LOGNAME, 또는 LOGIN을 사용할 수 있다. (이러한 값들은
이미 유닉스 로그인 이름으로 설정되어 있을 것이다. 그러므로 바꾸지 않는게 좋다) 비밀번
호는 MYSQL_PWD로 지정할 수 있다.(그렇지만 이것은 안전하지 않다; 다음 섹션을 참고하자)

연결 변수가 여러 가지 방법을 지정되었다면 명령행에서 지정한 값이 설정 파일과 환경 변
수로 설정한 것보다 우선권을 가진다. 또한 설정 파일의 값이 환경 변수보다 우선권을 가진
다.

6. 2. 1 비밀번호의 보안 유지

다른 사용자가 발견할 수 있게 비밀번호를 지정하는 방법은 권하지 않는다. 클라이언트 프
로그램을 실행할 때 비밀번호를 지정하는 방법은 아래와 같으며 각 방법마다 위험도를 같이
설명하였다:

ㅇ 명령행에서 -pyour_pass 또는 --password=your_pass 옵션 사용.  이 방법은 편리하지만
위험한 방법이다. 비밀번호를 시스템 상황 프로그램(ps 등)을 통해 볼 수 있기 때문에 다른
사용자가 명랭행으로 볼 수 있다.(mysql 클라이언트는 일반적으로 초기화되는 동안 명령행
인자를 0으로 덮어씌운다. 그렇지만 값을 볼 수 있는 짧은 틈이 여전히 있다)

ㅇ -p 또는 --password 옵션 사용(비밀번호 값을 지정하지는 않음). 이런 경우 클라이언트
프로그램은 터미널에서 비밀번호를 물어본다:
shell> mysql -u user_name -p
Enter password: ********

클라이언트는 비밀번호를 칠 때 터미널에서 '*'  문자를 보여준다. 그러므로 다른 사용자가
비밀번호를 볼 수 없다. 다른 사용자가 볼 수 없으므로 명령행에서 비밀번호를 입력하는 것
보다 훨씬 더 안전하다. 그렇지만 이 방법은 비대화식의 스크립트로 클라이언트 프로그램을
사용하면 적절하지 않다.

ㅇ 설정 파일에 비밀번호 저장. 예를 들어 홈 디렉토리의 '.my.cnf' 파일에서 [client] 섹
션에 비밀번호를 지정할 수 있다.
[client]
password=your_pass

비밀번호를 '.my.cnf' 파일에 저장한다면 그 파일은 그룹이나 다른 사용자가 읽기/쓰기를
할 수 없도록 해야 한다. 파일의 퍼미션이 400 이나 600 인지 확인하자.

4.14.4 [옵션 파일] 참고.

ㅇ 비밀번호를 MYSQL_PWD 환경 변수에 저장할 수 있다. 그렇지만 이 방법은 정말로 위험하
며 사용해서는 안된다. 일부 ps 프로그램은 실행 프로세스의 환경변수를 보여주는 옵션이
있다; MYSQL_PWD에 설정을 하면 다른 사람들이 쉽게 비밀번호를 볼 수 있다. 이런 기능의 p
s가 없는 시스템일지라도 프로세스 환경변수를 검색할 수 있는 방법이 없다고 생각하는 것
은 현명하지 못하다.

이중에서 가장 안전한 방법은 클라이언트 프로그램이 비밀번호를 요구하거나 적절하게 보안
이 된 '.my.cnf' 파일에 비밀번호를 지정하는 것이다.

6.3 mysql에서 제공하는 권한

권한과 관련된 정보는 mysql 데이터베이스의(데이터베이스 이름이 mysql 임) user, db, hos
t, table_priv, columns_priv  테이블에 저장된다. mysql 서버는 시작할 때, 그리고 환경을
지정할 때(6.7 [권한 변경] 참고) 이 테이블의 내용을 읽어들인다.

mysql에서 제공하는 권한을 설정할 때 사용하는 이름은 아래와 같다.테이블의 컬럼 이름은
grant tables의 각 권한 및 권한이 적용되는 context와 연관되어 있다.


Privilege              Column         Context
(권한)          (컬럼)         (환경)
select         Select_priv     tables
insert         Insert_priv     tables
update         Update_priv     tables
delete         Delete_priv     tables
index          Index_priv      tables
alter          Alter_priv      tables
create         Create_priv     databases, tables or indexes
drop            Drop_priv       databases or tables
grant          Grant_priv      databases or tables
reload         Reload_priv     server administration
shutdown       Shutdown_priv   server administration
process        Process_priv    server administration
file            File_priv               file access on server


select, insert, update, delete 권한은 데이터베이스의 테이블에서 레코드에 대한 오퍼레
이션을 할 수 있도록 허용한다.

SELECT 문은 오직 실제로 테이블에서 줄(레코드)를 가져올 때만 select 권한이 필요하다.
서버의 데이터베이스에 접근 권한이 없는 경우라고 하더라도 특정한 SELECT  문은 사용할
수 있다. 예를 들면 간단한 계산을 위해 mysql 클라이언트를 사용할 수 있다:

mysql> SELECT 1+1;
mysql> SELECT PI()*2;

index(인덱스) 권한은 인덱스를 생성하거나 제거할 수 있다.

alter 권한은 ALTER TABLE 을 사용할 수 있도록 한다.

create  와 drop 권한은 새로운 데이터베이스와 테이블을 생성하거나 존재하는 데이터베이
스와 테이블을 제거할 수 있도록 허용한다.

사용자에게 mysql 데이터베이스의 drop 권한을 허용하면, 그 사용자는 mysql 접근권한 정보
가 저장된 데이터베이스를 없앨 수 있다는것!을 명심하자.


grant 권한은 사용자가 가지고 있는 권한을 다른 사용자가 가질 수 있도록 허용한다.

file 권한은 LOAD DATA INFILE and SELECT ... INTO OUTFILE  문을 이용하여 서버에 파일을
저장하고 읽을 수 있는 권한을 허용한다. 이러한 권한을 가진 사용자는 mysql 서버가 읽고
쓸 수 있는 파일을 읽고 쓸 수 있는 권한이 허용된다.

나머지 권한들은 관리자 오퍼레이션에 사용되며 mysqladmin 프로그램의 기능을 수행한다.
아래의 테이블은 각 관리자 권한에 따라 사용할 수 있는 mysqladmin 명령을 보여준다:

Privilege              Commands permitted to privilege holders
(권한)          (권한에 따라 허용되는 명령)
reload         reload, refresh, flush-privileges, flush-hosts, flush-logs, flush-tab
les
shutdown       shutdown
process        processlist, kill


reload 명령은 서버가 grant 테이블을 다시 읽어 들인다. refresh 명령은 모든 열린 테이블
을 닫으며 로그 파일을 열고 닫는다. flush-privileges 는 reload 명령과 동의어이다. 다른
flush-* 명령은 refresh 와 비슷한 기능을 수행한다. 그러나 범위에 제한이 있으며 어떤 경
우에는 더 선택할 만하다. 예를 들어 로그 파일만 닫고 다시 열고자 한다면 flush-logs 가
refresh보다 더 나은 선택이다.
(** flush의 옵션으로는 호스트, 로그 파일, 권한 설정, 테이블, status variables 설정 변
수가 있다. SQL 문에서 또는 mysqladmin 유틸리티를 사용하면 된다. **)

shutdown 명령은 서버를 셧다운한다. (** 이거 번역 맞아~~?? **)

processlist 명령은 서버에서 실행되고 있는 스레드에 대한 정보를 보여준다. kill 명령은
서버 스레드를 죽인다. 언제나 자신의 스레드는 보거나 죽일 수 있지만 다른 사용자에 의해
시작된 스레드는 프로세스 권한이 있어야 보거나 죽일 수 있다.

몇가지 권한은 조심스럽게 허용해야 한다:y:

ㅇ grant(허용) 권한은 사용자가 다른 사용자의 권한을 설정할 수 있도록 허용한다. 다른
권한과 grant 권한을 가진 두 사용자는 권한을 결합할 수 있다.
ㅇ file 권한은 서버에서 모든 사람이 읽기 가능한 파일을 읽는데 남용 될 수 있.... SELEC
T  문을 이용해 접근할 수 있는 내용...
The file privilege can be abused to read any world-readable file on the server into a
database table, the contents of which can then be accessed using SELECT.
(** 굳이 권한을 주지 않아도 이용할 수 있는 것은 권한을 주지 않는게 낫다는 말이겠지요
**)
ㅇ shutdown 권한은 다른 사용자에가 완전히 서비스를 사용하지 못하도록 남용될 수 있다.
ㅇ  process 권한은 비밀번호를 설정하고 바꾸는 질의를 포함해 현재 수행하고 있는 질의를
보는데 사용될 수 있다.
ㅇ mysql 데이터베이스에 대한 권한은 비밀번호와 다른 접근 권한 정보를 바꾸는 데 사용될
수 있다. (비밀번호가 암호화되어 저장되었다고 하더라도, 충분한 권한을 가진 악의있는 사
용자는 다른 비밀번호롤 바꿀 수 있다)

mysql 권한 시스템으로 다룰 수  없는 몇가지가 있다:
ㅇ 접근을 거부할 사용자를 명백하게 지정할 수 없다. 왜냐하면 사용자와 연결을 거부하는
것을 완전하게 연관시킬 수 없기 때문이다.
ㅇ 사용자가 테이터베이스에서 테이블을 만들고 지울 수 있는 권한을 가질 수 있지만 데이
터베이스 자체를 만들고 삭제할 수는 없도록 지정할 수 없다.
(** 그러니까 create 와 drop 권한을 주면 데이터베이스 자체에 대해 제어할 수 있지요. 그
안의 테이블만 만들고 지울 수 있도록 하지는 못한다는 말 **)

{{}}
6.4 권한 시스템 작동 방법

mysql 권한 시스템은 모든 사용자가 허용된 것만큼만 할 수 있도록 보증한다. mysql 서버에
연결할 때, 사용자 확인은 연결한 호스트와 사용자가 지정한 사용자 이름에 의해 결정된다.
시스템은 사용자 확인과 지정한 권한에 따라 권한을 허용한다.


mysql은 사용자를 확인하는데 호스트이름과 사용자 이름 둘다 사용한다. 왜냐면 인터넷에서
이름이 같다고 같은 사용자라고 생각할 수는 없기 때문이다. 예를 들어 whitehouse.gov에서
접속하는 사용자 bill 은 microsoft.com에서 접속하는 사용자 bill 과 같은 사람일 필요는
없다. mysql은 때론 같은 이름을 가지고 있더라도 호스트를 이용해 사용자를 구별한다 : wh
itehouse.gov에서 접속하는 bill에게 특정한 권한을 허용할 수 있고 microsoft.com에서 접
속하는 bill에게 다른 권한을 허용할 수 있다.

mysql의 접근 제어는 두가지 단계가 있다:

단계 1: 서버에서 사용자가 연결할 수 있는지 없는지 판단

단계 2 (서버에 사용자가 연결이 허용되었을 경우) : 사용자가 수행하려는 명령에 대해 충
분한 권한이 있는지 각 요청마다 서버에서 판단.예를 들면, 데이터베이스의 테이블에서 sel
ect rows를 할때, 또는 데이터베이스에서 테이블을 제거할 때 서버에서 테이블에 대한 sele
ct 권한이 있는지 데이터베이스에 대한 제거 권한이 있는지 확인을 한다.



서버는 접근 제어의 각 두 단계에서 mysql 데이터베이스의 user, db, host 테이블을 이용한
다.grant 테이블의 필드는 아래와 같다:

Table name     user            db              host
Scope fields   Host            Host            Host
(필드 범위)     User            Db              Db
                Password                User
Privilege fields      Select_priv     Select_priv     Select_priv
(권한 필드)     Insert_priv     Insert_priv     Insert_priv
                Update_priv     Update_priv     Update_priv
                Delete_priv     Delete_priv     Delete_priv
                Index_priv      Index_priv      Index_priv
                Alter_priv      Alter_priv      Alter_priv
                Create_priv     Create_priv     Create_priv
                Drop_priv       Drop_priv       Drop_priv
                Grant_priv      Grant_priv      Grant_priv
                Reload_priv            
                Shutdown_priv          
                Process_priv           
                File_priv              


접권 제어의 두번째 단계를 위해(요청 인증), 요청이 테이블에 관계된 것이라면 추가적으로
tables_priv 와 columns_priv 테이블을 참고한다. 이 테이블의 필드는 다음과 같다:

Table name     tables_priv     columns_priv
Scope fields   Host            Host
                Db              Db
                User            User
                Table_name      Table_name
                                Column_name
Privilege fields      Table_priv      Type
                Column_priv    
Other fields   Timestamp       Timestamp
                Grantor




각 승인(grant) 테이블은 필드 범위와 권한 필드로 구성되어 있다.

필드 범위는 테이블에서 각 엔트리의 범위를 결정한다. 다시 말하면 엔트리가 적용되는 con
text(환경, 배경)이다. 예를 들면, Host 와 User 값이 'thomas.loc.gov' 와 'bob' 인 user
테이블 엔트리는 thomas.loc.gov 호스트에서 bob이 연결을 할때 서버에서 인증을 하는데 사
용된다.비슷하게 Host, User, db 필드값이  'thomas.loc.gov', 'bob', 'reports' 인 db 테
이블 엔트리는 thomas.loc.gov 호스트에서 bob 이 reports 데이터베이스에 접근할 때 사용
된다. tables_priv 와 columns_priv 테이블은 테이블이나 각 엔트리가 적용될 수 있는 테이
블/컬럼 조합을 가리키는 범위 필드를 포함하고 있다.

접권 체크를 하기 위해, HOst 값 비교는 대소문자를 구별하지 않는다. User, Password, Db,
Table_name 값은 대소문자를 구별한다. mysql 3.22.12 와  이후 버전에서 Column_name 값은
대소문자를 구별하지 않는다. (3.22.11에서는 대소문자 구별함)

권한 필드는 테이블 엔트리에 승인되는 권한을 가리키며 이는 수행할 수 있는 오페레이션이
다. 서버는 사용자의 권한을 완벽하게 설정하기 위해 다양한 승인(grant) 테이블의 정보를
조합한다. 여기에 사용하는 규칙은 6.6 [Request access]를 참고하자.

범위 필드는 문자열이며 다음과 같이 정의되었다; 기본 값은 빈 문자열이다:

Field name     Type   
Host            CHAR(60)       
User            CHAR(16)       
Password                CHAR(16)       
Db              CHAR(64)      (CHAR(60) for the tables_priv and columns_priv tables)



user, db, host 테이블에서 모든 권한 필드는 ENUM('N','Y')로 정의되어 있다. -- 각각은
'N' 나 'Y'의 값을 가지며 기본값은 'N' 이다.
(** ENUM 타입은 목록 값중 오직 하나의 값만 가진다.필드 타입 참조 **)

tables_priv 와 columns_priv 테이블에서 권한 필드는 SET 필드로 정의된다:
(** SET 타입은 목록 값중에 0이나 1개 이상의 값을 가진다 **)

Table name     Field name     Possible set elements
tables_priv     Table_priv      'Select', 'Insert', 'Update',
                                'Delete', 'Create', 'Drop', 'Grant',
                                'References', 'Index', 'Alter'
tables_priv     Column_priv     'Select', 'Insert', 'Update',
                                'References'
columns_priv    Type            'Select', 'Insert', 'Update',
                                'References'

간단하게 말해서 서버는 승인(grant) 테이블을 다음과 같이 사용한다:

ㅇ user 테이블의 scope(범위) 필드는 들어오는 연결에 대해 허용할 것인지 거부할 것인지
를 결정한다. 허용된 연결에 대하여, 권한 필드는 사용자의 전체적인 (superuser) 권한을
가리킨다.

ㅇ db 와 host 테이블은 함께 사용된다:
        - db 테이블의 범위 필드는 어떤 호스트에서 어떤 데이터베이스에 대해 어떤 사용
자가 접근할 수 있는지 결정한다. 권한 필드는 어떤 오퍼레이션이 허용되었는지를 결정한
다.
        - host 테이블은 db 테이블의 엔트리를 여러개의 호스트에 적용하려고 할 때 db 테
이블의 확장을 위해 사용한다.예를 들어, 사용자가 현재 네트웍의 여러 호스트에서 데이터
베이스를 사용할 수 있도록 하려면,사용자의 "db" 테이블 엔트리에 Host 값을 비워두고, "h
ost" 테이블에 각 호스트의 엔트리를 넣으면 된다.이러한 절차는 6,6 [Request access]에
자세하게 나와 있다.

ㅇ tables_priv 와 columns_priv 테이블은 db 테이블과 비슷하다. 그렇지만 더 세부적으로
지정할 수 있다: 이 테이블들은 데이터베이스 단계에서 더 나아가 테이블과 컬럼 단계에 적
용할 수 있다.

관리 권한(reload, shutdown,기타..)은 오직 user 테이블에서만 지정을 할 수 있다는 것을
기억하자! 왜냐면 관리자 오퍼레이션은 서버 자체에 대한 오퍼레이션이며 특정한 데이터베
이스를 지정하는 것이 아니다. 그러므로 이러한 권한은 다른 승인(grant) 테이블에 있을 필
요가 없다.실제로, 오직 user 테이블만이 관리자 오퍼레이션을 수행할 수 있는지 없는지를
결정할 때 참고가 된다.

파일(file) 권한도 마찬가지로 user 테이블에서만 지정한다.위와 같은 관리 권한은 아니다.
그렇지만 서버 호스트에서 파일을 읽거나 쓸 수 있는 권한은 접근하고 있는 데이터베이스와
무관한 것이다.

mysqld 서버는 시작할 때 승인(grant) 테이블을 한번 읽는다. 승인 테이블을 변경하고 효과
를 발휘하려면 6.7 [Privilege changes]를 참고하자.

승인 테이블의 내용을 수정했을 때 원하는대로 권한이 설정되었는지 확인하는 것은 좋은 생
각이다. 유용한 진단 프로그램은 mysqlaccess 스크립트로서 Yves CArlier 가 mysql distrib
ution 으로 제공하고 있다. 어떻게 작동하고 있는지 확인하기 위해 mysqlaccess 에 --help
옵션을 주어 실행해보자. 물론 6.11 [Access denied] 와 6.12 [Security]를 참고하자.


mysqlaccess는 오직 user, db, host 테이블만 점검한다. 테이블이나 컬럼 단계의 권한까지
는 점검하지 않는다는 것을 기억하자.

6.5 접근 제어, 단계 1 : 연결 확인(인증)

mysql 서버에 접속하려고 할 때 서버는 사용자 확인과 비밀번호를 통해 접속을 허용하거나
거부한다. 사용자 확인이 안되면 서버는 접속을 완전히 거부한다. 사용자 확인이 되면 서버
는 연결을 받아들이고 2번째 단계로 들어가며 요청을 기다린다.

사용자 확인은 두가지 정보에 기반하고 있다:

ㅇ 접속하는 호스트
ㅇ mysql 사용자 이름

사용자 확인은 user 테이블의 세가지 범위 필드(Host, User, Password)를 사용하여 수행된
다. 서버는 user 테이블 엔트리의 호스트이름과 사용자 이름이 맞으며, 비밀번호가 정확할
때만 접속을 받아들인다.

아래와 같이 user 테이블의 범위 필드값을 지정할 수 있다:

ㅇ Host 값은 호스트 이름이나 IP 숫자 또는 로컬 호스트를 가리키는 'localhost' 가 될 것
이다.
ㅇ Host 필드에서 '%' 와 '_' 의 와일드카드 문자를 사용할 수 있다.
ㅇ '%'의 Host 값은 모든 호스트 이름을 나타낸다. 공백의 호스트 값은 '%'와 같다. 특정한
호스트에 대한 이러한 값은 당신의 서버에 연결할 수 있다는 것을 참고하자.
ㅇ 와일드카드 문자는 User 필드에는 허용되지 않는다. 그렇지만 모든 유저에 해당하는 공
백으로 둘 수 있다. 연결을 하려는 목록에 공백 사용자 이름이 있다면 클라이언트에서 실제
로 지정한 이름 대신에 그 사용자는 익명 사용자, 이름이 없는 사용자로서 간주된다.
ㅇ Password 필드는 공백으로 될 수 있다.이것은 아무런 비밀번호나 사용할 수 있다는 것을
의미하는 것은 아니며 사용자는 비밀번호를 지정하지 않고 연결을 해야 한다는 의미이다.

아래의 테이블은 연결 요청에 적용하는 "user" 테이블 목록의 Host, User 값이 어떻게 조합
되는지를 보여주는 예제이다:

호스트값/사용자 값 : 목록에 해당하는 연결
'thomas.loc.gov'/'fred' : thomas.loc.gov 에서 연결하는 fred
'thomas.loc.gov'/'' : thomas.loc.gov 에서 연결하는 모든 사용자
'%'/'fred' : 모든 호스트에서 연결하는 fred
'%'/'' : 모든 호스트에서 연결하는 모든 사용자
'%.loc.gov'/'fred' : loc.gov 도메인의 모든 호스트에서 연결하는 fred
'x.y.%'/'fred' : x.y.net, x.y.com, x.y.edu 등에서 접속하는 fred (이것은 아마도 유용하
지 않을 것이다)
'144.155.166.177'/'fred' : 144.155.166.177의 IP 주소에서 접속하는 fred
'144.155.166.%'/'fred' : 144.155.166 클래스 C 서브넷의 모든 호스트에서 접속하는 fred


Host 필드에서 IP에 와일드 카드를 사용할 수 있기 때문에(예를 들어 '144.155.166.%' 는
서브넷의 모든 호스트에 적용된다) 144.155.166.somewhere 와 같은 호스트 이름을 이용하여
부당하게 이용할 가능성이 생길 수 있다. 이러한 것을 막기 위해 mysql은 숫자와 도트(.)으
로 시작하는 호스트이름은 허용하지 않는다. 1.2.foo.com 과 같은 호스트라면 이러한 호스
트이름은 승인(grant) 테이블의 Host 컬럼과 매치되지 않는다. IP 숫자만이 IP 와일드 카드
값과 매치시킬 수 있다.

만약 한개 이상의 user table 목록이 있다면 서버는 어떻게 user table을 선택할까? 이런
경우에는 user table의 정렬 순서에 따라 해결을 하며 , 정열은 서버가 시작할때 수행이 된
다. user table이 다음과 같다고 가정해보자:


+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-



서버가 테이블을 읽을 때, 먼저 특정하게 지정된 값이 있는 호스트부터 목록을 정열한다.
(Host 컬럼에서 '%'는 "모든 호스트"를 의미하여 최소한도로 지정하는 것이다) 목록에서 호
스트값이 같으면 먼저 특정하게 지정된 사용자가 있는 것부터 정열한다.(공백으로 되어 있
는 User 값은 "모든 사용자"를 의미하여 최소한도로 지정하는 것이다.) 이렇게 하면 정열된
user 테이블은 다음과 같다:



+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-


정열된 순서에 따라 매칭 알고리즘이 적용되며 먼저 매칭되는 것을 사용한다. localhost에
서 jeffrey가 연결을 하려할때, Host 컬럼에서 'localhost' 목록이 먼저 매칭된다. 물론 사
용자 이름이 공백인 목록은 연결하는 호스트네임과 사용자 이름에 매칭된다. ('%'/'jeffrey
' 목록 또한 매칭이 된다. 그러나 테이블에서 처음으로 매칭되는 것은 아니다.)


다른 예제가 있다. user 테이블이 다음과 같다고 가정해보자:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| thomas.loc.gov |          | ...
+----------------+----------+-


정열된 테이블은 다음과 같다:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| thomas.loc.gov |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

첫번째로 thomas.loc.gov에서 jeffrey가 연결하는 것이 매칭되며, whitehouse.gov 에서 jef
frey가 연결하는 거은 두번째로 매칭이 된다.

서버에 연결할 때 문제가 생기면, user 테이블을 출력하여 어떤 것이 먼저 매칭되는지 직접
정열을 하면 된다.


6.6 접근 제어, 2단계 : 요청 인증

{{}}연결되었다면 서버는 2단계로 들어간다. 연결이 성사되었을 때 각 요구에 대해 사용자가 수
행하려는 연산의 유형에 기반하여 서버는 사용자가 충분한 권한을 가지고 있는지 점검한다.
여기서 승인 테이블의 권한 필드가 작동한다. 권한은 user, db, host, table_priv, columns
_priv 테이블의 정보를 사용한다. GRANT 와 REVOKE 명령을 이용하여 권한 테이블을 다룰 수
있다. 7.25 [GRANT] 참고. (이전에 보았던 각 권한 테이블의 필드 목록을 참고하는 것이 도
움이 될 것이다; 6.4[Privilege] 참고.)

user 테이블의 승인 권한은 사용자에게 전체적인 기반을 제공하며 현재의 데이터가 어떤 것
인지와는 상관이 없다. 예를 들어, user 테이블에서 사용자에게 delete 권한을 승인했다면
서버 호스트에서 어떤 데이터베이스의 레코드라도 삭제할 수 있다! 다르게 말해서 user 테
이블 권한은 슈퍼유저 권한이며, 슈퍼유저(서버나 데이터베이스 관리자 등)에게만 user 테
이블에 대한 권한을 승인하는 것이 좋다. 다른 사용자에게는 user 테이블에서 권한을 'N'로
설정하고, db와 host 테이블을 사용하여 특정 데이터베이스에 기반한 권한승인을 하는게 좋
다.

db 와 host 테이블은 특정 데이터베이스의 권한을 승인한다. 각 테이블의 Host 와 Db 필드
에서 와일드카드 문자 '%' 와 '_' 를 사용할 수 있으며 값이 공백이면 필드 범위(scope fie
lds)에서 모든 값을 허용한다. '%' Host 값은 "모든 호스트"를 의미한다. db 테이블에서 Ho
st 값이 공백이면 "host 테이블에서 더 자세한 정보를 문의하라"는 의미이다. A '%' or bla
nk Db value in the host table means or "any database." (** or의 뜻이 무엇인지 모르겠
네요. host 테이블에서 Db 의 값이 '%' 또는 공백이면 "모든 데이터베이스"를 의미한다는
말 같은데요 **) User 값이 공백이면 익명 사용자로 간주된다.

서버가 시작할 때 db 와 host 테이블을 읽고 정열을 한다.(동시에 user 테이블을 읽는다.)
db 테이블은 Host, Db, User 순으로 필드 범위를 정열하며 host 테이블은 Host, Db 순으로
필드 범위를 정열한다. user 테이블과 같이 특정하게 지정되어 있는 값이 먼저 정열되고 최
소한도로 지정된 값이 나중에 정열된다. 서버에서 매칭되는 목록을 찾을때, 가장 먼저 발견
한 것을 사용한다.

tables_priv 와 columns_priv 테이블은 특정한 테이블과 컬럼에 관련된 권한을 승인한다.d
b와 host 테이블의 Host 필드와 같이 와일드카드를 Host 필드에서 사용할 수 있다. 그렇지
만 Db, Table_name, Column_name 필드에서는 와일드카드나 공백값을 사용할 수 없다.

Host 테이블에서만 와일드카드를 사용할 수 있지만 tables_priv 와 columns_priv 테이블은
db 테이블과 비슷하게 정열이 되며 정열은 간단하다.

요청 인증 과정은 아래에서 설명한다. 접근-점검 소스 코드에 친숙하다면, 여기서 설명하는
것은 코드에서 사용된 알고리즘과는 약간 다르다는 것을 알 수 있다.여기서의 설명은 코드
가 실제로 작동하는 방식과 동일하다. 단지 설명을 간단하게 하는데서 차이가 있는 것이다.

관리자 요청에 대해서(shutdown, reload 등) 서버는 단지 user 테이블만 체크를 한다. 왜냐
면 user 테이블에서만 관리자 권한을 지정하기 때문이다. 목록에서 요청된 연산을 허용하면
접근이 허용되며 아닌 경우에는 접근이 거부된다.예를 들어, mysqladmin shutdown을 실행하
고자 하는데 user 테이블 목록에서는 사용자에게 shutdown 권한을 승인하지 않으면, db나 h
ost 테이블을 체크하지 않더라도 접근이 거부된다. (이러한 테이블에는 Shutdown_priv 컬럼
이 없기 때문에 이렇게 할 필요도 없다)

데이터베이스와 관련된 요청에 대해(insert, update 등) 서버는 먼저 user 테이블 목록에서
사용자의 전체(슈퍼유저) 권한을 점검한다. 목록에서 요청한 연산을 허용하면 접근이 승인
된다.

user 테이블에서 전체적인 권한이 불충분하면, 서버는 db 와 host 테이블을 점검하여 데이
터베이스에 관련된 권한을 결정한다:

1. 서버는 db 테이블에서 매칭되는 Host, Db, User 필드를 찾는다. 연결하려는 사용자의 호
스트 이름과 Mysql 사용자 이름이 Host 와 User에 매칭되다. 사용자가 접근하기 원하는 데
이터베이스는 Db 필드에 매칭된다. 적합한 Host 와 User 목록이 없으면 접근은 거부된다.

2. 매칭되는 db 테이블 목록이 있고 Host 필드가 공백이 아니면, 목록은 사용자의 데이터베
이스 관련 권한을 정의한다.


3. 매칭되는 db 테이블 목록의 Host 필드가 공백이면, host 테이블에서 어떤 호스트가 데이
터베이스에 접근할 수 있는지 판단한다는 것을 의미한다. 이런 경우, 더 자세한 정보를 위
해 host 테이블에서 매칭되는 Host 와 Db 필드를 찾는다. host 테이블에 매칭되는 목록이
없으면 접근은 거부된다. 매칭되는 목록이 있으면 사용자의 데이터베이스 관련 권한은 db
와 host 테이블 목록에서 권한을 intersection 하여 결정된다.(** insertection은 교집합을
생각하면 되지요. and 조건 **) 다시 말해서, db와 host 테이블 둘 다 'Y'로 되어있을 때
권한이 설정된다.이러한 방법으로 db 테이블에서 일반적인 권한을 승인할 수 있으며, 그러
고나서 host 테이블 목록을 사용해 host를 기반으로 하여 선택적으로 권한을 제한할 수 있
다.)

db 와 host 테이블 목록을 이용해 데이터베이스와 관련된 권한 승인을 결정한 후, 서버는
이러한 정보를 user 테이블에서 승인한 전체적인 권한에 추가한다. 그 결과가 요청한 연산
을 허용하면 접근이 허용된다. 다른 방법으로, 서버는 tables_priv 와 columns_priv 테이블
에서 사용자의 테이블과 컬럼 권한을 점검하고 사용자의 권한에 추가한다. 그 결과에 따라
접근이 허용되거나 거부된다.

왜 서버에서 전체적인 사용자 엔트리 권한에 데이터베이스, 테이블, 컬럼에 관련된 권한을
추가하는지가 명확하지 않다.... 이런 경우 사용자 권한은 초기에 요청된 연산에 대하여 불
충분하다... (It may not be apparent why the server adds the database-, table- and col
umn-specific privileges to the global user entry privileges for those cases in which
the user privileges are initially found to be insufficient for the requested operatio
n.) 요청은 한가지 유형 이상의 권한이 필요하기 때문이다. 예를 들어, INSERT ... SELECT
문을 수행할 때 insert 와 select 권한 둘 다 필요하다. 사용자의 권한은 user 테이블에서
한가지 권한을 승인하고 db 테이블 엔트리에서 다른 권한을 승인할 것이다. 이런 경우, 사
용자는 이러한 요청을 수행하기 위해 필요한 권한을 가지고 있다. 그렇지만 서버는 자체적
으로 다른 테이블에 대해서는 .....(In this case, you have the necessary privileges to
perform the request, but the server cannot tell that from either table by itself;) ;
두 엔트리에 의해 승인된 권한이 조합되어야 한다.

host 테이블은 "안전한" 서버 목록을 유지하는데 사용할 수 있다. TcX에서는, host 테이블
에는 지역 네트웍의 모든 시스템이 포함되어 있다. 여기서는 모든 권한이 허용된다.

안전하지 않는 호스트를 가리키기 위해 host 테이블을 사용할 수 있다. 안전하다고 생각되
지 않는 공개 지역에 위치한 public.your.domain 시스템이 있다고 가정해보자. 사용자는 사
용자 네트웍의 모든 호스트에 접근할 수 있으며, host 테이블 엔트리가 다음과 같은 시스템
만 제외한다 :

+--------------------+----+-
| Host               | Db | ...
+--------------------+----+-
| public.your.domain | %  | ... (all privileges set to 'N')
| %.your.domain      | %  | ... (all privileges set to 'Y')
+--------------------+----+-

당연히 접근 권한이 원하는대로 되어 있는지 언제나 승인 테이블에서 목록을 테스팅해야 한
다. (예를 들어 mysqlaccess 를 사용)



6.7 권한 변경시 적용 방법


mysqld 가 시작할 때, 모든 승인 테이블 내용이 메모리로 올라가고 이때부터 유효하게 된
다.

GRANT, REVOKE, SET PASSWORD 를 이용해 승인 테이블에 변경을 하면 바로 서버에서 인식을
한다.

권한 테이블을 직접 변경했다면(INSERT, UPDATE 등을 사용하여), 서버에서 승인 테이블을
재가동하도록 하기 위해 FLUSH PRIVIEGES 문이나 mysqladmin flush-privileges 를 실행해야
한다.그렇게 하지 않으면 서버를 다시 시작하기 전까지 변경된 권한이 적용되지 않는다.

서버에서 권한 테이블이 변경되었다는 것을 감지했을 때, 이미 존재하던 클라이언트 연결은
다음과 같이 영향을 받는다:

1. 테이블과 컬럼 권한 변경은 클라이언트의 다음 요청부터 적용된다.
2. 데이터베이스 권한 변경은 다음의 USE db_name 명령부터 적용된다.
3. 전체적인 권한과 비밀번호 변경은 클라이언트가 다음에 연결할 때부터 적용된다.
{{}}

6.8 초기 mysql 권한설정

mysql을 설치하고 나서, mysql_install_db 스크립트를 실행해서 초기 접근 권한을 설정해야
한다. 4.7.1 [Quick install] 참고. mysql_install_db 스크립트는 mysqld 서버를 시작하고,
다음과 같이 승인 테이블의 권한을 초기화한다:

- mysql root 사용자는 슈퍼유저이며 모든 것을 할 수 있다. 로컬 호스트에서만 연결할 수
있다.
주의 : 처음에 root 비밀번호는 비어있다. 그래서 누구나 비밀번호없이 root로 연결할 수있
고 모든 권한을 승인받는다.

- 익명 사용자는 'test' 나 'test_' 로 시작하는 데이터베이스에 대한 모든 권한을 승인받
는다. 모든 사용자가 로컬 호스트에서 연결할 수 있으며 익명 사용자로 간주된다.

- 다른 권한은 거부된다. 예를 들어 일반 사용자는 mysqladmin shutdown 이나 mysqladmin p
rocesslist 를 사용할 수 없다.


설치했을 때 초기 권한이 폭넓게  설정되어 있기 때문에 가장 먼저 mysql root 사용자의 비
밀번호를 설정해야 한다. 다음과 같이 설정하면 된다. (PASSWORD() 함수를 이용해 비밀번호
를 설정해야 한다!):

shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
           WHERE user='root';
mysql> FLUSH PRIVILEGES;

or

shell> mysqladmin -u root password new_password
(** PASSWORD() 라는 함수를 사용하지 않아도 되므로 편리함. 또한 SQL문에서 grant 명령을
이용해 설정할 수도 있지요 **)

첫번째 방법을 사용하면 직접 user 테이블의 비밀번호를 업데이트한다. 이경우 서버가 다시
승인 테이블을 읽도록 해야 한다.(FLUSH PRIVILEGES 사용). 왜냐하면 다른 방법으로는 변경
사항을 알릴 수 없기 때문이다.

(** 승인 테이블을 다시 읽지 않아서 이전에 설정했던 비밀번호가 제대로 안되는 경우가 있
을 것입니다. 꼭 기억하고 있어야해요 **)

root 비밀번호가 설정되었으면 서버에 root로 접속할때마다 비밀번호를 명시해야 한다.

추가로 셋업을 하거나 테스트할 때는 비밀번호를 설정할 필요가 없기 때문에 root 비밀번호
를 빈값으로 남겨두고 싶을 것이다. 그렇지만 실제 작업을 하기 전에는 반드시 비밀번호를
설정했는지 확인해야 한다.

기본권한을 어떻게 설정하는지 mysql_install_db 스크립트를 살펴보자. 다른 사용자에게 권
한을 어떻게 설정할지 이것을 기본으로 사용할 수 있다.

위에서 설명한 것과 다르게 초기 권한을 설정하기 원하면, mysql_install_db 스크립트를 실
행하기 전에 수정하면 된다.

완전하게 승인 테이블을 다시 만들기 위해 mysql 데이터베이스를 포함하는 디렉토리의 '*IS
M' 과 '*.ISD' 파일을 제거해야 한다. (이 디렉토리는 database 디렉토리에서 'mysq''이라
는 이름이 붙어있다. mysqld --help 해서 database 디렉토리의 목록을 볼 수 있다.) 원하는
대로 권한을 수정한 후 mysql_install_db 스크립트를 실행하자.


6.9 mysql에 새로운 사용자 권한 추가하기

두가지 방법으로 사용자를 추가할 수 있다 : GRANT 문 사용 또는 mysql 승인 테이블 직접
조작. GRANT 문을 사용하는 것이 더 선호되는 방법이다.

아래의 예제는 새로운 사용자를 설정하기 위해 어떻게 mysql 클라이언트를 사용하는지 보여
준다. 이 예제는 이전에 설명했던것과 같이 기본값에 따라 권한을 설정하는 것으로 가정한
다. 이것은 설정을 바꾸기 위해 mysqld가 실행되고 있는 같은 시스템에 있어야 한다는 것을
말한다. (**초기값은 localhost에서만 접속 가능하므로**) 또한 mysql root 사용자로 접속
해야 하고 root 사용자는 mysql 데이터베이스에 대한 insert 권한과 reload 관리자 권한이
있어야 한다. root 사용자의 비밀번호를 바꾸었으면, 아래와 같이 mysql 명령행 상태에서
비밀번호를 명시해야 한다.

GRANT 문을 이용해 새로운 사용자를 추가할 수 있다:

shell> mysql --user=root mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
           IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%"
           IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
mysql> GRANT USAGE ON *.* TO dummy@localhost;

위 GRANT 문에서는 세 명의 사용자를 설정한다:

monty : 어느 곳에서든 서버에 연결할 수 있는 완전한 슈퍼유저이지만 비밀번호를 사용해야
한다. 우리는 monty@localhost 와 monty@"%"를 사용한 GRANT 문에 대해서 반드시 논의를 해
야 한다. localhost 목록을 추가하지 않으면, mysql_install_db 에 의해 생성된 localhost
의 익명 사용자 목록(등록?)이 로컬 호스트에서 접속할때 우선권을 갖는다. 왜냐하면 지정
된 Host 필드 값이 있으며 정열 순서에서 먼저 오기 때문이다. (** 승인 테이블의 정열 순
서가 특정한 Host를 지정한 것부터 시작하는 것을 기억하자.

admin : 비밀번호 없이 localhost에서 접속할 수 있으며 reload와 process 관리자 권한을
승인받은 사용자. 이경우 사용자가 mysqladmin processlist 뿐만 아니라 mysqladmin reloa
d, mysqladmin refresh, mysqladmin flush-* 명령을 실행할 수 있다.데이터베이스와 관련된
권한은 승인되지 않았다. 이것은 추가적인 GRANT 문을 사용해 나중에 승인할 수 있다.

dummy : 비밀번호없이 연결할 수 있지만 오직 localhost에서만 연결 가능한 사용자. 권한
유형(privilege type)이 USAGE 이기 때문에 전체적인 권한이 'N'로 설정되어 있다. USAGE
는 아무런 권한도 설정하지 않는다. 나중에 데이터베이스와 관련된 권한을 승인할 수 있다.

또한 동일한 사용자 접근 정보를 INSERT 문을 통해 직접 추가할 수 있으며 이경우에는 서버
가 승인 테이블을 다시 읽도록 알려주어야 한다.(**FLUSH PRIVILEGES 사용**)

shell> mysql --user=root mysql
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('something'),
                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),
                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user SET Host='localhost',User='admin',
                 Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
                        VALUES('localhost','dummy',");
mysql> FLUSH PRIVILEGES;

mysql 버전에 따라 위에서 'Y' 값이 다를 수 있다는 것을 기억하자. 3.22.11 버전 이후에서
사용할 수 있는 확장된 INSERT 문은 여기서 admin 사용자에게 사용되었다.

슈퍼유저를 설정하기 위해 권한필드를 'Y'로 한 user 테이블 목록만 만들면 된다는 것을 기
억하자. db 나 host 테이블 목록은 필요없다. (** 관리자 권한은 db나 host 테이블과는 전
혀 관련이 없다. db는 접속할 수 있는 데이터베이스에 대해 상세하게 설정하고 host 테이블
은 db테이블을 좀 더 정교하게 설정하기 위해 필요한 것이다. 관리자 권한은 오직 user 테
이블만 관련되어있다 **)

마지막 INSERT 문(dummy 사용자)에서는 user 테이블의 권한 컬럼이 명확하게 설정되지 않았
다. 왜냐면 이 컬럼의 기본값은 'N'로 되어 있기 때문이다.

다음의 예제에서는 custom 이라는 사용자를 추가한다. custom은 localhost, server.domain,
whitehouse.gov에서 접속할 수 있다. localhost에서는 bankaccount 데이터베이스에만 접속
할 수 있으며 whitehouse.gov에서는 expenses 데이터베이스에, 모든 세 호스트상에서는 cus
tomer 데이터베이스에 접속하길 원한다. 모든 세 호스트상에서 stupid라는 비밀번호를 사용
하길 원한다.

GRANT 문을 이용 이러한 사용자 권한을 설정하기 위해 다음의 명령을 실행하자:

shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON bankaccount.*
           TO custom@localhost
           IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON expenses.*
           TO custom@whitehouse.gov
           IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON customer.*
           TO custom@'%'
           IDENTIFIED BY 'stupid';

승인 테이블을 직접 수정해 사용자 권한을 설정하려면 다음의 명령을 사용하자. (마지막에
FLUSH PRIVILEGES 를 사용해야 한다는 것을 기억하자):

shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES('localhost','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
       VALUES('server.domain','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
       VALUES('whitehouse.gov','custom',PASSWORD('stupid'));
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       ('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       ('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;
~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~

처음의 세가지 INSERT 문은 custom 사용자가 비밀번호를 사용하여 다양한 호스트에서 접속
할 수 있도록 user 테이블 목록을 추가한다. 그렇지만 그에게 어떠한 퍼미션도 승인하지 않
는다. (모든 권한은 기본값으로 'N' 이다) 다음의 세가지 INSERT 문은 적절한 호스트에서
접속을 할 때, custom 에게 bankaccount, expenses, customer 데이터베이스에 대한 권한을
승인하는 db 테이블 목록을 추가한다. 일반적으로 승인 테이블을 직접 수정하였으면, 변경
된 권한을 적용하기 위해 서버가 승인 테이블을 다시 읽도록 해 주어야 한다.

특정한 사용자가 특정한 도메인의 시스템에서 접속할 수 있도록 설정하고자 한다면, 다음과
같이 GRANT 문을 설정할 수 있다:

mysql> GRANT ...
           ON *.*
           TO myusername@"%.mydomainname.com"
           IDENTIFIED BY 'mypassword';

승인 테이블을 직접 수정하려면 다음과 같이 한다:

mysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername',
           PASSWORD('mypassword'),...);
mysql> FLUSH PRIVILEGES;
~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~

승인 테이블을 다루기 위해 xmysqladmin, mysql_webadmin, xmysql 프로그램을 사용할 수 있
다. http://www.mysql.com/Contrib 에서 이러한 유틸리티를 찾을 수 있다.


6.10 비밀번호 설정 방법

앞의 예제는 중요한 원칙을 보여준다 : INSERT 나 UPDATE 문에서 공백이 아닌 비밀번호를
저장할 때 반드시 암호화하기 위해 PASSWORD() 함수를 사용해야 한다!! user 테이블은 비밀
번호를 플레인텍스트(**일반 텍스트 파일**)가 아니라 암호화된 형태로 저장하기 때문이다.
이러한 사실을 잊어버리면 다음과 같이 비밀번호를 설정하려고 할 것이다:

shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES('%','jeffrey','bLa81m0');
mysql> FLUSH PRIVILEGES;

플레인텍스트 값 'bLa81m0' 은 user 테이블에 비밀번호로 저장이 된다.jeffrey라는 사용자
가 이 비밀번호를 사용해 서버에 연결하려고 할 때 mysql 클라이언트를 이 비밀번호를 암호
화해서 그 결과를 서버로 보낸다. 서버는 암호화된 비밀번호('bLa81m0'이 아니다)를 user
테이블의 비밀번호(플레인텍스트 'bLa81m0' 값이다)와 비교한다. 비교는 실패하고 서버는
연결을 거부한다:

shell> mysql -u jeffrey -pbLa81m0 test
Access denied

비밀번호는 user 테이블에 입력될 때 반드시 암호화되어야 하기 때문에, INSERT 문은 다음
과 같이 사용해야 한다:

mysql> INSERT INTO user (Host,User,Password)
       VALUES('%','jeffrey',PASSWORD('bLa81m0'));

또한 SET PASSWORD 문을 사용할 때도 PASSWORD() 함수를 사용해야 한다:

mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('bLa81m0');

참고 : PASSWORD() 함수는 비밀번호 암호화를 수행한다. 그렇지만 유닉스에서 비밀번호를
암호화하는 방법과는 다르다. 유닉스 비밀번호와 mysql 비밀번호가 동일할 때 PASSWORD()
가 유닉스 비밀번호 파일(** /etc/passwd 파일 **)에 암호화되어 저장된 값과 같다고 생각
하면 안 된다.

GRANT ... IDENTIFIED BY 문이나 mysqladmin password 명령을 사용해 비밀번호를 설정하면
PASSWORD() 함수는 필요없다. 둘다 비밀번호를 암호화해서 저장한다:

mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'bLa81m0';
shell> mysqladmin -u jeffrey password bLa81m0

(** 당근, GRANT 문이나 mysqladmin password 명령을 사용하는게 편하겠지요? mysql의 암호
화 알고리즘이 유닉스와 다르듯 유닉스 계정과 mysql의 사용자는 전혀 다르다는 것도 다시
한번 기억하고 있어야 합니다.**)



6.11 접근 거부 에러가 나는 이유

mysql 서버에 연결하려 할 때 접근 거부 에러가 나면, 아래에서 설명하는 것에 따라 해결
방법을 찾을 수 있다:

- 초기 승인 테이블 내용을 설정하기 위해 mysql을 설치한 후 mysql_install_db 스크립트를
실행하였는가? 실행하지 않았다면 스크립트를 실행하자. 6.8 [Default privileges] 참고.
다음 명령을 이용해 초기 권한을 시험해 볼 수 있다:

        shell> mysql -u root test

에러없이 서버에 접속할 수 있을 것이다. mysql 데이터베이스 디렉토리에 'user.ISD' 파일
이 있는지 확인해보아야 한다. (일반적으로 'mysql 설치 디렉토리/var/mysql/user.IDS' 이
다)

- 설치를 새로하고 난후 , 서버에 연결하고 사용자와 접근 권한을 설정해야 한다:

        shell> mysql -u root mysql

초기에 mysql root 사용자만 비밀번호가 없기 때문에 서버에 연결할 수 있다. 보안문제가
있기 때문에, 다른 mysql 사용자를 설정하기 전에 먼저 root의 비밀번호를 설정해야 한다.
root로 접속하려하는데 다음의 에러가 났다고 가정하자:

        Access denied for user: '@unknown' to database mysql

이것은 user 테이블에 User 컬럼 = root 라는 목록이 없고, mysqld가 사용자 클라이언트의
호스트이름을 해석할 수 없다는 것을 의미한다. 이런 경우 --skip-grant-tables 옵션을 이
용해 서버를 다시 시작해야 하고 '/etc/hosts' 를 편집하거나 '\windows\hosts' 파일에 사
용자 호스트 목록을 추가해야 한다.

- 3.22.11 이전 버전에서 3.22.11이나 이후 버전으로 업데이트했다면, mysql_fix_privilege
_tables 스크립트를 실행했는가? 하지 않았다면 실행하자. mysql 3.22.11에서 GRANT 문 기
능이 가능해지면서 승인 테이블 구조가 바뀌었다.

- (INSERT 나 UPDATE 문을 사용해) 승인 테이블을 직접 고쳤고 변화가 아직 반영되지 않은
것으로 보이면, FLUSH PRIVILEGES 문을 사용하거나 mysqladmin flush-privileges 명령을 사
용해 서버가 승인 테이블을 다시 읽도록 해야 한다는 것을 기억하자.그렇지 않으면 서버가
재시작하기 전까지는 변화된 것이 반영되지 않는다. root 비밀번호를 설정하고 나서 권한을
flush 하기까지는 비밀번호를 명시할 필요가 없다. 왜냐면 서버는 아직 비밀번호를 바꾸었
는지 모르기 때문이다.

- 세션 중간에 권한이 변경된 것으로 보이면 슈퍼유저가 바꾸었을 것이다. 승인 테이블을
재시작하는 것은 새로운 클라이언트 접속에 영향을 미치지만 이미 존재하고 있던 연결은 6.
7 [Privileges changes]에서 설명한대로 영향을 미친다.

- 시험하기 위해, mysqld 대몬에  --skip-grant-tables 옵션을 주어 시작하자. 그러고나서
mysql 승인 테이블을 변경할 수 있고 변경된것이 원하는대로 작동하는지를 체크하는 mysqla
ccess 스크립트를 사용할 수 있다. 원하는대로 수정이 되었으면 mysqld 서버가 새로운 승인
테이블로 시작할 있도록 mysq1admin flush-priveleges 를 실행한다.
주의 : 승인테이블을 재로딩하는 것은 --skip-grant-tables 옵션을 무효화한다. 이를 통해
서버를 다운시키고 다시 재시작하지 않고도 승인 테이블을 시작할 수 있다.

- 펄, Python, ODBC 프로그램에서 접근하는데 문제가 있다면, mysql -u user_name db_name 
또는 mysql -u user_name -pyour_pass db_name 으로 서버에 접속을 시도해보자. (-p 와 비
밀번호사이에는 공백이 없다는 것을 기억하자. 또한 --password=your_pass 형태로도 사용할
수 있다) mysql 클라이언트로 접속이 되면 프로그램에 문제가 있는 것이며 접근 권한에는
문제가 없다.

- 비밀번호가 제대로 작동하지 않으면, INSERT, UPDATE, SET PASSWORD 문에서 비밀번호를
설정하면서 PASSWORD() 함수를 반드시 사용해야 한다는 것을 기억하자. PASSWORD() 함수는
GRANT ... INDENTIFIED BY 문이나 mysqladmin password 명령을 사용했다면 불필요하다. 6.1
0 [Passwords] 참고.

- localhost 는 지역 호스트 이름과 같은 말이다. 또한 호스트를 명백하게 설정하지 않은
경우 클라이언트에서 연결하려는 호스트의 기본값이다. 그러나 MIT-pthreads를 사용하는 시
스템에서는 localhost로의 연결이 제대로 작동하지 않는다. (localhost 연결은 유닉스 소켓
을 통해 만들어진다. 그렇지만 MIT-pthreads에서는 유닉스 소켓을 지원하지 않는다.) 이와
같은 시스템에서 문제를 피하려면, 서버에 호스트 이름을 명확하게 말해주기 위해 --host
옵션을 사용해야 한다. 그러면 mysqld 서버에 TCP/IP 연결을 만든다. 이경우, 서버 호스트
의 user 테이블 목록에 실제 호스트이름이 있어야 한다. (서버와 동일한 호스트에서 클라이
언트 프로그램을 실행한다고 하더라도 마찬가지이다.)

- mysql -u user_name db_name 으로 데이터베이스에 접속하려 할 때 접근 거부 에러가 나
면, user 테이블에 문제가 있을 것이다. mysql -u root mysql 를 실행하여 점검하고 다음의
SQL 문을 사용하자:

        mysql> SELECT * FROM user;

여기서 사용자의 호스트이름과 mysql 사용자 이름과 맞는 Host 와 User 컬럼의 목록이 포함
되어 있어야 한다.

- Access denied 에러 메시지는 접속하려는 사용자와 호스트 이름, 그리고 비밀번호를 사용
했는지 여부를 보여줄 것이다. 일반적으로 user 테이블에 에러 메시지에서 보여준 호스트
이름과 사용자 이름과 정확하게 맞는 목록을 가지고 있어야 한다.


- 다른 시스템에서 mysql 서버에 접속할 때 다음의 에러 메시지가 나오면, user 테이블에
연결을 하려고 하는 호스트 이름이 없다는 것을 말한다:

        Host ... is not allowed to connect to this MySQL server

(서버 호스트에서!) 명령행 유틸리티인 mysql을 사용하여 user 테이블에 연결하고자 하는
사용자/호스트 이름을 추가하여 해결할 수 있다. mysql 3.22 를 사용하고 있지 않고 연결하
고자 하는 시스템의 IP 숫자나 호스트 이름을 모른다면, user 테이블에 Host 컬럼 값으로
'%' 목록을 입력하고 서버 시스템에서 --log 옵션을 사용해 mysqld 를 재시작하자. 클라이
언트 시스템에서 연결을 시도한 후 mysql 로그에는 어떻게 실제로 연결을 했는지에 대한 정
보가 들어있다. (그러고나서 '%'를 로그에 나온 실제 호스트 이름으로 바꾼다. 그렇지 앟으
면 보안에 문제가 생길 수 있다.)

- mysql -u root test 는 작동을 하는데 mysql -h your_hostname -u root test 에서 접근에
에러가 나면, user 테이블에 정확한 호스트 이름이 없을 것이다. 일반적인 문제는 user 테
이블의 Host 값에는 완전하지 않은 호스트 이름(** 도메인은 빼고 호스트 이름만 넣은 경우
**) 이 들어가 있는데 시스템의 네임 해석 루틴은 FQDN(fully-qualified domain name - **
완전한 도메인 이름과 호스트 이름을 사용**)으로 처리하는 경우이다(또는 거꾸로 해석).예
를 들어, user 테이블에 호스트 이름이 'taejun' 으로 되어있는데, DNS는 mysql에 호스트
이름이 'taejun.subnet.se'라고 알려줄 수 있으며 이경우는 제대로 작동하지 않을 것이다.
user 테이블에 Host 컬럼 값으로서 해당하는 IP 숫자나 호스트 이름을 추가하자. (대신, us
er 테이블에 Host 값으로 와일드카드 문자를 포함할 수 있다. 예를 들어, 'taejun.%'. 그러
나 호스트이름 끝에 '%'를 사용하는 것은 안전하지 않으며 권하지도 않는다!)

- mysql -u user_name test 는 작동하는데 mysql -u user_name other_db_name 은 작동하지
않는다면 db 테이블에 other_db_name 목록이 없는 경우이다.

- 서버 시스템에서 mysql -u user_name db_name 은 작동을 하는데, 다른 클라이언트 시스템
에서 mysql -u user_name db_name 은 작동을 하지 않는다면, user 테이블이나 db 테이블에
클라이언트 시스템의 목록이 없는 것이다.

- 왜 Access denied 가 나는지 해결하지 못하면, user 테이블에서 와일드카드('%' 또는 '
_')를 포함하고 있는 Host 값을 가진 목록을 모두 제거하자. 매우 일반적인 에러는 Host='%
' 그리고 User='some user'로 입력을 하고나서 , 이렇게 하면 같은 시스템에서 연결할 때 l
ocalhost를 지정할 수 있도록 허용한다고 생각하는 것이다. 이것이 제대로 작동하지 않는
이유는 기본 권한에 Host='localhost' 와 User='' 목록이 포함되어 있기 때문이다. Host 값
에 '%' 보다 더 분명한 'localhost' 목록이 있기 때문에, localhost에서 접속할 때 새로운
목록보다 먼저 선택이 된다. 정확한 절차는 두번째 항목으로 Host='localhost' 와 User='so
me_user' 를 입력하거나 Host='localhost' 와 User='' 를 제거하는 것이다.

- 다음의 에러가 나는 경우:

        Access to database denied

db 나 host 테이블에 문제가 있을 것이다. 선택한 db 테이블의 목록에 Host 컬럼이 비어있
다면, host 테이블에 db 테이블 목록에 적용되는 호스트 이름이 있는지를 확인해야 한다.
(** 일반적으로 db 테이블에 host 값을 비워두는 경우, host 테이블에서 접근하는 호스트를
제어할 수 있다 **)

- 다음의 에러가 나는 경우:


        Access to database denied

SELECT ... INTO OUTFILE 또는 LOAD DATA INFILE 의 SQL 문을 사용하는 경우, user 테이블
목록에서 file 권한이 설정되어 있지 않았을 것이다.

- 다른 모든 것이 실패하였을 경우, mysqld 대몬을 디버깅 옵션으로 시작하자. (예를 들어,
--debug=d,general,query) 그러면 각 명령에서 생기는 정보와 함께, 접속을 시도하는 호스
트와 사용자에 대한 정보를 출력할 것이다. G.1 [Debugging] 참고.

- mysql 승인 테이블에서 다른 문제에 부딪쳤고 이 문제를 메일링리스트에 알려야겠다고 느
끼면, mysql 승인 테이블을 덤프하여 제공해야 한다. mysqldump mysql 명령을 사용해 테이
블을 덤프할 수 있다. 언제나 mysqlbug 스트립트를 사용하여 문제를 올리자.

- 다음의 에러가 나는 경우, mysqld 대몬이 실행되지 않거나 잘못된 소켓이나 포트로 연결
하려고 시도하는 경우:

        Can't connect to local MySQL server
        Can't connect to MySQL server on some_hostname

먼저 mysqld 대몬이 실제로 작동하는지 ps를 이용해 확인한다. 소켓 파일이 있느지 확인하
고 점검을 해 보아야 한다.(일반적으로 `/tmp/mysql.sock' 임) 또는 telnet host_name 3306
으로 접속을 시도해보자. 더 자세한 정보를 위해 mysqladmin version 과 mysqladmin -h hos
t_name version 을 사용해 볼 수 있다. 물론 참고할 것이 있는지 mysql 데이타 디렉토리의
에러 로그 파일을 점검해보자.

{{}}{{}}{{}}- 클라이언트 프로그램은 설정 파일이나 환경 변수에서 지정한 연결 패러미터를 사용할 수
있다는 것을 기억하자. 명령행에서 지정하지 않았는데 클라이언트가 잘못된 기본 연결 패러
미터를 보내는 것으로 생각되면, 홈 디렉토리에서 환경변수나 '.my.cnf' 파일을 점검해보
자. 비록 여기서 지정한 연결 패러미터와는 관계가 멀지만 시스템의 전반적인 mysql 설정
파일을 점검해 볼 수 있다. 4.14.4 [Option files] 참고. 클라이언트에서 아무런 옵션도 주
지 않았는데 Access denied 에러 메시지가 나오는 경우, 옵션 파일 중에서 예전의 비밀번호
를 지정하지 않았는지 확인해 보자. 4.14.4 [Option files] 참고.




6.12 크랙커에 대비하여 mysql을 안전하게 하는 방법

mysql 서버에 연결할 때 일반적으로 비밀번호를 사용해야 한다. 비밀번호는 연결할 때 단순
한 텍스트로 전송되지 않는다.

서버/클라이언트 연결은 암호화되지 않는다; 모든 정보는 연결을 볼 수 있는 누구라도 읽을
수 있는 텍스트로 전송된다. 이 문제에 대해 걱정이 되면 문제를 어렵게 하기 위해 압축 프
로토콜(mysql 3.22 이상 버전)을 사용할 수 있다. 보안을 더 확실하게 하기 위해 ssh를 설
치할 수 있다. (http://www.cs.hut.fi/ssh 참고) 이것을 이용해 mysql 서버와 클라이언트
사이에 암호화된 TCP/IP 연결을 사용할 수 있다.

mysql 시스템의 보안을 유지하게 위해 다음의 제안을 신중하게 고려하자:

- 모든 mysql 사용자가 비밀번호를 사용. 어떤 사용자가 비밀번호가 없으면 'mysql - u 사
용자이름' 을 이용해 간단하게 그 사용자로 로그인할 수 있다는 것을 기억하자. 이것은 클
라이언트/서버 애플리케이션의 일반적인 작동방법이다. mysql_install_db 스크립트를 실행
하기 전에 이 스크립트를 수정하여 모든 사용자의 비밀번호를 바꿀 수 있다. 또는 mysql ro
ot 사용자의 비밀번호를 바꿀 때는 다음과 같이 하면 된다:

shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
           WHERE user='root';
mysql> FLUSH PRIVILEGES;

- mysql 데몬을 유닉스의 root 사용자로 시작하지 말자. mysqld 는 다른 사용자가 실행할
수 있다.또한 보안을 더 엄격하게 하기 위해 mysql이라는 유닉스 사용자를 만들 수 있다.
다른 유닉스 사용자로 mysqld를 실행하면 user 테이블에서 root 사용자 이름을 바꿀 필요가
없다. mysqld를 다른 유닉스 사용자가 시작하기 위해 mysql.server 스크립트를 수정하면 된
다. 일반적으로 su 명령을 사용한다. 더 자세한 내용은 16.7 [Changing mysql user] 참고.

- mysqld를 실행할 수 있는 사용자만이 데이터베이스 디렉토리에 읽기/쓰기 권한을 가지고
있는지 확인.

- 모든 사용자에게 process 권한을 주지 말자. mysqladmin processlist 을 출력하면 현재
실행하는 쿼리의 내용을 볼 수 있다. 그러므로 이러한 명령을 실행할 권한이 있는 사용자는
다른 사용자의 UPDATE user SET password=PASSWORD(_'no_secure') 질의를 볼 수 있다.mysql
은 process 권한을 가진 사용자를 위해 추가적인(extra) 연결을 저장한다.그래서 mysql roo
t 사용자는 모든 일반적인 연결이 사용되었어도 로그인하고 점검을 할 수 있다.

- 모든 사용자에게 file 권한을 주지 말자. 이러한 권한이 있는 사용자는 mysqld 대몬의 권
한이 있는 파일 시스템의 어느 곳에라도 파일을 저장할 수 있다.좀 더 안전하게 하기 위해
SELECT ... INTO OUTFILE 로 생성되는 모든 파일은 모든 사용자가 읽기만 할 수 있으며 이
미 존재하는 파일을 덮어씌울 수 없다.
(** file 권한은 LOAD DATA INFILE , SELECT .. INTO OUTFILE 문을 이용하여 서버에 파일을
저장하고 읽을 수 있는 권한을 허용한다. 이러한 권한을 가진 사용자는 mysql 서버가 읽고
쓸 수 있는 파일을 읽고 쓸 수 있는 권한이 허용된다. 일반 사용자에게 이런 권한을 줄 필
요는 없다. 필요한 부분만 권한을 주는 것이 좋다. 권한을 남용말자. **)

- DNS 를 신뢰하지 못한다면 승인 테입르에서 호스트이름 대신 IP를 사용하자. 기본적으로
mysqld 의 --secure 옵션은 호스트이름을 안전하게 한다. 어떤 경우 와일드카드 문자가 포
함된 호스트이름 값을 사용할때는 매우 조심해야 한다.

- mysql.server 스크립트에서 유닉스 root 사용자의 비밀번호를 넣는다면, 이 스크립트는
오직 root만이 읽을 수 있도록 해야 한다.

다음의 mysqld 옵션은 보안과 관련되어 있다:

--secure : gethostbyname() 시스템 콜에 의해 리턴된 IP 숫자가 원래의 호스트이름을 reso
lve 한 것과 같은지를 점검한다. 이것은 어떤 사람이 다른 호스트 이름을 에뮬레이터해서
접근하는 것을 어렵게 만든다. 이 옵션은 또한 호스트이름이 온전한지에 대한 점검을 추가
한다. 해석하는데 때로는 시간이 많이 걸려서 mysql 3.21에서는 기본적으로 설정이 되어 있
지 않다. mysql 3.22에서는 호스트이름을 캐쉬하고 이 옵션이 기본적으로 설정되어 있다.
(** 함수 gethostbyname()은 호스트 이름을 인자로 받아 그에 해당하는 IP 주소 및 기타 정
보를 해당하는 구조체에 담아 그 구조체의 포인터를 리턴하는 함수입니다. 쉽게 말해서 호
스트 이름을 넣으면 해당 IP 주소를 찾아주지요.**)

--skip-grant-tables : 이 옵션을 사용하면 서버가 권한 시스템을 전혀 사용하지 않는다.
그러면 모든 사용자가 모든 데이터베이스에 접속할 수 있다! (mysqladmin reload 를 실행하
여 실행중인 서버가 승인 테이블을 사용하도록 할 수 있다.)

--skip-name-resolve : 호스트이름이 해석되지 않는다. 승인 테이블의 모든 Host 컬럼값은
반드시 IP 숫자이거나 로컬호스트이어야 한다.

--skip-networking : 네트웍을 통한 TCP/IP 연결을 허용안함. mysqld와 모든 연결은 유닉스
도메인 소켓을 통해 만들어진다. 이 옵션은 MIT-pthreads를 사용하는 시스템에서는 제대로
작동을 하지 않는다. 왜냐면 MIT-pthreads 패키지는 유닉스 소켓을 지원하지 않기 때문이
다. (** 리눅스를 사용하는 사람들에게는 상관없겠죠? 유닉스 도메인 소켓을 지원하니깐.
이와 비슷하게 postgres도 6.3버전 이후부터인가요? 기본적으로 유닉스 도메인 소켓으로 바
뀌었지요. **)
9. mysql 서버 기능(functions)

9.1 mysql에서 지원하는 언어
mysqld의 에러 메시지는 다음의 언어로 나타날 수 있습니다. : Czech, Dutch, English(기본
값), 기타 등등 (** 기타 언어는 매뉴얼 참고. 한글, 일본어 등 동양권은 여기서 빠져있습니
다. 9.1.1 절을 참고하세요. **)

mysqld를 특정한 언어로 시작하려면 --language=lang 또는 -L lang 옵션을 사용하면 됩니
다.

예> # mysqld--language=swedish

또는

# mysqld --language=/usr/local/share/swedish

모든 언어는 소문자로 표기합니다.

언어 파일은 (기본값으로) 'mysql_base_dir/share/LANGUAGE/'에 있습니다.

에러 메시지 파일을 업데이트하려면 'errmsg.txt' 파일을  편집하고 'errmsg.sys' 파일을 만
들기 위해 다음의 명령을 사용합니다.

# comp_err errmsg.txt errmsg.sys

만약 mysql의 새로운 버전으로 업그레이드하면 새로운 'errmsg.txt' 파일로 위와 같은 과정
을 거쳐야 합니다.


9.1.1 데이터와 정열에 사용하는 문자 셋
기본적으로 mysql은 ISO-8859-1 (Latin 1) 문자 셋을 사용합니다. 이 문자셋은 미국과 서유
럽에서 사용하는 문자 셋입니다.

문자셋은 이름에 어떤 문자셋을 사용할 수 있는지 그리고 SELECT 문에서 ORDER BY 와
GROUP BY 문을 사용할 때 어떻게 정렬되는지를 결정합니다.

컴파일할때 configure에서 --with-charset=charset 옵션을 사용하여 문자셋을 바꿀 수 있습
니다. 자세한 것은 4.7.1 을 참고하세요.
(** 한글을 사용하기 위해서 이 부분은 중요합니다. 우리는  컴파일할때 문자셋을 sjis로 바
꾸어 주면 됩니다. sjis는 일본어 2바이트 문자  셋입니다. 이렇게 해야 정렬이 제대로 되고
정규표현식을 사용할 수 있습니다. **) 


9.1.2 새로운 문자셋 추가
** 생략 **


9.1.3 멀티바이트 문자 지원
멀티 바이스 문자셋을 만들면 _MB 매크로를 사용할 수 있습니다.

** 생략 **


9.2 업데이트 로그
mysqld를 시작할 때 --log-update=file_name 옵션을  사용하면 mysqld는 데이타를 업데이
트한 모든  sql 문을  포함하는 로그  파일을 기록합니다.  파일은  data 디렉토리(**  보통
mysql 설치 디렉토리 밑의 data  디렉토리 **)에 기록되며 file_name.#  형태로 됩니다. #은
mysqladmin refresh 나 mysqladmin flush -logs, FLUSH LOGS 문, 또는 서버를 재시작할
때마다 증가됩니다.

--log 나 -l 옵션을 사용하면 파일 이름은 'hostname.log'가 되며, restart나 refreshes를  해
도 새로운 로그 파일이 만들어지지 않습니다. 기본적으로 mysql.server 스크립트는  -l 옵션
으로 mysql 서버를 시작합니다. production enviroment(?)를 사용하여 시작할때 더 나은 성
능이 필요하면 mysql.server에서 -l 옵션을 제거할 수 있습니다.

업데이트 로그는 지능적이서 실제로 데이타가 업데이트될 때만 로그 기록을 남깁니다. 그래
서 WHERE를 사용한 UPDATE나 DELETE에서 해당하는 레코드를 찾지 못하면 로그 파일
에 기록하지 않습니다. 또한 이미 존재하는 값을 사용할때도 Update 문은 무시됩니다.

업데이트 로그 파일에서 데이터베이스를  업데이트하려면 다음과 같이  하면 됩니다. (로그
파일이 'file_name.#'의 형태라고 가정)

# ls -1 -t -r file_name.[0-9]* | xargs cat | mysql

ls는 정확한 순서로 모든 로그 파일을 가져올 때 사용합니다.

이것은 데이터베이스에 손상이 생긴 뒤 백업 파일로 복구할 때 유용하며, 백업과 손상이 생
긴 시간 사이에 일어난 업데이트를 다시 할때(redo) 사용할 수 있습니다.

또한 다른 호스트에 미러링된 데이터베이스를  가지고 있으며 마스터 데이터베이스에  생긴
변화를 복사할때 업데이트 로그를 사용할 수 있습니다.

9.3 mysql 테이블 최대 크기
mysql 자체는 테이블 최대 크기가 4G이며 운영 시스템은 각자의 고유한 파일 크기  제한이
있습니다. 리눅스에서는 현재 2G 입니다. 솔라리스 2.5.1에서는 4G이며,  솔라리스 2.6에서는
1000G가 될 것입니다. 현재 테이블 크기 제한은 4G이거나, (MYSQL 제한) 운영 시스템 제
한입니다. 4G 이상으로 확대하기 위해 앞으로 mysql을  바꿀 것입니다. 부록 F를 참고하세
요.

거대 테이블을 읽기 전용으로 하면  많은 테이블을 하나로 모으고  압축하는 pack_isam 을
사용할 수 있습니다. pack_isam은 일반적으로 테이블을 최소 50%  압축하여 효과적으로 더
큰 테이블을 사용할 수 있습니다. 12.3 [pack_isam]을 참고하세요.

다른 솔루션은 MERGE 라이브러리에 포함되어 있으며  identical 테이블을 모아 하나로 관
리할 수 있습니다. (여기서  Identical은 모든 테이블이 identical  컬럼 정보로 만들어진다는
것을  의미합니다.)  현재  MERGE는  인덱스를  지원하지  않기  때문에  테이블의  모음
(collection)만을 검색하는데만 사용할 수 있습니다. 가까운  시일내에 여기에 인덱스를 추가
할 것입니다.

(** 참고로 읽기 전용 테이블은 mysql에 라이센스를 지불하고 구입했을 때만 만들 수 있습
니다. 단지 읽기만 하는 것은 가능하지만 압축이 된 읽기 전용 테이블은 만들 수  없습니다.
**)
10. mysql의 최대 성능 향상 방법

10.1 버퍼 크기 조정
mysqld 서버가 사용하는 기본 버퍼 크기는 다음의 명령으로 알 수 있다.

shell> mysqld --help

이 명령은 모든 mysqld 옵션의 목록과 설정 변수를 보여준다. 출력되는 내용은 기본값을
포함하고 있으며 다음과 비슷하다.

Possible variables for option --set-variable (-O) are:
back_log              current value: 5
connect_timeout       current value: 5
join_buffer           current value: 131072
key_buffer            current value: 1048540
long_query_time       current value: 10
max_allowed_packet    current value: 1048576
max_connections       current value: 90
max_connect_errors    current value: 10
max_join_size         current value: 4294967295
max_sort_length       current value: 1024
net_buffer_length     current value: 16384
record_buffer         current value: 131072
sort_buffer           current value: 2097116
table_cache           current value: 64
tmp_table_size        current value: 1048576
thread_stack          current value: 131072
wait_timeout          current value: 28800

mysqld 서버가 현재 가동중이면 다음의 명령을 통해 실제 변수값을 볼 수 있다.

shell> mysqladmin variables

각 옵션은 밑에서 설명한다. 버퍼  크기, 길이, 스택 크기는 바이트이다. 'K'(킬로바이트)
나 'M'(메가바이트)를 앞에 붙여 값을 지정할 수 있다. 예를 들면 16M는 16 메가바이트를
가리킨다. 대소문자는 구별하지 않는다. 16M 와 16m은 같다.

-back_log
mysql이 가질 수 있는 최대 연결 요청의 수. 이것은 main mysql 스레드가 매우 짧은 시간
동안 매우 많은 연결 요청을 받을 때 기능을 한다. 이때 메인 스레드가 연결을 체크하고 새
로운 스레드를 시작하는데는 약간의 시간이 걸린다.(그러나 아주 짧은 시간임) back_log 값
은 mysql이 순간적으로 새로운 요청에 답하는 것을 멈추기전에 이 짧은 시간동안 얼마나
많은 요청을 쌓아두고 있는지를 지정한다. 매우 짧은 시간동안 매우 많은 연결이 예상될때
만 이 값을 증가시켜야 한다.

다른 말로 이 값은 tcp/ip 연결을 받는 listen queue의 크기이다. 각 운영체제마다 이러한 큐
의 크기에 한계가 있다. Unix system call listen(2) 매뉴얼페이지에 자세한 정보가 있다. ba
ck_log값의 한계는 운영체제 문서를 확인해봐라. back_log를 최대값보다 더 높여도 효과가
없다.

-connect_timeout
Bad handshake에 반응하기 전에 연결 패킷을 mysql 서버에서 기다리는 시간.(초)

-join_buffer
(인덱스를 사용하지 않는 조인의) full-join에서 사용하는 버퍼의 크기. 버퍼는 두 테이블 사
이에서 각 full-join마다 한번 할당이 된다. 인덱싱을 추가하지 못할 때 조인 버퍼를 증가시
키면 full join의 속도를 향상시킬 수 있다. (일반적으로 빠르게 조인을 하는 가장 좋은 방법
은인덱스를 추가하는 것이다)

-key_buffer
인덱스 블락은 버퍼링되고 모든 스레드에서 공유한다. 키 버퍼는 인덱스 블락에서 사용하는
버퍼의 크기이다. 인덱스가 많은 테이블에서 delete나 insert 작업을 많이 하면 키 버퍼값을
증가시키는 것이 좋다. 더 빠른 속도를 내려면 LOCK TABLES를 사용하자. [Lock Tables]
참고.

-max_allowed_packet
한 패킷의 최대 크기. 메시지 버퍼는 net_buffer_length 바이트로 초기화되지만 필요하면 최
대 허용 패킷 바이트를 증가시킬 수 있다.기본값은 큰 패킷을 잡기에는 작다. 거대 BLOB
컬럼을 사용한다면 값을 증가시켜야 한다. 사용자가 원하는 최대 blob만큼 크게  해야 한다.

-max_connections
동시 클라이언트 숫자. mysqld가 필요로하는 파일 지시자(descriptor)의 숫자만큼 값을 늘려
야 한다. 밑에서 파일 디스크립터 제한에 대한 내용을 참고하자.

-max_connect_errors
호스트에서 최대 연결 에러이상의 interrupted 연결이 있으면 더 많은 연결을 위해 호스트는
block화된다. FLUSH HOSTS 명령으로 호스트의 block을 해제할 수 있다.

-max_join_size
최대 조인 크기이상으로 레크도를 읽는 조인을 하면 에러가 난다. 만약 사용자가 where 문
을 사용하지 않고 시간이 많이 걸리면서 몇백만개의 레코드를 읽는 조인을 수행하려 하면
이 값을 설정한다.

-max_sort_length
BLOB나 TEXT 값으로 정열할때 사용하는 바이트의 숫자. (각 값중 오직 첫번째 max_sort
_length 바이트만 사용된다. 나머지는 무시된다)

-net_buffer_length
질의에서 통신 버퍼가 초기화되는 크기. 일반적으로 바뀌지 않지만 매우 적은 메모리를 가
지고 있을 때 예상되는 질의에 맞게 세팅할 수 있다. (이것은 클라이언트에 가는 예상된 sql
문의 길이이다. 질의문이 이 크기를 넘으면 버퍼는 자동으로 max_allowed_packet 바이트까
지 증가한다)

-record_buffer
순차적인 검색을 하는 각 스레드에서 각 검색 테이블에 할당하는 버퍼 크기. 순차적인 검색
을 많이 하면 이 값을 증가시켜야 한다.

-sort_buffer
정렬이 필요한 각 스레드에서 할당하는 버퍼 크기. order by 나 group by 오퍼레이션을 빠
르게 하려면 이 값을 증가시킨다. 16.4 [임시 파일] 참고.

-table_cache
모든 스레드에서 열 수 있는 테이블의 숫자. mysqld가 필요로 하는 파일 디스크립터의 숫
자만큼 이 값을 증가시켜라. mysql은 각 유일한 오픈 테이블에서 두개의 파일 디스크립터가
필요하다. 파일 디스크립터 제한을  참고한다. 테이블 캐쉬가 어떻게 작동하는지는 10.6 [테
이블 캐쉬]를 참고한다.

-tmp_table_size
임시 테이블이 이 값을 넘으면 mysql은 "The Table tbl_name is full"이라는 에러 메시지를
낸다. 매우 많은 group by 질의를 사용하면 이 값을 증가시켜야 한다.

-thread_stack
각 스레드의 스택 사이즈. creash-me test(**역자주 : 데이터베이스의 벤치마킹을 하는 테스
트입니다. 말그대로 데이터베이스를 죽여주지요) 에서 잡히는 많은 제한은 이 값에 달려있
다. 기본값은 일반적으로 충분히 크다. 11장의 [벤치마크] 참조

-wait_timeout
연결을 끊기전에 연결 활동(activity)을 서버에서 기다리는 시간(초).

table_cache 와 max_connections는 서버가 열 수 있는 최대 파일 갯수에 영향을 미친다. 이
값을 증가시키면 운영시스템에서 오픈 파일 디스크립터의 per-process 숫자의 한계까지 올
릴 수 있다. (** ... imposed by your operating system on the per-process number of
open file descriptors. 번역이 이상하므로 영문 참고)
그러나 많은 시스템에서 이 한계를 증가시킬수 있다. 이렇게 하려면 각 시스템에서 이 한계
를 변화시키는 방법이 매우 다양하므로 운영체제 문서를 참고해야 한다.

table_cache 는 max_connections 와 관계가 있다. 예를 들면 200개의 연결이 있으면 최소 2
00 * n 의 테이블 캐쉬를 가져야 한다. 여기서 n은 조인에서 테이블의 최대 숫자이다.

mysql은 매우 유용한 알고리즘을 사용하기 때문에 일반적으로는 매우 적은 메모리로 사용
할 수 있으며 메모리가 많을 수록 성능이 더 많이 향상된다.

많은 메모리와 많은 테이블을 가졌고 중간정도 숫자의클라이언트에서 최대의 성능을 원한다
면 다음과 같이 사용한다.

shell> safe_mysqld -O key_buffer=16M -O table_cache=128 \
           -O sort_buffer=4M -O record_buffer=1M &

메모리가 적고 연결이 많으면 다음과 같이 사용한다.

shell> safe_mysqld -O key_buffer=512k -O sort_buffer=100k \
           -O record_buffer=100k &

또는:

shell> safe_mysqld -O key_buffer=512k -O sort_buffer=16k \
           -O table_cache=32 -O record_buffer=8k -O net_buffer=1K &

매우 많은 연결이 있을 때 mysqld가 각 연결마다 최소한의 메모리를 사용하도록 설정하지
않았다면 "swapping problems" 문제가 생길 것이다.

mysqld에서 옵션을 바꾸었으면 그것은 서버의 해당하는 인스턴스에만 영향을 미친다는 것
을 기억하자.

옵션을 바꾸었을때의 효과를 보기 위해 다음과 같이 해보자.

shell> mysqld -O key_buffer=32m --help

마지막에 --help 옵션이 들어간 것을 기억하자. 그렇지 않으면 커맨드 라인에서 사용한 옵
션의 효력은 출력에는 반영되지 않을 것이다.


10.2 메모리 사용 방법 <메모리 최적화>

아래에서 설명하는 목록은 mysqld 서버가 메모리를 사용하는 방법에 대해서 나타내고 있
다. 메모리 사용과 관련된 서버의 변수 이름이 주어진다.


- 키 버퍼(변수 key_buffer)는 모든 스레드에서 공유한다. 서버에서 사용하는 다른 버퍼는
필요한대로 할당이 된다.

- 각 연결은 각 스레드마다의 특정한 공간을 사용한다. 스택(64k, 변수 thread_stack) , 연결
버퍼(변수 net_buffer_length), result 버퍼 (변수 net_buffer_length) 등. 연결 버퍼와 result
버퍼는 필요할때 max_allowed_packet 까지 동적으로 증가된다. 질의가 수행될 때 현재의
질의문의 복사문이 또한 할당이 된다.
(** When a query is running a copy of the current query string is also alloced.)

- 모든 스레드는 같은 기본 메모리를 공유한다.
- 메모리 맵은 아직 지원이 안된다. (압축 테이블을 제외하고. 그러나 이것은 다른 이야기이
다) 왜냐하면 4GB의 32비트 메모리 공간은 대부분의 대형 테이블에서 충분히 크기가 않기
때문이다. 우리가 64비트 주소 공간을 가진 시스템을 가지게 될 때 우리는 메모리 맵핑을
위한 일반적인 지원을 추가할 것이다.

- 테이블에서 순차적인 검색을 하는 각 요청은 read 버퍼에 할당이 된다. (변수 record_buff
er)

- 모든 조인은 한번에 수행이 되며 대부분의 조인은 임시 테이블을 생성하지 않고 수행이
된다. 대부분의 테이블은 메모리 기반(HEAP) 테이블이다. 거대 길이의 레코드를 가졌거나
BLOB 컬럼을 포함한 임시 테이블은 디스크에 저장이 된다. 현재의 문제는 메모리 기반 테
이블이 tmp_table_size를 초과했을때 "The table tbl_name is full"이라는 에러가 생기는 것
이다. 가까운 시일안에 필요할때 자동적으로 메모리 기반(HEAP) 테이블을 디스크 기반(NI
SAM) 테이블로 바꾸도록 고칠 것이다.
이 문제를 해결하기 위해서 mysqld의 tmp_table_size 옵션을 설정하여 임시 테이블 크기를
늘이거나 클라이언트 프로그램에서 SQL_BIG_TABLES라는 sql 옵션을 설정하여야 한다. 7.
24 SET OPTION 을 참고하자.
mysql 3.20에서 임시 테이블의 최대 크기는 record_buffer*16이다. 3.20 버전을 사용하고 있
다면 record_buffer의 값을 증가시켜야 한다. 또한 mysqld를 시작할 때 --big-tables 옵션을
사용하여 항상 임시 테이블을 디스크에 저장할 수 있지만 질의 속도에 영향을 미친다.

- 정열을 하는 대부분의 요청은 정렬 버퍼와 하나나 두개의 임시 파일을 할당한다. 16.4의
[임시 파일]을 참고한다.

- 대부분의 파징(parsing)과 계산은 지역 메모리에서 이루어진다. 작은 아이템에는 메모리 o
verhead가 필요없고 일반적인 느린 메모리 할당(slow memory allocation)과 freeing(메모리
해제)는 무시된다. 메모리는 오직 예상지 못한 거대 문자열에서 할당이 된다.( mallloc() 과
free() 사용)

- 각 인덱스 파일은 한번에 열리며 각 병행수행되는 스레드에서 데이터 파일은 한번에 열
린다. 각 병행수행 스레드마다 테이블 구조, 각 컬럼의 컬럼 구조, 3 * n 의 버퍼 크기가 할
당된다. ( n은 최대 레코드 길이이며 BLOB 컬럼은 해당하지 않는다) BLOB는 BLOB 데이
터의 길이에 5에서 8 바이트를 더한 값을 사용한다.

- BLOB 컬럼을 가진 각 테이블에서 버퍼는 거대 BLOB 값을 읽을 수 있도록 동적으로 커
진다. 테이블을 검색하면 버퍼는 최대 BLOB의 값만큼 버퍼가 할당이 된다.

- 모든 사용중인 테이블의 테이블 핸들러는 캐쉬에 저장되며 FIFO로 관리가 된다. 일반적
으로 캐쉬는 64 엔트리를 갖는다. 동시에 두개의 실행 스레드에서 테이블을 사용하면 캐쉬
는 테이블의 두 엔트리를 포함한다. 10.6 [테이블 캐쉬]를 참고한다.

- mysqladmin flush-tables 명령은 사용하지 않는 모든 테이블을 닫고 현재 실행되는 스레
드가 끝날 때 모든 사용중인 테이블을 닫는다고 표시한다. 이것은 효과적으로 사용중인 메
모리를 해제한다.


ps 와 다른 시스템 상황 프로그램은 mysqld가 많은 메모리를 사용하고 있다고 보고할 것이
다. 이것은 다른 메모리 주소의 스레드-스택때문에 생긴다. 예를 들면 솔라리스의 ps 는 스
택사이의 사용하지 않는 메모리를 사용하는 메모리로 간주한다. 이것은 swap -s를 이용 사
용가능한 스왑을 체크하여 확인할수 있다. 우리는 mysqld를 상용 메모리 유출 측정 프로그
램으로 테스팅해서 mysqld에는 메모리 유출이 없다.


10.3 속도 향상에 영향을 미치는 컴파일/링크 방법 <컴파일시 최적화하기>

다음 테스트의 대부분은 리눅스와 mysql 벤치마크를 가지고 수행되었지만 다른 운영 시스
템에도 암시해주는 것이 있다.

static으로 링크를 할때 가장 빠른 실행 속도를 얻을 수 있다. 데이터베이스에 연결하기 위
해 TCP/IP보다는 유닉스 소켓을 사용하면 더 좋은 성능을 낼 수 있다.

리눅스에서 pgcc와 -O6을 사용하면 가장 빠르다. 'sql_yacc.cc'를 이 옵션으로 컴파일하려면
gcc/pgcc는 모든 성능을 내기 위해 많은 메모리가 필요하기 때문에 180M의 메모리가 필요
하다. 또한 mysql을 설정할때 libstdc++ 라이브러리를 포함하지 않기 위해 CXX=gcc라고 설
정해야 한다.

- pgcc를 사용하고 모두다 -O6 옵션으로 컴파일하면 mysqld 서버는 gcc로 컴파일한 것보
다 11% 빨라진다.

- 동적으로 링크하면 (-static을 사용하지 않고) 13% 느려진다.
    If you connect using TCP/IP rather than Unix sockets, the result is 7.5% slower.
- 유닉스 소켓을 사용하는 것보다 tcp/ip로 연결하는 것이 7.5% 느려진다.

- On a Sun sparcstation 10, gcc 2.7.3 is 13% faster than Sun Pro C++ 4.2.
- On Solaris 2.5.1, MIT-pthreads is 8-12% slower than Solaris native threads.
(** 번역을 안한 이후. 리눅스랑 상관없으니깐... **)

TcX에서 제공한 mysql 리눅스 배포판은 pgcc로 컴파일되었고 정적으로 링크되었다.


10.4 How MySQL uses indexes

prefix- and end-space compressed. See section 7.26 CREATE INDEX syntax (Compatibil
ity function).

모든 인덱스(PRIMARY, UNIQUE and INDEX()) 는 B-trees 에 저장된다. 문자열은 자동적
으로 앞 뒤의 공간(?)이 압축된다. 7.26 [인덱스 생성] 참고.

인덱스의 사용 :
- WHERE 문에서 해당하는 레코드 빨리  찾기
- 조인을 수행할때 다른 테이블에서 레코드 가져오기
- 특정 키에서 MAX() 나 MIN() 값 찾기
- 소팅이나 그룹화할때 인덱스 키를 사용하면 테이블을 정열하거나 그룹화한다. 키에  DES
C가 붙으면 역순으로 인덱스를 읽는다.
- 어떤 경우에는 데이터 파일에 묻지 않고 값을 가져온다. 어떤 테이블에서 사용하는 모든
컬럼이 숫자이고 특정 키로 형성되어있으면 빠른 속도로 인덱스 트리에서 값을 가져올 수
있다.

다음 예제를 보자.

mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;


다중 컬럼 인덱스가 col1 과 col2에 있으면 해당하는 레코드를 직접 가져올 수 있다.  분리
된 단일 컬럼 인덱스가 col1 과 col2 에 있으면 최적화기는 어떤 인덱스가 더 적은 레코드
를 가졌는지 확인하고 레코드를 가져오기 위해 그 인덱스를 사용하도록 결정한다.

테이블이 다중 컬럼 인덱스를 가졌다면 최적화기가 레코드를 찾는데 어떤 인덱스키를 사용
할 수 있다. 예를 들면 세가지 컬럼 인덱스(col1, col2, col3)를 가졌다면 (col1), (col1,col2)
(col1,col2,col3) 인덱스를 사용하여 검색을 할 수 있다. 

MySQL can't use a partial index if the columns don't form a leftmost prefix of the inde
x.
Suppose you have the SELECT statements shown below:
(** 해석이 잘 안되는데 예제를 보시면 무슨 말인지 알 수 있을 것임**)

mysql> SELECT * FROM tbl_name WHERE col1=val1;
mysql> SELECT * FROM tbl_name WHERE col2=val2;
mysql> SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;

If an index exists on (col1,col2,col3), only the first query shown above uses the index.
The second and third queries do involve indexed columns, but (col2) and (col2,col3) are
not leftmost prefixes of (col1,col2,col3).

인덱스가 (col1,col2,col3)로 있다면 위의 질의중 오직 첫번째 질의만 인덱스를 사용한다. 두
번째 및 세번째 질의은 인덱스된 컬럼이 포함되어 있지만 (col2) 와 (col2,col3)는 (col1,col2,c
ol3) 인덱스에 해당하지 않는다.

MySQL also uses indexes for LIKE comparisons if the argument to LIKE is a constant
string that doesn't start with a wildcard character. For example, the following SELECT
stat ements use indexes:

mysql은 또한 LIKE의 인수가 와일드카드 문자로 시작하지 않는 상수 문자열일이라면 LIK
E 비교문에서 인덱스를 사용한다. 예를 들어 다음의 SELECT 문은 인덱스를 사용한다.

mysql> select * from tbl_name where key_col LIKE "Patrick%";
mysql> select * from tbl_name where key_col LIKE "Pat%_ck%";

첫번째 문장에서는 "Patrick" <= key_col < "Patricl" 을 가진 레코드만 고려된다. 두번째 문
장에서는 "Pat" <= key_col < "Pau" 을 가진 레코드만 고려된다.


다음의 SELECT 문은 인덱스를 사용하지 않는다:

mysql> select * from tbl_name where key_col LIKE "%Patrick%";
mysql> select * from tbl_name where key_col LIKE other_col;

첫번째 문장에서 LIKE 값은 와일드카드 문자로 시작하고 있다. 두번째 문장에서는 LIKE
값이 상수가 아니다.



10.5 WHERE 문에서 최적화하기
(이번 절은 완전한 내용을 포함하고 있지는 않다. mysql은 많은 최적화방법이 있다.)

In general, when you want to make a slow SELECT ... WHERE faster, the first thing t
o check is whether or not you can add an index. All references between different tables
should usually be done with indexes. You can use the EXPLAIN command to determine
which indexes are used for a SELECT. See section 7.21 EXPLAIN syntax (Get informat
ion about a SELECT).
일반적으로 느린 SELECT ... WHERE 문을 빠르게 하려면 가장 먼저 확인해야 할 것이 인
덱스 추가 문제이다. 다른 테이블사이에서 모든 레퍼런스(references 참조)는 일반적으로 인
덱스에 의해 수행된다. SELECT 문에서 어떤 인덱스를 사용하는지 결정하기 위해 EXPLAI
N 명령을 사용할 수 있다. 7.21 [Explain]을 참고.

mysql에서 수행하는 최적화는 다음과 같다.


- 불필요한 삽입어 제거

       ((a AND b) AND c OR (((a AND b) AND (c AND d))))
    -> (a AND b ANDc) OR (a AND b AND c AND d)

-상수 폴딩(folding)

       (a<b AND b=c) AND a=5
    -> b>5 AND b=c AND a=5

- 상수 조건 제거(상수 폴딩때문에  필요)

       (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
    -> B=5 OR B=6

- 인덱스에서 사용되는 상수 표현은 한번에 계산된다.
(Constant expressions used by indexes are evaluated only once.)

- WHERE 절이 없는 단일 테이블의 COUNT(*)는 테이블 정보에서 직접 값을 가져온다.
단일 테이블에서 사용된 NOT NULL 표현도 이와 같이 수행된다. 

- 유효하지 않은 상수 표현은 미리 제거된다. mysql은 불가능하고 해당하는 레코드가 없는
SELECT 문을 빠르게 감지한다.

- GROUP BY 나 그룹 펑션(COUNT(), MIN() ...)을 사용하지 않으면 HAVING은 WHERE
에 합쳐진다.
(** HAVING 절에서는 인덱스를 사용하지 못함. 그러므로 가능한 HAVING절을 사용하지
않는게 속도면에서 좋다 **)

- 각 서브 조인에서 빠르게 WHERE 문을 계산하고 가능한한 레코드를 제외하도록 간소하
게 WHERE 문이 만들어진다.

- mysql은 일반적으로 최소한의 레코드를 찾기 위해 인덱스를 사용한다. =, >, >=, <, <=,
BETWEEN 그리고  'something%' 처럼 앞이 와일드카드로 시작하지 않는 LIKE 문등을
사용하여 비교를 할 때 인덱스를 사용한다. (** 10.4 절에서 설명하였듯이 like 를 사용할때
와일드카드로 시작하는 like 문을 사용하면 인덱스를 사용하지 않는다. 일정한 단어로만 시
작하는 컬럼에서 자료를 찾을 때 유용할 것이다. **)

- Any index that doesn't span all AND levels in the WHERE clause is not used to opti
mize the query.

다음의 WHERE 문은 인덱스를 사용한다.:

... WHERE index_part1=1 AND index_part2=2
... WHERE index=1 OR A=10 AND index=2      /* index = 1 OR index = 2 */
... WHERE index_part1='hello' AND index_part_3=5
          /* optimized like "index_part1='hello'" */

다음의 WHERE 문은 인덱스를 사용하지 않는다.:

... WHERE index_part2=1 AND index_part3=2  /* index_part_1 is not used */
... WHERE index=1 OR A=10                  /* No index */
... WHERE index_part1=1 OR index_part2=10  /* No index spans all rows */

- 질의에서 다른 테이블보다 모든 상수 테이블을 먼저 읽는다. 상수 테이블은 다음과 같다.
        ㅇ빈 테이블이나 1개의 레코드만 있는 테이블
        ㅇWHERE 문에서 UNIQUE 인덱스나 PRIMARY KEY 를 사용하고 모든 인덱스
는 상수 표현으로된 테이블

        다음의 테이블은 상수 테이블로 사용된다.

    mysql> SELECT * FROM t WHERE primary_key=1;
    mysql> SELECT * FROM t1,t2
               WHERE t1.primary_key=1 AND t2.primary_key=t1.id;

- 모든 가능성을 시도하여 테이블을 조인하는데 가장 좋은 조인 조합을 찾는다. (ORDER B
Y나 GROUP BY의 모든 컬럼이 동일한 테이블에서 나오면 조인을 할때 이 테이블이 먼저
선택된다)

- ORDER BY 문과 다른 GROUP BY 문이 있을 때, 또는 ORDER BY 나 GROUP BY가
조인 큐의 첫번째 테이블이 아닌 다른 테이블의 컬럼을 포함하고 있으면 임사 테이블을 만
든다.

- 각 테이블 인덱스를 찾고 레코드의 30%미만을 사용하는 (best) 인덱스가 사용된다. 그런
인덱스가 없으면 빠른 테이블 검색이 사용된다.

- 어떤 경우에는 mysql은 데이터 파일을 조회하지 않고 인덱스에서 레코드를 읽을 수 있
다. 인덱스에서 사용한 모든 컬럼이 숫자라면 질의를 처리하는데 단지 인덱스 트리만을 사
용한다.

- 각 레코드가 출력되기 전에 HAVING 절에 맞지 않는 레코드는 건너뛴다.

다음은 매우 빠른 질의의 예이다:

mysql> SELECT COUNT(*) FROM tbl_name;
mysql> SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;
mysql> SELECT MAX(key_part2) FROM tbl_name
           WHERE key_part_1=constant;
mysql> SELECT ... FROM tbl_name
           ORDER BY key_part1,key_part2,... LIMIT 10;
mysql> SELECT ... FROM tbl_name
           ORDER BY key_part1 DESC,key_part2 DESC,... LIMIT 10;

다음의 커리는 인덱스 트리만을 사용하여 값을 구한다.(인덱스 컬럼은 숫자라고 가정):

mysql> SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;
mysql> SELECT COUNT(*) FROM tbl_name
           WHERE key_part1=val1 and key_part2=val2;
mysql> SELECT key_part2 FROM tbl_name GROUP BY key_part1;

다음의 질의는 개별적인 정열을 하지 않고 정열된 순서대로 열을 가져오는 데 인덱스를 사
용한다:

mysql> SELECT ... FROM tbl_name ORDER BY key_part1,key_part2,...
mysql> SELECT ... FROM tbl_name ORDER BY key_part1 DESC,key_part2 DESC,...


10.6 테이블 열고 닫는 방법

open 테이블의 캐쉬는 table_cache의 최대값까지 커질 수 있다. (기본값 64 ; 이 값은 mysql
d에서 -0 table_cache=# 으로 바꿀 수 있다) 캐쉬가 꽉 찼을때, 그리고 다른 스레드가 테이
블을 열려고 할 때, 또는 mysqladmin refresh 나 mysqladmin flush-tables를 사용할때를 제
외하고는 테이블은 결코 닫히지 않는다.

테이블 캐쉬가 꽉 차면 서버는 캐쉬 엔트리를 사용하도록 조절하기 위해 다음의 절차를 사
용한다.

- 가장 먼저 사용했던 순서대로 현재 사용하지 않는 테이블을 닫는다.
- 캐쉬가 꽉 찼고 어떤 테이블도 닫히지 않지만 새로운 테이블을 열어야 한다면 캐쉬가 필
요한 만큼 임시적으로 확장된다.
- 캐쉬가 임시적으로 확장된 상태이고 테이블을 사용할 수 없는 상황으로 가면 테이블을
닫고 캐쉬를 해제한다.

테이블은 각 동시병행적인 접근때마다 열린다. 동일한 테이블에 접근하는 두개의 스레드가
있거나 같은 질의에서 테이블에 두번 접근하면(with AS) 테이블을 두번 열여야 한다는 의
미이다. 테이블의 첫번째 개방은 두개의 파일 디스크립터를 가진다. ; 추가적인 테이블의 개
방은 하나의 파일 디스크립터를 가질 뿐이다. 처음에 개방에 사용하는 추가적은 파일 디스
크립터는 인덱스 파일에 사용된다. ; 이 디스크립터는 모든 스레드에서 공유된다.


10.6.1 데이터베이스에서 많은 수의 테이블을 만들때의 단점

디렉토리에 많은 파일이 있다면 open, close 그리고 create 오퍼레이션은 느려질 것이다. 서
로 다른 많은 테이블에서 SELECT 문을 수행하면 테이블 캐쉬가 꽉 찰 때 약간의 overhea
d가 있을 것이다. 왜냐면 개방된 테이블이 있다면 다른 테이블은 닫혀야 하기 때문이다. 테
이블 캐쉬를 크게 해서 이러한 오우버헤드를 줄일 수 있다.


10.7 많은 테이블을 여는 이유

mysqladmin status 를 실행할 때 다음과 같이 나올 것이다:

Uptime: 426 Running threads: 1 Questions: 11082 Reloads: 1 Open tables: 12

단지 6테이블을 사용했는데 이러한 결과는 당황스러울 것이다.

mysql은 멀티스레드를 사용한다. 그래서 동시에 같은 테이블에서 많은 질의를 할 수 있다.
같은 파일에 대하여 다른 상황을 가지는 두개의 스레드에 대한 문제를 줄이기 위해 테이블
은 각 동시병행적인 스레드마다 독립적으로 개방된다. 이것은 테이타 파일에서 약간의 메모
리와 하나의 추가적인 파일 디스크립터를 사용한다. 모든 스레드에서 인덱스 파일은 공유된
다.


10.8 데이터베이스와 테이블에서 심볼릭 링크 사용

데이터베이스 디렉토리에서 테이블과 데이터베이스를 다른 위치로 옮기고 새로운 위치로 심
볼릭 링크를 사용할 수 있다. 이렇게 하는 것을 원할 경우가 있다. 예를 들면 데이터베이스
를 더 여유공간이 많은 파일시스템으로 옮기는 경우 등.

mysql에서 테이블이 심볼링 링크되었다는 것을 감지하면 심볼링 링크가 가리키는 테이블을
대신 사용할 수 있다. realpath() call 을 지원하는 모든 시스템에서 작동한다. (최소한 리눅
스와 솔라리스는 realpath()를 지원한다) realpath()를 지원하지 않는 시스템에서 동시에 실
제 경로와 심볼릭 링크된 경로에 접근하면 안된다. 이런 경우에는 업데이트 된후에 테이블
이 모순될 수 있다.

mysql은 기본값으로 데이터베이스 링크를 지원하지 않는다. 데이터베이스간에 심볼릭 링크
를 사용하지 않는 작동을 잘 할 것이다. mysql 데이터 디렉토리에 db1 데이터베이스가 있
고 db1을 가리키는 db2 심볼릭 링크를 만들었다고 해보자:

shell> cd /path/to/datadir
shell> ln -s db1 db2

이제 db1에 tbl_a라는 테이블이 있다면 db2에도 tbl_a가 나타날 것이다. 한 스레드가 db1.tbl
_a를 업데이트하고 다른 스레드가 db2.tbl_a를 업데이트하면 문제가 생길 것이다.

정말로 이 기능이 필요하면 , `mysys/mf_format.c'에서 다음의 코드를 수정해야 한다.:

if (!lstat(to,&stat_buff))  /* Check if it's a symbolic link */
    if (S_ISLNK(stat_buff.st_mode) && realpath(to,buff))

위 코드를 다음과 같이 수정한다 :

if (realpath(to,buff))


10.9 테이블에 락 거는 방법

mysql의 모든 락은 deadlock-free 이다. 언제나 질의를 시작할때 한번에 모든 필요한 락을
요청하고 언제나 같은 순서대로 테이블에 락을 걸어 관리한다.

WRITE 락을 사용하는 방법은 다음과 같다:

- 테이블에 락이 없으면 그 테이블에 write 락을 건다.
- 이런 경우가 아니라면 write 락 큐에 락을 요청한다.

READ 락을 사용하는 방법은 다음과 같다:

- 테이블에 write 락이 없으면 그 테이블에 read 락을 건다.
- 이런 경우가 아니라면 read 락 큐에 락을 요청한다.

락이 해제되었을 때 락은 write 락 큐의 스레드에서 사용할 수 있으며 그러고 나서 read 락
큐의 스레드에서 사용한다.

테이블에서 업데이트를 많이 하면 SELECT 문은 더 이상 업데이트가 없을 때까지 기다린
다는 것을 의미한다.

이러한 문제를 해결하기 위해 테이블에서 INSERT 와 SELECT 오퍼레이션을 많이 사용하
는 경우에 다음과 같이 하면 된다. 임시 테이블에 레코드를 입력하고 한번에 임시 테이블에
서 실제 테이블로 레코드를 업데이트한다.

다음의 예를 보자:

mysql> LOCK TABLES real_table WRITE, insert_table WRITE;
mysql> insert into real_table select * from insert_table;
mysql> delete from insert_table;
mysql> UNLOCK TABLES;

만약 어떤 경우에 SELECT문에 우선권을 주고 싶다면 INSERT 옵션에서 LOW_PRIORITY
or HIGH_PRIORITY 옵션을 사용할 수 있다. 7.13 [Insert] 참고. (** LOW_PRIORITY를 지
정하면 클라이언트에서 테이블을 읽지 않을 때까지 INSERT 문 수행이 미루어진다. **)

단일 큐를 사용하기 위해 `mysys/thr_lock.c' 의 락킹 코드를 바꿀 수 있다. 이런 경우 writ
e 락과 read 락은 같은 우선권을 가지며 어떤 애플리케이션에서는 유용할 수 있다.

10.10 테이블을 빠르고 작게 배열하는 방법 <** 테이블 최적화 **>

다음은 테이블에서 최대의성능을 내는 방법과 저장 공간을 절약할 수 있는 테크닉이다:

- 가능한한 NOT NULL로 컬럼을 선언한다. 속도가 빨라지며 각 컬럼마다 1 비트를 절약할
수 있다.
- default 값을 가질 때 유리하다. 입력되는 값이 기본값과 다를 때만 확실하게 값이 입력된
다. INSERT 문에서 첫번째 TIMESTAMP 컬럼이나 AUTO-INCREAMENT 컬럼의 값을
입력할 필요가 없다. 18.4.49 [mysql_insert_id()] 참고.
- 가능한한 테이블을 작게 만드려면 더 작은 integer 타입을 사용하자. 예를 들면 MEDIUM
INT 가 보통 INT 보다 좋다.
- 가변 길이 컬럼이 없다면(VARCHAR, TEXT or BLOB columns), 고정 길이 레코드 포
맷이 사용된다. 이 경우 속도는 더 빠르지만 불행히도(흑흑~) 낭비되는 공간이 더 많다. 10.1
4 [Row format] 참고.
- mysql이 질의를 효과적으로 최적화하기 위해 많은 양의 데이터를 입력한후 isamchk --a
nalyze를 실행하자. 이렇게 하면 동일한 값을 가진 줄의 평균 숫자를 가리키는 각 인덱스의
값을 업데이트한다. (물론 unique 인덱스에서는 항상 1이다)
- 인덱스와 인덱스에 따른 데이타를 정열하려면
isamchk --sort-index --sort-records=1 을 사용하자.(if you want to sort on index 1).
인덱스에 따라 정렬된 모든 레코드를 읽기 위해 unique 인덱스를 가졌다면 이렇게 하는 것
이 속도를 빠르게 하는 가장 좋은 방법이다.
- INSERT 문에서 가능한 다중 값 목록을 사용하자. 개별적인 SELECT 문보다 훨씬 빠르
다. 데이타를 테이블에 입력할 때 LOAD DATA INFILE을 사용하자. 많은 INSERT 문을
사용하는 것보다 보통 20배 빠르다. 7.15 [Load] 참고.

많은 인덱스를 가진 테이블에 데이타를 입력할때 다음의 과정을 사용하면 속도를 향상시킬
수 있다.
1. mysql이나 Perl 에서 CREATE TABLE로 테이블을 만든다.
2. mysqladmin flush-tables 실행. (** 열린 테이블을 모두 닫음 **)
3. isamchk --keys-used=0 /path/to/db/tbl_name 사용. 테이블에서 모든 인덱스 사용을 제
거한다.
4. LOAD DATA INFILE 를 이용 테이블에 데이타를 입력.
5. pack_isam을 가지고 있고 테이블을 압축하기 원하면 pack_isam을 실행.
6. isamchk -r -q /path/to/db/tbl_name 를 이용 인덱스를 다시 생성.
7. mysqladmin flush-tables 실행.

- LODA DATA INFILE 과 INSERT 문에서 더 빠른 속도를 내려면 키 버퍼를 증가시킨
다. mysqld나 safe_mysqld에서 -O key_buffer=# 옵션을 사용하면 된다. 예를 들어 16M는
풍부한 램을 가졌다면 훌륭한 값이다.
- 다른 프로그램을 사용하여 데이타를 텍스트 파일로 덤프할때 SELECT ... INTO OUTFIL
E 을 사용하자. 7.15 [LOAD DATA INFILE] 참고.
- 연속으로 다량의 insert와 update를 할 때 LOCK TABLE을 사용하여 테이블에 락을 걸
면 속도를 향상시킬 수 있다. LOAD DATA INFILE 그리고 SELECT ...INTO OUTFILE
는 원자적이기 때문에 LOCK TABLE을 사용하면 안된다. 7.23 [LOCK TABLES/UNLOCK
TABLES] 참고.

테이블이 얼마나 단편화되었는지 점검하려면 '.ISM' 파일에서 isamchk -evi 를 실행한다. 1
3장 [Maintenance] 참고.



10.11 INSERT 문에서 속도에 영향을 미치는 부분 <** insert 최적화 **>

insert 하는 시간은 다음와 같이 구성된다:

    Connect: (3)
    Sending query to server: (2)
    Parsing query: (2)
    Inserting record: (1 x size of record)
    Inserting indexes: (1 x indexes)
    Close: (1)

(숫자)는 비례적인 시간이다. 이것은 테이블을 개방할때 초기의 overhead를 고려하고 있지
는 않다. (매 동시병행적으로 수행되는 질의마다 발생)

The size of the table slows down the insertion of indexes by N log N (B-trees).


테이블의 크기는 N log N(B-trees)에 따라 인덱스의 입력이 느려진다. (**말이 좀 이상. 테
이블이 커짐에 따라 인덱스 생성도 느려진다는 뜻이겠죵 **)

테이블에 락을 걸거나 insert 문에서 다중 값 목록을 사용하여 입력 속도를 빠르게 할 수
있다. 다중 값 목록을 사용하면 단일 insert 보다 5배 정도 속도가 빨라진다.

mysql> LOCK TABLES a WRITE;
mysql> INSERT INTO a VALUES (1,23),(2,34),(4,33);
mysql> INSERT INTO a VALUES (8,26),(6,29);
mysql> UNLOCK TABLES;

주요한 속도 차이는 모든 INSERT 문이 완료되고 난 후에 한번에 인덱스 버퍼가 쓰여기지
때문에 생긴다. 보통 서로 다른 여러 INSERT 문이 있으면 많은 인덱스 버퍼 플러쉬가 있
을 것이다. 모든 줄을 단일 문으로 입력하면 락은 필요없다.

락킹은 또한 다중 연결 테스트의 총 시간을 줄일 수는 있다. 그러나 어떤 스레드에서는 총
대기시간은 증가할 수 있다.(왜냐면 락을 기다리기 때문이다)
예를 들어보자:

thread 1 does 1000 inserts
thread 2, 3, and 4 does 1 insert
thread 5 does 1000 inserts

락을 사용하지 않으면 2, ,3 4는 1과 5 전에 끝마칠 것이다. 락을 사용하면 2,3,4는 아마도 1
이나 5 전에 끝나지 않을 것이다. 그러나 총 시간은 40% 빨라진다.

INSERT, UPDATE, DELETE 오퍼레이션은 mysql에서 매우 빠르다. 그렇기 때문에 줄에서
5개  이상의 insert나 update를 할 때 락을 추가하면 더 좋은 성능을 얻을 수 있다. 줄에 매
우 많은 자료를 입력한다면 다른 스레드에서 테이블에 접근하도록 하기 위해 때때로(각 100
0줄마다) UNLOCK TABLES를 사용하는 LOCK TABLES 실행하면 된다. 이렇게 하면 좋
은 성능을 낼 수 있다. (** 열심히 입력을 하고 중간에 락을 풀었다가 다시 락을 거는 것
반복함**)

물론 LOAD DATA INFILE 이 더 빠르다.



10.12 DELETE 문에서 속도에 영향을 미치는 부분 <** DELETE 문 최적화 **>

레코드를 삭제하는 시간은 정확히 인덱스 숫자에 비례한다. 레코드를 빠르게 지우기 위해
인덱스 캐쉬의 크기를 증가시킬 수 있다. 기본 인덱스 캐쉬는 1M 이다; 빠르게 삭제하기 위
해 증가되어야 한다.(충분한 메모리를 가지고 있다면 16M로 하자)


10.13 mysql에서 최대 속도를 얻는 방법

벤치마킹을 시작하자! mysql 벤치마크 스위트에서 어떤 프로그램을 사용할 수 있다. (일반
적으로 'sql-bench' 디렉토리에 있음) 그리고 입맞에 맞게 수정하자. 이렇게 하면 당신의 문
제를 해결할 수 있는 다른 해결책을 찾을 수 있으며 당신에게 가장 빠른 해결책을 테스트할
수 있다.

- mysqld를 적절한 옵션으로 시작하자. 메모리가 많을수록 속도가 빠르다.
  10.1 [MySQL parameters] 참고.
- SELECT 문의 속도를 빠르게 하기 위해 인덱스를 만들자.
10.4 [MySQL indexes] 참고.
- 가능한 효율적으로 컬럼 타입을 최적화하자. 예를 들면 가능한 NOT NULL로 컬럼을 정
의하자. 10.10 [Table efficiency] 참고.
- --skip-locking 옵션은SQL 요청에서 파일 락킹을 없앤다. 속도가 빨라지지만 다음의 과
정을 따라야 한다:
        ㅇ isamchk로 테이블을 체크하거나 수리하기 전에 mysqladmin flush-tables 로 모
든 테이블을 플러시해야 한다. (isamchk -d tbl_name은 언제나 허용된다. 왜냐하면 이건 단
순히 테이블의 정보를 보여주기 때문이다)
        ㅇ 동시에 뜬 두개의 mysql 서버가 동일한 테이블을 업데이트하려 한다면 동일한
데이터 파일에 두개의 mysql 서버를 띄우면 안된다.

        --skip-locking 옵션은 MIT-pthreads로 컴파일할때 기본값이다. 왜냐면 모든 플랫
폼의 MIT-pthreads에서 flock()가 완전하게 지원이 되지 않기 때문이다.

- 업데이트에 문제가 있다면 업데이트를 미루고 나중에 하자. 많은 업데이트를 하는 것이
한번에 하나를 업데이트하는 것보다 더 빠르다.
- FreeBSD 시스템에서 MIT-pthreads에 문제가 있으면 FreeBSD 3.0 이후 버전으로 업데
이트 하는것이 좋다. 이렇게 하면 유닉스 소켓을 사용하는 것이 가능하며(FreBSD에서 유닉
스 소켓이 MIT-pthreads에서 TCP/IP 연결을 사용하는 것보다 빠르다) 그리고 스레드 패키
지가 조정(intergrated?)되어야 한다.
- 테이블이나 컬럼 단계를 체크하는 GRANT는 성능을 떨어뜨린다.


10.14 로우 포맷과 다른 점은 무엇인가? 언제 VARCHAR/CHAR을 사용해야 하는가?

mysql은 실제의 SQL VARCHAR 타입이 없다. 그대신 mysql은 레코드를 저장하고 이것을
VARCHAR로 에뮬레이트하는데 세가지 방법이 있다.

테이블에 VARCHAR, BLOB, TEXT 컬럼이 없으면 고정 row size를 사용한다. 그외에는
동적 row size를 사용한다. CHAR 과 VARCHAR 컬럼은 애플리케이션의 관점에서 동일하
게 취급된다; 둘다 trailing space는 컬럼을 가져올때 제거된다.

isamchk -d 를 이용 테이블에서 사용하는 포맷을 체크할 수 있다.
(-d 는 "테이블 묘사"를 의미)

mysql은 세가지 다른 테이블 포맷을 가지고 있다; 고정길이, 다이나믹, 압축.


고정 길이 테이블
- 기본 포맷. 테이블에 VARCHAR, BLOB, TEXT 컬럼이 없을 때 사용.
- 모든 CHAR, NUMERIC, DECIMAL 컬럼은 컬럼 길이에 space-padded 이다. (** space-
padded를 무엇이라고 번역해야 할지 애매모호해서 **)
- 매우 빠름
- 캐쉬하기 쉽다
- 손상 후 복구가 쉽다. 왜냐면 고정된 위이에 레코드가 위치하기 때문이다.
- 많은 양의 레코드가 지워졌거나 운영 시스템에서 자유 공간을 늘리길 원치 않는다면 (isa
mchk를 이용) 재조직화할 필요없다.
- 보통 다이나믹 테이블보다 많은 디스크 공간을 필요로 한다.


다이나믹 테이블
- 테이블이 VARCHAR, BLOB, TEXT 컬럼을 포함하고 있을 때 사용.
- 모든 문자열 컬럼은 다이나믹하다.(4보다 작은 길이를 가진 문자열 제외)
- 컬럼이 문자열 컬럼에서 비었거나 ('') 숫자형 컬럼에서 0(NULL 값을 가진 컬럼과 동일
한 것이 아니다) 을 나타내는 비트맵이 모든 레코드 앞에 선행된다. 문자열 컬럼에서 trailin
g space를 제거한 후 zero의 길이를 가지거나 숫자형 컬럼이 zero의 값을 가지면 비트 맵으
로 표시되고 디스크에 저장되지 않는다. 비지 않은 문자는 문자내용에 길이 바이트만큼 추
가되어 저장된다.
- 보통 고정 길이 테이블보다 디스크 공간 절약.
- 줄의 길이를 확장하는 정보를 가지고 줄을 업데이트하면 줄은 단편화될 것이다. 이런 경
우 더 좋은 성능을 위해 때때로 isamchk -r 을 실행해야 한다. 통계적으로(?) isamchk -ei
tbl_name을 사용하자.
- 손상후 복구가 어렵다. 왜냐면 레코드가 많은 조각드로 단편화되고 링크(단편)가 없어지
기 때문이다.
- 다이나믹 사이즈 테이블의 예상되는 열 길이 :
    3
    + (number of columns + 7) / 8
    + (number of char columns)
    + packed size of numeric columns
    + length of strings
    + (number of NULL columns + 7) / 8

각 링크마다 6 바이트가 더 있다. 다이나믹 레코드는 업데이트로 레코드가 늘어날때마다 링
크된다. 각 새로운 링크는 최소 20바이트일 것이며, 그래서 다음의 확장은 아마도 동일한 링
크로 될 것이다. 그게 아니라면 다른 링크가 있을 것이다. isamchk -ed 로 얼마나 많은 링
크가 있는지 체크할 수 있다. 모든 링크는 isamchk -r 로 제거할 수 있다.(** ?? **)

There is a penalty of 6 bytes for each link. A dynamic record is linked whenever an up
date causes an enlargement of the record. Each new link will be at least 20 bytes, so th
e next enlargement will probably go in the same link. If not, there will be another link.
You may check how many links there are with isamchk -ed. All links may be removed
with isamchk -r.


압축 테이블

- 읽기 전용 테이블은 pack_isam 유틸리티로 만들 수 있다. 확장 mysql 이메일 지원을 구
입한 모든 고객은 내부적인 용도로 pack_isam을 사용할 권리가 주어진다.
- 압축해제 코드는 모든 mysql 배포판에 있으므로 pack_isam이 없는 고객도 pack_isam으
로 압축된 테이블을 읽을 수 있다. (테이블이 같은 플랫폼에서 압축되어 있는한)
- 매우 적은 디스크 용량을 사용.
- 각 레코드는 개별적으로 압축이 된다.( 매우 적은 액세스 overhead) 레코드의 헤더는 테
이블의 가장 큰 레코드에 따라 (1-3 바이트) 고정된다. 각 컬럼은 다르게 압축이 된다. 압축
타입은 다음과 같다:

        ㅇ 일반적으로 각 컬럼마다 다른 Huffman 테이블이다.
        ㅇ Suffic 공간 압축
        ㅇ Prefix 공간 압축
        ㅇ 0 값을 가진 숫자는 1비트로 저장.
        ㅇ integer 컬럼의 값이 작은 범위를 가졌다면, 컬럼은 최대한 작은 타입으로 저장
된다. 예를 들면 BIGINT 컬럼은 모든 값이 0부터 255라면 TINIINT 컬럼(1바이트)로 저장
된다.
        ㅇ 컬럼이 몇가지 가능한 값으로만 구성되어 있다면, 컬럼 타입은 ENUM으로 변환
된다.
        ㅇ 컬럼은 위 압축 방법을 조합하여 사용한다.
- 고정 길이나 다이나믹 길이의 테이블을 다룰 수 있다. 그러나 BLOB나 TEXT 컬럼은 다
룰 수 없다.
- isamchk로 압축을 해재할 수 있다.

mysql은 다른 인덱스 타입을 지원한다. 그러나 일반적인 타입은 NISAM이다. 이것은 B-tre
e 인덱스이며 모든 키의 갑을 합하여 (키 길이+4)*0.67로 인덱스 파일의 크기를 대강 계산
할 수 있다. (이것은 모든 키가 정렬된 순서로 입력된 가장 나쁜 경우이다)


String indexes are space compressed. If the first index part is a string, it will also be p
refix compressed. Space compression makes the index file smaller if the string column h
as a lot of trailing space or is a VARCHAR column that is not always used to the full
length. Prefix compression helps if there are many strings with an identical prefix.

문자열 인덱스는 공간이 압축된다. 첫번째 인덱스 부분이 문자열이라면, prefix가 압축된다.
문자열 컬럼이 다량의 trailing space를 가졌거나 언제나 완전한 길이를 사용하지 않는 VA
RCHAR 컬럼일 때 space 압축은 인덱스 파일을 더 작게 만든다. prefix 압축은 많은 문자
열에 동일한 prefix가 있을 때 유용하다.
{{<!-- This HTML file has been created by texi2html 1.52 (hacked by david@detron.se)
     from /dr1/my/masters/mysql/Docs/manual.texi on 2 Febuary 1999 -->
}}11. mysql 벤치마크 스위트

여기에는 mysql 벤치마크 스위트(그리고 crash-me)에 대한 기술적인 설명이 들어가야 한다. 그렇
지만 아직 작성이 되지 않았다. 현재로서는 배포판의 'bench' 디렉토리에서 코드와 결과를 살펴보
아야 한다.(또한 다음의 웹페이지에서 살펴볼 수 있다.
{{{{http://www.mysql.com/crash-me-choose.htmy)
}}
}}

이것은 사용자에게  주어진 SQL 수행이 제대로 수행되는지 아닌지를 알려주는 벤치마크이다.

crash-me 는 실제로 질의를 수행하여 데이터베이스에서 지원하는 기능과 능력, 제한사항 등을 측
정하는 프로그램이다. 예를 들어 다음의 사항을 측정한다:

        ㅇ 지원하는 컬럼 타입
        ㅇ 지원하는 인덱스 숫자
        ㅇ 지원하는 펑션
        ㅇ 질의의 최대 크기
        ㅇ VARCHAR 컬럼의 최대 크기
번역자 : 문태준(taejun@hitel.net)

12. mysql 유틸리티

12.1 다양한 mysql 프로그램 개요

mysql client 라이브러리를 사용하여 서버와 통신을 하는 모든 mysql 클라이언트는 다음의
환경 변수를 사용한다:

Name                    Description
MYSQL_UNIX_PORT         기본 소켓; 로컬호스트에서 접속할때 사용
MYSQL_TCP_PORT          기본 TCP/ip port
MYSQL_PWD               기본 패스워드
MYSQL_DEBUG             디버깅할때 Debug-trace 옵션
TMPDIR                  임시 테이블/파일이 생성되는 디렉토리

MYSQL_PWD 를 사용하는 것은 보안에 취약하다. 6.2 [Connecting] 참고.

'mysql' 클라이언트는 명령행 라인 히스토리에 환경 변수를 저장하기 위해 MYSQL_HISTF
ILE 이라는 파일을 사용한다.

모든 MYSQL 프로그램은 매우 다양한 옵션이 있다. 그러나 모든 MYSQL 프로그램에서 --
help 옵션을 제공한다. --help 옵션을 이용해 프로그램의 다양한 옵션에 대한 모든 정보를
볼 수 있다. 예를 들어, mysql --help 를 해보자.

아래의 목록은 mysql 프로그램에 대해서 설명하고 있다:

isamchk : mysql 테이블 정보 보기, 점검, 최적화, 복구 유틸리티. 많은 기능이 있기 때문에
별도의 장에서 자세히 설명하고 있다. 13장 참고.

make_binary_release : 컴파일된 mysql 바이너리 버전을 만든다. 다른 myql 사용자의 편의
를 위해 ftp.tcx.e의 '/pub/mysql/Incoming' 에 올리자.

msql2mysql : msql 프로그램을 mysql로 변환하는 쉘 스크립트. 모든 경우를 다룰 수는 없
지만 변환할때 유용할 것이다.

mysql : 간단한 SQL 쉘. (GNU readline 호환성있음) 상호대화식 및 비대화식으로 사용할
수 있다. 대화식으로 사용하는 경우, 질의 결과는 아스키-테이블 포맷으로 출력된다. 비대화
식으로 사용할 경우, 결과는 텝으로 분리된 포맷으로 출력된다. (출력 포맷은 명령행 라인
옵션을 이용해 바꿀 수 있다) 다음과 같이 스크립트를 사용할 수 있다:

shell> mysql database < script.sql > output.tab

클라이언트에서 메모리가 부족해서 문제가 생기면 --quick 옵션을 사용하자. 그러면 질의
결과를 가져오기 위해 mysql_store_result() 대신 mysql_use_result()를 사용한다.

mysqlaccess : host, user, database 조합의 접근 권한 점검 스크립트.

mysqladmin : 데이터베이스 생성 및 삭제, 승인 테이블 재로딩, 디스크에 테이블 플러싱, 로
그 파일 재오픈 등을 수행하는 관리자용 유틸리티. mysqladmin은 또한 서버에서 버전, 프로
세스, 상태(status) 정보를 확인할 수 있다.

mysqlbug : mysql 버그 레포트 스크립트. mysql의 버그를 알릴 때 사용하는 스크립트.

mysqld : SQL 대몬. 항상 실행되고 있어야 한다.

mysqldump : mysql 데이터베이스를 SQL문 형태의 파일이나 탭으로 구분된 텍스빚 파일로
덤프하는 유틸리티.

mysqlimport : LOAD DATA INFILE을 사용해 텍스트 파일의 자료를 테이블에 입력하는
유틸리티. 12.2 참고.

mysqlshow : 데이터베이스, 테이블, 컬럼과 인덱스에 대한 정보 출력

mysql_install_db : 기본 권한으로 MYSQL 승인 테이블 생성. 처음 설치했을때만 수행된다.

replace : msql2mysql에서 사용되는 유틸리티이다. 그렇지만 다양하게 적용할 수 있다. 파일
이나 표준 입력의 문자열을 교체할 수 있다. 먼저 긴 문자열을 매칭하기 위해 제한된 상황
의 시스템에서 사용하자(** ??) 문자열을 교체하는데 사용할 수 있다. 예를 들어 다음의 명
령어는 파일에서 a와 b를 교체한다:

shell> replace a b b a -- file1 file2 ...

safe_mysqld : mysqld 대몬을 시작하는 스크립트. 에러가 났을때 서버를 재시작하고 로그
파일에 실행 정보를 기록하는 등 몇가지 안정 대책이 있다.



12. 2 텍스트 파일에서 데이터 입력(수입?)하기

mysqlimport 는 명령행 인터페이스에서 LOAD DATA INFILE sql 문을 제공한다. 대부분
의 옵션은 LOAD DATA INFILE 과 동일하다. 7.15 [Load] 참고.
다음과 같이 사용한다:

shell> mysqlimport [options] filename ...

명령행에서 지정한 텍스트 파일에 대하여, mysqlimport는 파일이름에서 확장자를 제거한다.
그리고 파일의 내용을 어떤 테이블에 넣을 것인지 결정하는데 사용한다. 예를 들어 vkdlfdlf
madl 'patient.txt', 'patient.text', 'patient'는 모두 patient라는 테이블 이름으로 입력될 것이
다.

mysqlimport 는 다음의 옵션을 지원한다:

-C, --compress : 서버, 클라이언트에서 압축을 지원하면 서버/클라이언트 사이에서 모든
정보를 압축한다

-#, --debug[=option_string] : 프로그램 사용 추적(디버깅용)

-d, --delete : 텍스트 파일에서 입력하기 전에 테이블을 비움

--fields-terminated-by=...
--fields-enclosed-by=...
--fields-optionally-enclosed-by=...
--fields-escaped-by=...
--fields-terminated-by=...
        : LODA DATA INFILE 에서의 옵션과 동일한 기능을 갖는 옵션

-f, --force : 에러 생략.텍스트 파일을 위한 테이블이 없으면, 다른 남아있는 파일을 계속
처리(if a table for a text file doesn't exist, continue processing any remaining files) 이
옵션이 없는 경우, 테이블이 없으면 빠져나온다

--help : 도움말 출력

-h host_name, --host=host_name : 지정한 호스트의 mysql 서버에 데이타 입력. 기본값은
localhost

-i, --ignore : --replace 옵션의 정보 참고.

-l, --lock-tables : 텍스트 파일로 처리하기 전에 모든 테이블에 쓰기 락을 건다. 그러면 서
버에서 모든 테이블이 동기화될 수 있다.

-L, --local : 클라이언트에서 입력 파일 읽음. 기본적으로, localhost에서 접속하면 텍스트
파일은 서버에 있다고 가정된다.

-pyour_pass, --password[=your_pass] : 서버에 연결할 때 사용하는 비밀번호. '=your_pass
'를 지정하지 않으면 터미널에서 비밀번호를 물어봄

-P port_num, --port=port_num : 호스트에 연결할 때 사용하는 TCP/IP 숫자. (localhost가
아닌 호스트에서 접속할 때 사용. 예를 들어 유닉스 소켓을 사용하는 경우)

-r, --replace : --replace 와 --ignore 옵션은 unique key 값의 레코드가 중복되어 있을 경
우에 사용된다. --replcae 를 명시할 경우, 동일한 unique key 값을 가지고 있는 레코드를
대체한다. --ignore 를 명시할 경우, unique key 값이 동일한 레코드는 생략된다. 두 옵션
모두 명시하지 않는다면, 중복되는 키 갑이 발견되면 에러를 출력하고 텍스트 파일의 나머
지 부분은 생략이 된다.

-s, --silent : 침묵 모드. 에러가 발생했을 때만 출력.

-S /path/to/socket, --socket=/path/to/socket : 로컬호스트(기본 호스트값)에서 접속할 때
사용하는 소켓 파일.

-u user_name, --user=user_name : 서버에 연결할 때 사용하는 mysql 사용자 이름. 기본값
은 유닉스 로그인 이름.

-v, --verbose : Verbose 모드. 프로그램의 수행에 대한 상세한 정보 출력.

-V, --version : 버전 정보 출력.



12.3 mysql 압축 읽기 전용 테이블 생성기
** 이 부분은 번역 생략. 간단하게 소개만 합니다 **

pack_isam 은 10 라이센스 이상을 구입하거나 extended support 를 받을 때 사용할 수 있
는 추가 유틸리티. 바이너리로만 배포하므로 특정한 플랫폼에서만 사용 가능. 압축률은 40%
-70% 정도이다. 메모리맵을 사용하므로(mmap()) mmap()가 작동되지 않으면 문제가 생긴
다. 압축하고나서는 읽기 전용 테이블이 되며 BLOB 칼럼은 압축하지 못한다.

공개적으로 구할 수 있는 mysql에서 압축 읽기 전용 테이블을 생성하지는 못하지만 읽는
것은 가능하다. 기타 자세한 내용은 매뉴얼을 참고하자.
13. 테이블 유지보수 및 파손 복구에 isamchk 사용하기


데이터베이스 테이블의 정보를 얻을 때, 테이블 점검, 복구 및 최적화 할때 isamchk 유틸리티를 사
용할 수 있다. 다음의 섹션은 어떻게 isamchk를 사용하는지(옵션에 대한 상세한 설명 포함), 테이블
유지 계획을 어떻게 설정할 것인지, 어떻게 isamchk의 다양한 기능을 수행하기 위해 isamchk를 사
용하는지에 대해 설명하고 있다.

{{}}13.1 isamchk 명령어 사용법

isamchk 는 다음과 같이 사용한다:

shell> isamchk [options] tbl_name

옵션은 isamchk로 무엇을 할 것인지 지정한다. 아래에서 설명한다. (isamchk --help 명령으로 옵션
의 목록을 볼 수 있다) 옵션이 없을 때, isamchk는 단지 테이블을 점검한다. 더 많은 정보를 얻으려
하거나 특정한 작업이 필요하면 아래에서 설명하는데로 옵션을 지정한다.

tbl_name은 점검하기 원하는 데이터베이스 테이블이다. 데이터베이스 디렉토리가 아닌 다른 곳에
서 isamchk를 실행하면, 파일의 경로를 지정해야 한다. 왜냐하면 isamchk는 데이터베이스의 위치
에 대해서 알지 못하기 때문이다. 실제로, isamchk는 작업하려는 파일이 데이터베이스 디렉토리에
있는지 아닌지 신경을 쓰지 않는다; 데이터베이스 테이블에 해당하는 파일을 다른 곳으로 복사하
고 그곳에서 복구 작업을 할 수 있다.

원한다명 isamchk의 명령행에서 여러개의 테이블을 사용할 수 있다. 또한 이름을 인덱스 파일 이
름('.ISM' 가 붙음)으로 지정할 수 있으며 이런 경우 '*.ISM' 패턴을 사용하여 디렉토리의 모든 테이
블을 지정할 수 있다. 예를 들어 데이터베이스 디렉토리에 있다면 다음과 같이 디렉토리의 모든
테이블을 점검할 수 있다:

shell> isamchk *.ISM


If you are not in the database directory, you can check all the tables there by specifying the path to the dir
ectory:

데이터베이스 디렉토리에 있지 않으면, 디렉토리의 경로를 지정하여 모든 테이블을 점검할 수 있
다.

shell> isamchk /path/to/database_dir/*.ISM

또한 mysql data 디렉토리의 경로를 사용한 와일드 카드를 지정하여 모든 데이터베이스의 모든 테
이블을 점검할 수 있다:

shell> isamchk /path/to/datadir/*/*.ISM

isamchk는 다음의 옵션을 지원한다:

-a, --analyze
Analyze the distribution of keys. This will make some joins in MySQL faster.
키의 분포를 분석. mysql에서 특정한 조인을 빠르게 만든다.

-#, --debug=debug_options
Output debug log. The debug_options string often is 'd:t:o,filename'.
디버그 로그 출력. debug_options 문자는 흔지 'd:t:o,filename' 이다.

-d, --description
테이블의 정보 출력

-e, --extend-check
테이블을 매우 상세하게 점검. 아주 특정한 경우에만 필요하다. 일반적으로 isamchk는 이 옵션이
없어도 모든 에러를 찾을 수 있다.

-f, --force
Overwrite old temporary files. If you use -f when checking tables (running isamchk without -r), isamchk
will automatically restart with -r on any table for which an error occurs during checking.
이전의 오래된 임시 파일을 덮어씀. 테이블을 점검할때 -f를 사용하면(-r 없이 isamchk를 실행) isa
mchk는 점검하는 동안 에러가 발생하는 테이블에서 자동으로 -r 옵션을 시작한다.


--help
도움말 출력.

-i, --information
점검을 한 테이블의 통계 정보 출력.

-k #, --keys-used=#
Used with -r. Tell the NISAM table handler to update only the first # indexes. Higher-numbered indexes
are deactivated. This can be used to get faster inserts! Deactivated indexes can be reactivated by using isa
mchk -r.
-r 과 함께 사용. NISAM 테이블 핸들러에 첫 # 인덱스만 업데이트하라는 것을 알려준다. Higher-nu
mberd(?) 인덱스가 해제된다. 이것은 insert를 빠르게 할때 사용한다! 해제된 인덱스는 isamchk -r 을
사용하여 재활성화된다.

-l, --no-symlinks
복구할때 심볼릭 링크를 따르지 않는다. 일반적으로 isamchk는 심볼릭 링크가 가리키는 테이블을
복구한다.



-q, --quick
빠르게 복구하기 위해 -r 과 함께 사용. 일반적으로 원래의 데이타 파일은 건드리지 않는다; 두번째
-q를 지정하여 원래의 데이타 파일을 사용하도록 할 수 있다.

-r, --recover
복구 모드. 유일하지 않는 unique 키만 제외하고 거의 모든 것을 복구한다.

-o, --safe-recover
복구 모드. 구식 복구 방법을 사용; -r을 사용하여 복구하는 것보다 느리다. 그렇지만 -r이 다룰 수
없는 몇가지 경우에 사용할 수 있다.
(** -r이 다룰 수 없는 경우란 무엇인지 잘 모르겠네요... **)

-O var=option, --set-variable var=option
변수값 설정. 설정가능한 변수는 아래에서 설명.

-s, --silent
침묵 모드. 에러가 발생할 때만 출력을 한다. 두개의 -s(-ss)를 사용하면  isamchk에서 매우 조용하
게 작업을 할 수 있다.

-S, --sort-index
Sort index blocks. This speeds up "read-next" in applications.
인덱스 블락 정열. 애플리케이션에서 "read-next" 속도를 향상.(??)

-R index_num, --sort-records=index_num
인덱스에 따라 레코드를 정렬. 이 작업을 하면 데이타를 집중시킬 수 있고 이 인덱스를 사용한 SE
LECT 와 ORDER BY 작업의 속도를 증가시킬 수 있다. (처음에는 정렬하는 시간이 매우 느리다!)
테이블의 인덱스 번호를 찾기 위해 SHOW INDEX를 사용한다. SHOW INDEX는 isamchk에서 사용
하는 것과 같은 순서로 테이블의 인덱스를 보여준다. 인덱스는 1번부터 시작하여 번호가 매겨진
다.

-u, --unpack
Unpack a table that was packed with pack_isam.
pack_isam 으로 압축된 테이블의 압축 해제.

-v, --verbose
Verbose 모드. 정보를 출력. -d 와 -e 와 함께 사용할 수 있다. 여러개의 -v를 사용(-vv, -vvv)하여 더
자세하게 볼 수 있다.

-V, --version
isamchk 버전 출력.

-w, --wait
테이블에 락이 걸려 있으면 기다림.

--set-variable (-O) 옵션의 설정 가능한 변수는 다음과 같다:

keybuffer             default value: 520192
readbuffer            default value: 262136
writebuffer           default value: 262136
sortbuffer            default value: 2097144
sort_key_blocks       default value: 16
decode_bits           default value: 9
{{}}

13.2 isamchk 메모리 사용법

Memory allocation is important when you run isamchk. isamchk uses no more memory than you specify
with the -O options. If you are going to use isamchk on very large files, you should first decide how much
memory you want it to use. The default is to use only about 3M to fix things. By using larger values, you
can get isamchk to operate faster. For example, if you have more than 32M RAM, you could use options s
uch as these (in addition to any other options you might specify):

메모리 할당은 isamchk를 실행할 때 중요하다.isamchk는 -O 옵션에서 지정한 것 이상으로 메모리
를 사용하지 않는다. 매우 큰 파일에서 isamchk를 사용하려 하면, 얼마마 많은 메모리를 사용할 것
인지 먼저 결정해야 한다. 기본값은 문제를 고치는데 3M를 사용한다. 더 많은 값을 사용해 더 빠르
게 isamchk를 사용할 수 있다. 예를 들어 32M 이상 램을 가지고 있다면 다음과 같은 옵션을 사용할
수 있다. (사용자가 지정한 옵션에 추가하여):

shell> isamchk -O sortbuffer=16M -O keybuffer=16M \
           -O readbuffer=1M -O writebuffer=1M ...

-O sortbuffer=16M 를 사용하면 대부분의 경우에는 충분하다.

Be aware that isamchk uses temporary files in TMPDIR. If TMPDIR points to a memory file system, you
may easily get out of memory errors.
isamchk 는 TMPDIR의 임시 파일을 사용한다는 것에 주의하자. 만약 TMPDIR이 메모리 파일 시스
템을 가리킨다면 쉽게 메모리 에러에서 벗어날 수 있다.


13. 3 테이블 유지보수 설정
{{}}13.3 Setting up a table maintenance regime

문제가 생길때를 기다리는 것보다 정기적으로 테이블을 점검하는 게 좋다. 유지보수 계획를 위하
여 isamchk -s 를 사용해 테이블을 점검할 수 있다. -s 옵션을 사용하면 isamchk가 침묵 모드로 작동
을 하며 에러가 발생했을 때만 메시지를 출력한다.

서버를 시작할때 테이블을 점검하는 것도 좋은 생각이다. 예를 들어 업데이트 도중에 시스템이 리
부팅을 했을 때마다 일반적으로 영향을 받은 모든 테이블(이것을 "expected crashed table"이라고 한
다)을 점검해야 한다. 만약 오래된 '.pid' (프로세스 ID) 파일이 재부팅후에 남아 있다면 최근 24시간
동안 변경이 된 모든 테이블을 점검하기 위해 safe_mysqld에 isamchk를 실행하는 테스트를 추가해
야 한다.('.pid' 파일은 mysqld가 시작할때 만들어지며 일반적으로 mysqld가 종료될때 제거된다. 시
스템이 시작할때 '.pid' 파일이 있다는 것은 mysqld가 비정상적으로 종료되었다는 것을 나타낸다.)

더 좋은 테스트는 최근에 변경된 시간이 '.pid' 파일보다 최근인 테이블을 점검하는 것이다.

또한 일반적인 시스템 운영중에 정기적으로 테이블을 점검할 수 있다. TcX에서는 'crontab' 파일에
다음의 라인을 사용하여 일주일에 한번씩 우리의 중요한 테이블을 점검하도록 cron 작업을 돌린
다:

35 0 * * 0 /path/to/isamchk -s /path/to/datadir/*/*.ISM

이렇게 하면 손상된 테이블에 대한 정보를 출력하여 필요할때 테이블을 점검하고 복구할 수 있다.

몇년동안 우리는 예상하지 못하게 테이블이 손상(하드웨어 문제가 아닌 다른 이유로 문제가 생긴
테이블)된 경우가 없어서 우리에겐 일주일만으로도 충분하다. (이것은 정말로 진실이다)

우리만큼 mysql에 대해 신뢰를 할 때까지 최근 24시간동안 업데이트된 모든 테이블에 대해 매일
밤마다 isamchk -s 를 실행할 것을 추천한다.


13.4 테이블 정보 얻기

테이블에 대한 정보나 통계를 얻기 위해 아래의 명령을 사용하자. 뒤에서 자세하게 정보에 대해
설명할 것이다.

isamchk -d tbl_name
테이블에 대한 정보를 얻기 위해 "describe(설명) 모드"로 isamchk를 실행. mysql 서버를 --skip-locki
ng 옵션을  사용해 시작하면, isamchk는 서버가 실행되는 동안 업데이트된 테이블에서 에러가 난
것을 보고한다. 그러나 isamchk는 describe 모드에서 테이블을 변경하지 못하기 때문에 데이타를
읽을 위험이 없다.

isamchk -d -v tbl_name
isamchk가 수행하는 것에 대해 더 자세한 정보를 보기위해 -v 옵션을 추가하여 verbose 모드로 수
행할 수 있다.

isamchk -eis tbl_name
테이블에서 가장 중요한 정보만 보여준다. 전체 테이블을 다 읽어야 하기 때문에 속도가 느리다.

isamchk -eiv tbl_name
-eiv 와 비슷하지만 현재 무엇이 진행되고 있는지  보여준다.


isamchk -d 출력 예제:

ISAM file:     company.ISM
Data records:           1403698  Deleted blocks:         0
Recordlength:               226
Record format: Fixed length

table description:
Key Start Len Index   Type
1   2     8   unique  double
2   15    10  multip. text packed stripped
3   219   8   multip. double
4   63    10  multip. text packed stripped
5   167   2   multip. unsigned short
6   177   4   multip. unsigned long
7   155   4   multip. text
8   138   4   multip. unsigned long
9   177   4   multip. unsigned long
    193   1           text


isamchk -d -v 출력 예제:

ISAM file:     company.ISM
Isam-version:  2
Creation time: 1996-08-28 11:44:22
Recover time:  1997-01-12 18:35:29
Data records:           1403698  Deleted blocks:              0
Datafile: Parts:        1403698  Deleted data:                0
Datafilepointer (bytes):      3  Keyfile pointer (bytes):     3
Max datafile length: 3791650815  Max keyfile length: 4294967294
Recordlength:               226
Record format: Fixed length

table description:
Key Start Len Index   Type                      Root Blocksize Rec/key
1   2     8   unique  double                15845376      1024       1
2   15    10  multip. text packed stripped  25062400      1024       2
3   219   8   multip. double                40907776      1024      73
4   63    10  multip. text packed stripped  48097280      1024       5
5   167   2   multip. unsigned short        55200768      1024    4840
6   177   4   multip. unsigned long         65145856      1024    1346
7   155   4   multip. text                  75090944      1024    4995
8   138   4   multip. unsigned long         85036032      1024      87
9   177   4   multip. unsigned long         96481280      1024     178
    193   1           text


Example of isamchk -eis 출력 예제:

Checking ISAM file: company.ISM
Key:  1:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
Key:  2:  Keyblocks used:  98%  Packed:   50%  Max levels:  4
Key:  3:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
Key:  4:  Keyblocks used:  99%  Packed:   60%  Max levels:  3
Key:  5:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  6:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  7:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  8:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  9:  Keyblocks used:  98%  Packed:    0%  Max levels:  4
Total:    Keyblocks used:  98%  Packed:   17%

Records:          1403698    M.recordlength:     226   Packed:             0%
Recordspace used:     100%   Empty space:          0%  Blocks/Record:   1.00
Recordblocks:     1403698    Deleteblocks:         0
Recorddata:     317235748    Deleted data:         0
Lost space:             0    Linkdata:             0

User time 1626.51, System time 232.36
Maximum resident set size 0, Integral resident set size 0
Non physical pagefaults 0, Physical pagefaults 627, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 639, Involuntary context switches 28966


isamchk -eiv 출력 예제:

Checking ISAM file: company.ISM
Data records: 1403698   Deleted blocks:       0
- check file-size
- check delete-chain
index  1:
index  2:
index  3:
index  4:
index  5:
index  6:
index  7:
index  8:
index  9:
No recordlinks
- check index reference
- check data record references index: 1
Key:  1:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
- check data record references index: 2
Key:  2:  Keyblocks used:  98%  Packed:   50%  Max levels:  4
- check data record references index: 3
Key:  3:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
- check data record references index: 4
Key:  4:  Keyblocks used:  99%  Packed:   60%  Max levels:  3
- check data record references index: 5
Key:  5:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 6
Key:  6:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 7
Key:  7:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 8
Key:  8:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 9
Key:  9:  Keyblocks used:  98%  Packed:    0%  Max levels:  4
Total:    Keyblocks used:   9%  Packed:   17%

- check records and index references
[LOTS OF ROW NUMBERS DELETED]

Records:          1403698    M.recordlength:     226   Packed:             0%
Recordspace used:     100%   Empty space:          0%  Blocks/Record:   1.00
Recordblocks:     1403698    Deleteblocks:         0
Recorddata:     317235748    Deleted data:         0
Lost space:             0    Linkdata:             0

User time 1639.63, System time 251.61
Maximum resident set size 0, Integral resident set size 0
Non physical pagefaults 0, Physical pagefaults 10580, Swaps 0
Blocks in 4 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 10604, Involuntary context switches 122798



다음은 앞의 예제에서 사용한 테이블의 데이타와 인덱스 파일 크기이다:

-rw-rw-r--   1 monty    tcx     317235748 Jan 12 17:30 company.ISD
-rw-rw-r--   1 davida   tcx      96482304 Jan 12 18:35 company.ISM


isamchk가 출력하는 정보 타입에 대한 설명은 아래와 같다. "keyfile"은 인덱스 파일이다. "Record"
와 "row"는 같은 말이다.

ISAM file
        ISAM (index) 파일 이름.

Isam-version
        ISAM 포맷 버전. 현재는 항상 2.

Creation time
        데이타 파일 생성 시간.

Recover time
        인덱스/데이타 파일이 최근에 복구된 시간.

Data records
        테이블에 있는 레코드 수.

Deleted blocks
        지워진 블락이 차지하고 있는 공간. 이러한 공간을 줄이기 위해 테이블의 최적화를 할 수
있다. 13.5.3 [최적화] 참고.

Datafile: Parts
        동적인 레코드 포맷을 위해, 얼마나 많은 데이타 블락이 있는지를 알림. 단편화된 레코드
가 없는 최적화된 테이블에서는 Data records 와 같다.

Deleted data
        회수하지 않은 지원진 데이타의 바이트 수. 이렇나 공간을 없애기 위해 테이블을 최적화
할 수 있다. 13.5.3 [최적화] 참고.

Datafile pointer
        데이타 파일 포인터의 크기로 바이트수. 일반적으로 2,3,4,5 바이트이다. 대부분의 테이
블은 2바이트로 관리를 한다. 그렇지만 아직까지 mysql에서는 제어를 할 수 없다. 고정 테이블에서
이는 레코드 주소(address)이다. 동적 테이블에서 이는 바이트 주소이다.



Keyfile pointer
        인덱스 파일 포인터의 크기로 바이트. 일반적으로 1,2,3 바이트이다. 대부분의 테이블은
2바이트로 관리를 한다. 그렇지만 이 크기는 mysql에서 자동으로 계산이 된다. 항상 블락 주소이
다.

Max datafile length
        테이블의 데이터 파일(.ISD 파일)의 최대 크기. 바이트.

Max keyfile length
        테이블의 key file(.ISM 파일)의  최대 크기. 바이트.

Recordlength
        각 레코드가 차지하고 있는 공간. 바이트.

Record format
테이블의 레코드를 저장하는데 사용된 포맷. 위에서 보여준 예제는 고정 길이를 사용하고 있다.
다른 값은 Compressed 와 Packed 이다.

table description
        테이블의 모든 키의 목록. 각 키에 대한 자세한 설명은 다음과 같다:
Key
        키의 숫자.
Start
        Where in the record this index part starts.
        레코드에서 인덱스가 시작하는 위치.
Len
How long this index part is. For packed numbers, this should always be the full length of the column. For
strings, it may be shorter than the full length of the indexed column, because you can index a prefix of a st
ring column.
        인덱스 부분의 길이. For packed numbers(꽉 찬 숫자를 위해??? 번역이 이상..), 컬럼의 총
길이가 되어야 한다. 문자열에서는 인덱스된 컬럼의 총 길이보다 작아야 한다. 왜냐하면 문자열
컬럼 앞에 인덱....

Index
        이 인덱스에 같은 값이 여러개 존재할 수 있는지 없는지를 나타냄.
Type
        인덱스 부부의 데이터 타입. packed, stripped, empty 옵션을 가진 NISAM 데이타 타입이
다.
Root
        루트 인덱스 블락의 주소.
Blocksize
        각 인덱스 블락의 크기.기본값은 1024이다. 그렇지만 이 값은 컴파일 할때 변경할 수 있
다.
Rec/key
This is a statistical value used by the optimizer. It tells how many records there are per value for this key.
A unique key always has a value of 1. This may be updated after a table is loaded (or greatly changed) wit
h isamchk -a. If this is not updated at all, a default value of 30 is given.
        최적화기(optimizer)에서 사용하는 통계적인 값. It tells how many records there are per valu
e for this key. unique 키는 항상 1의 값을 가진다. 이 값은 isamchk -a로 테이블이 로딩된 후에(또는
매우 많이 변경되었을때) 업데이트된다. 전혀 업데이트되지 않으면 기본값으로 30이 주어진다.


위의 첫번째 예제에서, 9번째 키는 두부분을 가진 멀티-파트 키이다.


Keyblocks used
What percentage of the keyblocks are used. Since the table used in the examples had just been reorganize
d with isamchk, the values are very high (very near the theoretical maximum).
        키블락이 사용하고 있는 비율.(%) 예제의 테이블은 isamchk로 재조직화(reorganize)되었
기 때문에 값이 매우 높다.(이론적인 최대값에 매우 근접)

Packed
MySQL tries to pack keys with a common suffix. This can only be used for CHAR/VARCHAR/DECIM
AL keys. For long strings like names, this can significantly reduce the space used. In the third example ab
ove, the 4th key is 10 characters long and a 60% reduction in space is achieved.
....  이름과 같은 long 문자열에서 공간 사용을 상당히 줄인다. 위의 네번째 예제에서 4번째 키는 10
문자 long 이고 60%의 공간이 줄었다.
(** 번역이 잘 안되는데 접미사같은 것을 붙여서 문자열 등의 공간을 줄인다 머 그런 것이겠지요 *
*)

Max levels
        How deep the B-tree for this key is. Large tables with long keys get high values.

Records
        테이블의 레코드수.
M.recordlength
        평균 레코드 길이. 고정 길리 레코드의 테이블에서 이 값은 레코드 길이와 같다.

Packed
        MySQL strips spaces from the end of strings. The Packed value indicates the percentage saving
s achieved by doing this.


mysql은 문자끝의 공백을 제거한다.Packed value는 이렇게 해서 절약된 공간의 비율을 말한다.

Recordspace used
        데이타 파일이 사용하는 공간의 비율.

Empty space
        데이타 파일이 사용하지 않는 공간의 비율.

Blocks/Record
        레코드당 평균 블락수.(즉, 단편화된 레코드가 몇개의 링크로 구성되어 있는지) 고정-포
맷 테이블에서는 항상 1이다. 이 값은 가능한한 1에 가깝게 유지해야한다. 이 값이 너무 커지면 isa
mchk로 테이블을 최적화(reorganize)해야 한다. 13.5.3 [Optimizaiton] 참고.

Recordblocks
        사용하는 블락(링크)수. 고정 포맷에서 이값은 레코드수와 같다.

Deleteblocks
        삭제된 블락(링크)수.

Recorddata
        데이타 파일이 사용하는 바이트수.

Deleted data
        데이터 파일에서 삭제된(사용하지 않는) 바이트수.

Lost space
        레코드가 매우 짧은 길이로 업데이트되면 약간의 공간을 잃게 된다. 이 값은 이러한 공간
의 bytes 합계이다.

Linkdata
        동적 테이블 포맷을 사용할 때,레코드 조각은 포이터로 링크된다.Linkdata는 이런 포인터
에서 사용하는 저장 공간의 합이다.


pack_isam으로 테이블을 압축했으면, isamchk -d 는 각 테이블 컬럼에 대한 추가적인 정보를 출력
한다.이러한 정보와 그 정보가 무엇을 의미하는지에 대해서는 12.3 [pack_isam]을 참고.


{{}}13.5 파손 복구에 isamchk 사용하기.
mysql에서 데이타를 저장하는데 사용하는 파일 포맷은 광범위하게 테스트되었다. 그렇지만 데이
터베이스 테이블의 손상될 수 있는 외부적인 상황이 항상 있다:



ㅇ 쓰기 도중에 mysqld 프로세스가 죽었을때.
ㅇ 예상치 못하게 컴퓨터가 셧다운되었을때(예를 들어, 컴퓨터의 전원이 나가는 경우)
ㅇ 하드웨어 에러

이번 절에서는 mysql 데이터베이스에서 data의 손상을 체크하고 이에 대처하는 방법에 대해서 설
명한다.

손상 복구 작업을 할 때 테이터베이스의 각 테이블 tbl_name은 데이터베이스 디렉토리의 세 파일
에 조응한다는 것에 대해서 이해하고 있는 것이 중요하다:

파일                    용도
`tbl_name.frm'            테이블 정의(형식) 파일
`tbl_name.ISD'            데이타 파일
`tbl_name.ISM'           인덱스 파일


세가지 파일 타입은 다양한 방법으로 손상을 당한다. 그렇지만 대부분의 문제는 데이타 파일과 인
덱스 파일에서 생긴다.

isamchk는 '.ISD' (데이타) 파일의 복사복을 만들어 작업을 한다. 이전의 '.ISD' 파일을 제거하고 새
로운 파일을 이전의 파일 이름으로 바꾸면서 복구 작업을 마친다. --quick 옵션을 사용하면 isamchk
는 임시 '.ISD' 파일을 만들지 않는다. 대신 '.ISD' 파일이 정확하다고 가정하여 '.ISD' 파일은 손대지
않고 새로운 인덱스 파일만 생성한다. isamchk는 자동으로 'ISD' 파일이 손상되었는지 확인하고 손
상되었을 경우 복구 작업을 중지하므로 --quick 옵션을 사용하는 것은 안전하다. 두개의 -quick 옵
션을 사용할 수 있다. 이런 경우 특정한 에러(중복된 키 등)에서 취소를 하지는 않지만 '.ISD' 파일
을 수정하여 문제를 해결하려고 한다.일반적으로 두개의 --quick 옵션을 사용하는 것은 복구작업
을 수행하기 위한 디스크 공간이 거의 없을 경우에만 유용하다. 이런 경우 isamchk를 수생하기전
에 최소한 백업을 해 놓아야 한다.

{{}}
13.5.1 에러가 났을때 테이블 점검 방법

테이블을 점검하기 위해 다음의 명령을 사용한다:
:
isamchk tbl_name
        모든 에러의 99.99%를 발견할 수 있다. 이 경우 발견하지 못하는 것은 데이타 파일과 관
련된 손상이다.(일반적으로 거의 생기지 않는다) 테이블을 점검하고자 한다면 일반적으로는 아무
런 옵션을 주지 않거나 -s 나 --silent 옵션을 주어 isamchk를 수행하는 것이다.

isamchk -e tbl_name
        이 옵션은 모든 데이터를 완전하게 점검한다.( -e 는 "extended check" 를 의미한다) 모든
키가 정확한 레코드를 가리키고 있는지 점검한다.It does a check-read of every key for each row to ve
rify that they indeed point to the correct row. 많은 키를 가진 큰 테이블에서는 시간이 많이 걸린다. is
amchk는 일반적으로 첫번째 에러를 발견하면 실행을 멈춘다. 더 많은 정보를 얻고자 한다면, --ver
bose (-v) 옵션을 추가할 수 있다. 이 옵션을 추가하면 isamchk는  최대 20개의 에러가 있을 때까지
계속 실행을 한다. 일반적으로는 간단한 isamchk (테이블 이름 외에 아무런 인수도 없는)만으로 충
분하다.

isamchk -e -i tbl_name
        위의 명령과 같다. 그렇지만 -i 옵션을 붙이면 isamchk가 정보의 통계를 출력한다.


13.5.2 테이블 복구방법

손상된 테이블의 징후는 일반적으로 질의가 갑자기 중지되고 다음과 같은 에러를 낸다:
ㅇ`tbl_name.frm' is locked against change
ㅇCan't find file `tbl_name.ISM' (Errcode: ###)
ㅇGot error ### from table handler (Error 135 is an exception in this case)
ㅇUnexpected end of file
ㅇRecord file is crashed

이런 경우, 테이블을 고쳐야 한다. isamchk는 일반적으로 잘못된 것을 감지하고 대부분을 고친다.

복구 과정은 아래에서 설명하는대로 4단계가 있다.시작하기 전에 먼저 데이타베이스 디렉토리로
이동하고(cd 명령 이용) 테이블 파일의 퍼미션을 확인해야 한다. mysqld를 실행할 수 잇는 유닉스
사용자가 읽을 수 있는지 확인해야 한다. (또한 작업을 하려는 사용자. 왜냐하면 점검하려는 파일
에 접근해야 하기 때문이다) 파일을 수정해야 한다면 파일에 쓰기 권한이 있어야 ㅎ난다.

1단계 : 테이블 점검

isamchk *.ISM 또는 (충분한 시간이 있다면 isamchk -e *.ISM). 불필요한 정보를 보지 않으려면 -s (s
ilent) 옵션을 사용한다.

isamchk에서 에러가 있다고 알리는 테이블만 고쳐야 한다. 이런 테이블의 경우는 2단계로 넘어간
다.

점검하면서 에러를 만났을 때(out of memory 에러 등) 또는 isamchk가 기능을 멈추었을 때 3단계로
넘어간다.


2단계 : 쉽고 안전한 복구

먼저 isamchk -r -r tbl_name을 시도한다. (-r -q는 "빠른 복구 모드"를 의미) 이경우 데이타 파일은 손
대지 않고 인덱스 파일 복구를 시도한다. 데이타 파일이 제대로 되어 있고 삭제 링크가 데이타 파
일내의 정확한 위치를 가리키고 있다면, 원활하게 작동을 하고 테이블을 고칠 것이다.(If the data fi
le contains everything that it should and the delete links point at the correct locations within the data file, t
his should work and the table is fixed.) 다음 테이블을 고치자. 그게 아니라면 다음 과정을 사용한다:

        1. 진행하기 전에 데이타 파일의 백업본 만들기
        2. isamchk -r tbl_name 사용.(-r 는 "복구 모드" 의미) 그러면 데이타 파일에서 정확하지 않
은 레코드와 삭제된 레코드를 제거하고 인덱스 파일을 재구성한다.
        3. 앞의 과정이 실패하면, isamchk --safe_recover tbl_name을 사용. Safe recovery 모드는 구
식 복구 방법을 사용하며 일반적인 복구 모드로 할 수 없는 몇가지 경우에 사용할 수 있다.(그렇지
만 더 느리다)


점검하면서 에러를 만났을 때(out of memory 에러 등) 또는 isamchk가 기능을 멈추었을 때 3단계로
넘어간다.


3단계 : 어려운 복구

인덱스 파일의 첫 16k 블락이 파괴되거나 정확하지 않은 정보를 가지고 있을 때, 또는 인덱스 파일
이 없는 경우에만 이번 단계까지 온다. 이경우 새로운 인덱스 파일을 만들어야 한다. 다음과 같이
하자:

        1. 데이타 파일을 안전한 장소로 이동.
        2. 새로운(빈) 데이타와 인덱스 파일을 만들기 위해 table description 파일을 사용:
                shell> mysql db_name
                mysql> DELETE FROM tbl_name;
                mysql> quit
        3. 이전의 데이타 파일을 새롭게 만든 데이터 파일로 복사. (이전의 데이타 파일을 새로운
파일로 옮기지는 말자; 잘못되었을 경우 복사본을 유지하길 원할 것이다)

2단계로 가자. isamchk -r -q는 이제 제대로 작동을 할 것이다. (무한 루프가 되면 안된다. This shoul
dn't be an endless loop).



4단계 : 매우 어려운 복구

description 파일 또한 손상을 입었을 경우에만 이번 단계까지 온다. description 파일은 테이블을 만
든 이후에 변경이 되지 않기 때문에, 이러한 경우는 결코 생겨서는 안된다.

        1. 백업본에서 description 파일을 복구해 3단계로 넘어간다. 또한 인덱스 파일을 복구할
수 있고 2단계로 넘어간다. 뒤의 경우 isamchk -r로 시작을 해야 한다.
        2. 백업본이 없지만 정확히 어떻게 테이블을 만들었는지 알고 있다면, 다른 데이터베이
스에 테이블의 복사본을 만든다. 새로운 데이타 파일을 제거하고 다른 데이터베이스의 description
과 인덱스 파일을 손상된 데이터베이스로 옮긴다. 이렇게 하면 새로운 description 과 인덱스 파일
을 얻을 수 있지만 데이타 파일만 따로 남아있다. 2단계로 가서 인덱스 파일을 재구성한다.

13.5.3 테이블 최적화

레코드를 삭제하거나 업그레이드 하면서 생긴 단편화된 레코드를 모으고 불필요하고 낭비된 공간
을 제거하기 위해 복구 모드로 isamchk를 실행한다:

        shell> isamchk -r tbl_name

SQL OPTIMIZE TABLE 문을 이용하여 같은 방법으로 테이블을 최적화할 수 있다. OPTIMIZE TA
BLE 은 쉽지만 isamchk가 더 빠르다.

또한 isamchk는 테이블의 성능을 향상시킬 수 있는 몇가지 옵션을 사용할 수 있다:

-S, --sort-index
        high-low 순서로 인덱스 트리 블락을 정열. 검색을 최적화하고 키에 의한 테이블 검색을
빠르게 한다.
-R index_num, --sort-records=index_num
        인덱스에 따라 레코드를 정열. 데이타를 지역화하고 이 인덱스를 사용하는 SELECT 와 O
RDER BY 오퍼레이션의 속도를 향상시킨다. (처음에는 정열을 하는 시간이 엄청 느리다!) 테이블
의 인덱스 번호를 확인하려면 SHOW INDEX를 사용하면 되며, SHOW INDEX는 isamchk가 인덱스
를 검색하는 순서대로 테이블의 인덱스를 보여준다. 인덱스는 1번부터 번호가 매겨진다.
-a, --analyze
        테이블에서 키의 분포를 분석. 나중에 테이블에서 레코드를 가져올 때 조인의 성능을 향
상시킨다.
15. mysql ODBC 지원


mysql은 MyODBC 프로그램을 통해 ODBC에 대한 지원을 제공한다.

15.1 MyODBC 를 지원하는 운영체제

MyODBC 는 윈도우95와 NT에서 32비트 ODBC(2.50) 레벨 0 드라이버이다. 우리는 누군가가 윈
도우 3.x 에 이 프로그램을 포팅해주길 바란다.
(** 당근, 저는 능력안됨 **)


15.2 MyODBC에 문제가 있는 경우

ODBC는 액세스, Admndemo.exe, C++-빌더, Centura Team Developer (formerly Gupta SQL/Win
dows), 콜드퓨전(솔라리스용), 크리스탈 레포트, 델파이, 엑셀, iHTML, FileMaker Pro, 폭
스프로, 노츠 Notes 4.5/4.6, SBSS, perl DBD-ODBC, 파라독스, 파워빌더, VC++, 비주얼 베
이직에서 테스팅되었다.

MyODBC 에서 잘 작동하는 다른  애플리케이션이 있으면 myodbc@tcx.se 에 메일을  보내주세
요~ (** 이정도는 해 주어야 서로서로 좋겠지용**)

어려움에 부딪치면, ODBC 매니저에서의 로그 파일과 MyODBC 로그에 대해서 알고 싶다. 이런
파일이 있으면 문제를 조금이나마 줄이는데 도움이 될 것이다.

MyODBC log 파일을 얻으려면 MyODBC 연결/설정 화면의 'Trace MyODBC' 옵션에 체크를 한다.
로그는 `c:\myodbc.log' 에 기록될 것이다. 이 옵션이 제대로 작동하려면 MYSQL2.DLL 이 아
니라 MYSQL.DLL 을 사용해야 한다는 것을 기억하자!


15.3 MyODBC 와 잘 작동하는 프로그램

대부분의 프로그램은 myodbc 와 잘 작동한다. 그렇지만 아래의 각 목록에 있는 것은 우리가
직접 테스팅하였거나 다른 사람들이 제대로 작동한다고 확증해 준 것이다::

ㅇ액세스
액세스와는 잘 작동한다:
        - 테이블에서 프라이머리 키를 지정해야 한다.
        - 업데이트가 되길 원하는 모든 테이블에 timestamp를 가지고 있어야 한다.
        - double float 필드만을 사용해야 한다. single floats 와 비교를 하면 실패한다.
        - mysql에 연결할 때 'Return matching rows' 옵션 필드에 체크를 하자.
        - NT에서의 액세스는 BLOB 컬럼을 OLE OBJECTS 로 보고한다. 대신 MEMO 컬럼을 가
지길 원하면 ALTER TABLE 을 이용해 컬럼을 TEXT 로 바꾸자.

ㅇ 엑셀
잘 작동한다 몇가지 팁이 있다:

dates 에서 문제가 있으면 CONCAT() 함수를 사용하여 string 으로서 select 를 사용하자.
예를 들면:

        select CONCAT(rise_time), CONCAT(set_time) from sunrise_sunset;


문자열로서 값을 가져오며 엑셀97에서 time 값이 제대로 인식될 것이다.

이 예제에서 CONCAT()의 목적은 ODBC가 컬럼을 "string type"으로 생각하도록 속이는 것이
다. CONCAT() 가 없으면, ODBC는 컬럼을 time 타입으로 인식하며 엑셀은 이것을 이해하는데
실패한다.

이것은 엑셀의 버그라는 것을 기억하자. 엑셀은 자동적으로 문자열(string)을 time으로 변
환한다. 소스가 텍스트 파일이라면 잘 될 것이다. 그렇지만 소스가 각 컬럼의 정확한 타입
을 보고하는 ODBC 연결이라면 분명히 어리석은 짓이다.

ㅇ odbcadmin
ODBC 테스트 프로그램.


ㅇ 델파이
DBE 3.2 나 이후 버전을 사용해야 한다. mysql에 연결할 때 'Don't optimize column width'
옵션 필드에 체크를 한다.

물론, 여기에는 myodbc 를 위한 ODBC 목록과 BDE 목록을 세팅하기 위해 잠재적으로 유용한
델파이 코드가 있다. (BDE 목록은 델파이 슈퍼 페이지에서 공개로 받을 수 있는 BDE Alias
데이터를 필요로 한다) : (Thanks to Bryan Brunton bryan@flesherfab.com for this)

fReg:= TRegistry.Create;
          fReg.OpenKey('\Software\ODBC\ODBC.INI\DocumentsFab', True);
          fReg.WriteString('Database', 'Documents');
          fReg.WriteString('Description', ' ');
          fReg.WriteString('Driver', 'C:\WINNT\System32\myodbc.dll');
          fReg.WriteString('Flag', '1');
          fReg.WriteString('Password', ");
          fReg.WriteString('Port', ' ');
          fReg.WriteString('Server', 'xmark');
          fReg.WriteString('User', 'winuser');
          fReg.OpenKey('\Software\ODBC\ODBC.INI\ODBC Data Sources', True);
          fReg.WriteString('DocumentsFab', 'MySQL');
          fReg.CloseKey;
          fReg.Free;

          Memo1.Lines.Add('DATABASE NAME=');
          Memo1.Lines.Add('USER NAME=');
          Memo1.Lines.Add('ODBC DSN=DocumentsFab');
          Memo1.Lines.Add('OPEN MODE=READ/WRITE');
          Memo1.Lines.Add('BATCH COUNT=200');
          Memo1.Lines.Add('LANGDRIVER=');
          Memo1.Lines.Add('MAX ROWS=-1');
          Memo1.Lines.Add('SCHEMA CACHE DIR=');
          Memo1.Lines.Add('SCHEMA CACHE SIZE=8');
          Memo1.Lines.Add('SCHEMA CACHE TIME=-1');
          Memo1.Lines.Add('SQLPASSTHRU MODE=SHARED AUTOCOMMIT');
          Memo1.Lines.Add('SQLQRYMODE=');
          Memo1.Lines.Add('ENABLE SCHEMA CACHE=FALSE');
          Memo1.Lines.Add('ENABLE BCD=FALSE');
          Memo1.Lines.Add('ROWSET SIZE=20');
          Memo1.Lines.Add('BLOBS TO CACHE=64');
          Memo1.Lines.Add('BLOB SIZE=32');

          AliasEditor.Add('DocumentsFab','MySQL',Memo1.Lines);


ㅇ C++빌더
BDE 3.0과 테스팅을 했다. 유일하게 알려진 문제는 테이블 스키마를 변경할 대로 질의 필드
가 업데이트되지 않는다. 그런데 BDE는 문제는 아닌 것 같지만 index PRIMARY 에서만 프라
이머리 키를 인식하지 못하는 것으로 보인다.
Tested with BDE 3.0. The only known problem is that when the table schema changes, q
uery fields are not updated. BDE however does not seem to recognize primary keys, onl
y the index PRIMARY, though this has not been a problem.


ㅇ 비주얼 베이직
테이블을 업데이트 가능하게 하려면 테이블의 프라이머리 키를 정의해야 한다.
(** 이 부분은 제가 출력한 ps 파일에는 없는데 웹사이트에는 있네요... **)
{{}}


15.4 ODBC 관리자 프로그렘 설정 방법

윈도우 95에서 서버의 이름을 지정하는 것에는 세가지 방법이 있다:

- 서버의 IP 주소 사용.
-'lmhosts' 파일에 다음의 정보 추가:
        ip hostname
예를 들면
        194.216.84.21 my
- DNS를 사용하여 PC를 설정

"ODBC setup" 을 채우는 예제:

Windows DSN name:   taejun
Description:        This is my love database
MySql Database:     love
Server:             194.216.84.21
User:               taejun
Password:           my_password
Port:

윈도우즈 DSN 이름 필드의 값은 윈도우즈 ODBC 셋업에서 유일한 값이다.

ODBC 셋업 화면에서 서버, 유저, 패스워드, 포드 필드에 값을 지정할 필요는 없다. 그러나
지정을 해두면 그 값이 연결을 시도할 때 기본값으로 사용된다. 그때마다 값을 바꿀 수 있
다.

포트 번호가 주어지지 않으면, 기본 포트(3306)이 사용된다.


15.5 ODBC에서 AUTO_INCREMENT 컬럼의 값 가져오기

일반적인 문제는 INSERT 에서 어떻게 자동으로 생성되는 ID 값을 가져올 수 있느냐이다. OD
BC에서 다음과 같이 할 수 있다. (auto 가 AUTO_INCREMENT 필드라고 가정):

INSERT INTO foo (auto,text) VALUES(NULL,'text');
SELECT LAST_INSERT_ID();

또는, 다른 테이블에 ID를 입력한다면 다음과 같이 할 수 있다:

INSERT INTO foo (auto,text) VALUES(NULL,'text');
INSERT INTO foo2 (id,text) VALUES(LAST_INSERT_ID(),'text');

다른 ODBC 애플리케이션(최소한 델파이와 액세스)에서 유용하게 사용하기 위해 다음의 질의
를 새롭게 입력된 열을 찾는데 사용할 수 있다:

SELECT * FROM tbl_name WHERE auto IS NULL;
17. 일반적인 문제 해결 방법

17. 1. 데이터베이스 복사(복제?)

데이터베이스를 복사하는 가장 일반적인 방법은 업데이트 로그를 이용하는 것이다. 9.2 [Th
e update log] 참고. 이 경우 마스터로 작동하는 데이터베이스 하나(데이터가 변경된 곳)와
슬레이브로 작동하는 다른 하나의 데이터베이스가 필요하다. 슬레이브를 업데이트하려면 단
지 mysql < update_log을 하면 된다. 슬레이드 데이터베이스에 맞는 호스트, 유저, 패스워
드 옵션을 지정한다. 그리고 입력값으로 마스터 데이터베이스의 업데이트 로그를 사용한다.

테이블에서 삭제한 것이 없다면, 마지막으로 복사를 한 후 (마지막으로 복사한 시간을 비
교) 테이블에서 입력되거나 변경된 열을 찾아내기 위해 TIMESTAMP 컬럼을 사용할 수 있고
미러링되는 데이터베이스에 변경된 자료만 복사를 한다.

업데이트 로그(for deletes)와 timestamps(on both sides)를 같이 사용하여 두가지 방법으
로 업데이트하는 시스템을 만들 수 있다. 그러나 이런 경우 두가지 ends(?)에서 변경된 동
일한 데이터에서 충돌을 관리할 수 있어야 한다. 아마도 어떤 것이 업데이트되었는지 결정
하기 위해 예전 버전을 유지하고 싶을 것이다.

It is possible to make a two-way updating system using both the update log (for delet
es) and timestamps (on both sides). But in that case you must be able to handle confl
icts when the same data have been changed in both ends. You probably want to keep the
old version to help with deciding what has been updated.

이 경우 복사(복제)는 SQL문으로 이루어지기 때문에, 데이터베이스를 업데이트하는 문장에
서 다음의 함수를 사용해서는 안된다; 여기에서는 원본 데이터베이스와 동일한 값을 반환하
지 않을 수 있다:

     DATABASE()
     GET_LOCK() and RELEASE_LOCK()
     RAND()
     USER(), SYSTEM_USER() or SESSION_USER()
     VERSION()

timestamp는 필요한 경우에 미러되는 곳으로 보내기지 때문에 모든 time 함수는 안전하게
사용할 수 있다. LAST_INSERT_ID() 또한 안전하게 사용할 수 있다.

All time functions are safe to use, as the timestamp is sent to the mirror if needed.
LAST_INSERT_ID() is also safe to use.


17.2 데이터베이스 백업

mysql 테이블은 파일로 저장되기 때문에 백업하기가 쉽다.  일관된 백업 작업을 위해
관련된 테이블에 LOCK TABLES를 실행하자. 7.23 [LOCK TABLES/UNLOCK TABLES synta
x]를 참고. 단지 읽기 락만이 필요하다; 데이터베이스 디렉토리의 파일 복사본을 만드
는 동안에도 다른 스레드에서는 테이블에 질의를 계속 할 수 있다. SQL 레벨의 백업을
하고자 한다면 SELECT INTO OUTFILE을 사용할 수 있다.

데이터베이스를 백업하는 다른 방법은 mysqldump 프로그램을 사용하는 것이다:

데이터베이스에 대한 풀 백업 실행:
    
shell> mysqldump --tab=/path/to/some/dir --lock-tables --opt
    
     서버에서 업데이트를 하지 않는한 간단하게 모든 테이블 파일(`*.frm', `*.ISD' , `*.
     ISM' 파일)을 복사할 수 있다. mysqld가 실행되고 있으면 멈추어야 한다. 그러고나서
     --log-update 옵션으로 다시 시작하자. ''hostname.n'의 형식을 가진 로그 파일이 생
     성될 것이다. n은 mysqladmin refresh, mysqladmin flush-logs, the FLUSH LOGS 문,
     또는 서버를 재시작할때마다 증가하는 숫자이다. 이렇게 생긴 로그 파일을 이용해 mys
     qldump를 수행하고 나서 데이터베이스에 변화된 내용을 복사(복제)하는데 필요한 정보
     를 얻을 수 있다.
    
복원하고자 한다면, 먼저 isamchk -r을 사용해 테이블을 복구하자. 모든 경우 99.9%가 제대
로 수행된다. isamchk가 실패하면 다음의 과정대로 따르자:

       
     기존의 mysqldump 백업을 복원한다.
     업데이트 로그에서 업데이트를 다시 수행하기 위해 다음의 명령을 실행한다:
    
shell> ls -1 -t -r hostname.[0-9]* | xargs cat | mysql

ls는 정확한 순서대로 로그 파일을 가져오는데 사용된다.

또한 SELECT * INTO OUTFILE 'file_name' FROM tbl_name을 이용해 선택적인 백업을 할 수
있으며 레코드가 중복되는 것을 방지하기 위해  LOAD DATA INFILE 'file_name' REPLACE ... 
을 이용해 복원할 수 있다. 이경우에는 테이블에서 PRIMARY 키나 UNIQUE 키가 필요하다. RE
PLACE 키워드는 새로운 레코드에서 unique 키 값이 같은 이전의 레코드가 중복되는 경우 이
전의 레코드를 새로운 레코드로 교체한다.


17.3 같은 머신에서 여러개의 mysqld 서버 실행하기
같은 머신에서 다중의 서버를 사용하길 원할 수 있다. 예를 들어, 이전의 서버를 그대
로 두고 새로운 mysql 릴리즈를 테스팅하는 경우가 있을 수 있다. 또는 다른 고객들
에게 독립적인 mysql 설치를 제공하길 원하는 인터넷 서비스 제공자일 수 있다.

다중 서버를 사용하길 원하면, 가장 쉬운 방법은 다른 TCP/IP 포트와 소켓 파일로 서버를
컴파일해서 서버에서 동일한 TCP/IP 포트나 소켓 파일을 청취하지 않도록 할 수 있다.

이미 사용하고 있는 서버가 기본 포트와 소켓 파일로 구성되어 있다고 가정해보자. 그러면
다음과 같은 명령으로 새로운 서버를 설정하자:

shell> ./configure  --with-tcp-port=port_number \
             --with-unix-socket=file_name \
             --prefix=/usr/local/mysql-3.22.9

여기서 port_number와 file_name은 기본 포트 숫자 및 소켓 파일의 경로와는 달라야하며, -
-prefix 값은 현재 설치되어 있는 mysql과는 다른 디렉토리를 지정해야 한다.

Here port_number and file_name should be different than the default port number and s
ocket file pathname, and the --prefix value should specify an installation directory
different than the one under which the existing MySQL installation is located.

다음의 명령으로 현재 실행되고 있는 mysql 서버의 소켓과 파일을 확인할 수 있다:

shell>; mysqladmin -h hostname --port port_number variables

사용하고 있는 포트에서 실행되고 있는 mysql 서버가 있다면, 소켓 이름을 포함해 mysql의
가장 중요한 설정 변수의 목록을 알 수 있다. 다중 mysqld 서버를 시작하고 중지시키기 위
해 시스템의 초기화 스크립트(일반적으로 ''mysql.server')를 수정해야 한다.

다른 포트와 소켓으로 서버를 시작하기 위해 새로운 mysql 서버를 재컴파일할 필요는 없다.
safe_mysqld를 시작할 때 옵션으로 포트와 소켓을 지정할 수 있다:

shell>; /path/to/safe_mysqld --socket=file-name --port=file-name

동일한 데이터베이스 디렉토리에서 로그를 기록하도록 하면서 또 다른 서버를 실행하고자
한다면, safe_mysqld 에 --log 와 --log-update 를 이용해 로그 파일의 이름을 지정해 주어
야 한다. 그렇지 않으면 두 서버가 같은 로그 파일에 기록을 하려고 할 것이다.

주의 : 일반적으로 동일한 데이터베이스의 자료를 업데이트하는 두개의 서버를 사용해서는
안된다! 운영체제에서 fault-free 시스템 로킹(locking)을 지원하지 않는다면,  좋지 않은
결과를 보게 될 것이다. (** fault-free란 정확히 무엇인지 모르겠군요. 아마도 락을 거는
데 문제가 있다면 그 락을 해제하는 것으로 보입니다. **)

두번재 서버에서 다른 데이터베이스 디렉토리를 사용하기 원하면 safe_mysqld 에 --datadir
=path 옵션을 사용할 수 있다.

다른 포트에서 실행중인 mysql 서버에 접근하길 원한다면 다음의 방법을 사용할 수 있다:

        ㅇ 클라이언트에서 다음의 옵션을 가지고 시작. --host 'hostname'  --port=port-n
umer or [--host localhost] --socket=file-name.
        ㅇ C나 펄 프로그램에서 mysql 서버에 접속할 때 포트와 소켓 인자를 준다.
        ㅇ 클라이언트를 시작하기 전에 MYSQL_UNIX_PORT 와 MYSQL_TCP_PORT 환경 변수를
설정. 일반적으로 특정한 소켓이나 포트를 사용하면,  'login' 파일에 환경 변수를 설정하
자. 12.1 [Programs] 참고.
        ㅇ 홈 디렉토리에서 '.my.cnf' 파일에 기본 소켓과 TCP/IP 소켓을 지정.  4.15.4
[Option files] 참고.





18 MySQL client tools and APIs

18.1 MySQL C API

C API 코드는 MYSQL에 함께 배포되며, 이것은 mysqlclient 라이브러리에 포함되어져 C 프
로그램으로 하여금 데이터베이스에 접근할 수 있도록 해준다. MySQL 소스 배포판의 많은
클라이언트들이 C로 코딩되어 있으며, C API를 사용하는 방법에 대한 설명을 찾고자 할 때
이 클라이언트들의 코드를 참조할 수 있다.

18.2 C API datatypes
-----------------------------------------------------------------------------------------
|데이터 형식       | 설명 |
-----------------------------------------------------------------------------------------
|  MYSQL       | 데이터 베이스와의 하나의 연결을 다루는 구조체로서 거의 모든     |
|       | MySQL 함수들에서 사용된다. |
-----------------------------------------------------------------------------------------
|  MYSQL_RES       | 행을 리턴하는 질의들(SELECT, SHOW, DESCRIBE, EXPLAIN)의 결 |
|       | 과를 표현하는 구조체로서 어떤 질의의 결과로서 리턴되는 정보들   |
|       | 을 결과 셋(result set)이라고 부른다. |
-----------------------------------------------------------------------------------------
|  MYSQL_ROW       | 한 행의 데이터를 표현하는 데이터 형식이다. 현재 이것은 counted  |
|       | byte string들의 배열로 구현되어 있다. 필드값이 이진 데이터를 포 |
|       | 함할 수 있는 경우에는 값 내부에 null 바이트를 가지고 있을 수    |
|       | 있기 때문에 이 데이터 형식을 null-terminated string으로 다룰 수 |
|       | 없다. 행들은 mysql_fetch_row() 함수를 호출함으로써 얻어올 수 있 |
|       | 다. |
-----------------------------------------------------------------------------------------
|  MYSQL_FIELD       | 필드 명, 형식, 크기와 같은 필드에 대한 정보를 포함하는 구조체 |
|       | 이다. 이 구조체의 멤버들은 아래에서 상세히 기술된다. 각각의 필  |
|       | 드에 대하여 mysql_fetch_field() 함수를 호출함으로써 각 필드에 대|
|       | 한 MYSQL_FIELD 구조체의 값을 얻을 수 있다. 필드에 들어있는      | 
|       | 실제 값은 이 구조체의 멤버가 아니며, 실제 데이터는 |
|       | MYSQL_ROW 구조체에 들어가게 된다. |
-----------------------------------------------------------------------------------------
|  MYSQL_FIELD_OFFSET | MySQL 필드 리스트에 들어가는 변위(offset)을 표현하는 type-safe  |
|       | 형식이다(mysql_field_seek() 함수에서 사용된다). Offset은 행 내에|
|       | 서의 필드의 개수이며 0에서 시작한다. |
-----------------------------------------------------------------------------------------
|  my_ulonglong       | 행들의 개수, mysql_affected_rows(), mysql_num_rows(), |
|       | mysql_insert_id() 함수에서 사용되는 형식이다. 이 형식은 0에서   |
|       | 1.84e19까지의 값을 가질 수 있다. 어떤 시스템에서는 |
|       | my_ulonglong 형식의 값을 출력하는데 문제가 있을 수 있는데, 이   |
|       | 경우에 이 값을 출력하기 위해서는 이것을 unsigned long 형식으로  |
|             | 변환한 후 '%lu' 프린트 형식을 사용한다. 예를 들면 다음과 같다:  |
|       | |
|       | printf (Number of rows: %lu\n", (unsigned long) \ |
|       | mysql_num_rows(result)); |
-----------------------------------------------------------------------------------------

MYSQL_FIELD 구조체는 다음과 같은 멤버들을 가진다:

char * name
- 필드의 이름

char * table
- 이 필드가 계산된 필드(calculated field)가 아닌 경우, 이 필드를 가지고 있는
  테이블의 이름. 계산된 필드인 경우 NULL 포인터를 가진다

char * def
- 이 필드의 디폴트 값(mysql_list_fields() 함수를 사용하는 경우에만 설정된다)

enum enum_field_types type
- 필드의 형식(type). 필드 형식은 다음 테이블 값 중에 하나이다.

-------------------------------------------------------------------------
| Type value | Type meaning |
-------------------------------------------------------------------------
| FIELD_TYPE_TINY | TINYINT field |
-------------------------------------------------------------------------
| FIELD_TYPE_SHORT | SMALLINT field |
-------------------------------------------------------------------------
| FIELD_TYPE_LONG | INTEGER field |
-------------------------------------------------------------------------
| FIELD_TYPE_INT24 | MEDIUMINT field |
-------------------------------------------------------------------------
| FIELD_TYPE_LONGLONG | BIGINT field |
-------------------------------------------------------------------------
| FIELD_TYPE_DECIMAL | DECIMAL or NUMERIC field |
-------------------------------------------------------------------------
| FIELD_TYPE_FLOAT | FLOAT field |
-------------------------------------------------------------------------
| FIELD_TYPE_DOUBLE | DOUBLE or REAL field |
-------------------------------------------------------------------------
| FIELD_TYPE_TIMESTAMP | TIMESTAMP field |
-------------------------------------------------------------------------
| FIELD_TYPE_DATE | DATE field |
-------------------------------------------------------------------------
| FIELD_TYPE_TIME | TIME field |
-------------------------------------------------------------------------
| FIELD_TYPE_DATETIME | DATETIME field |
-------------------------------------------------------------------------
| FIELD_TYPE_YEAR | YEAR field |
-------------------------------------------------------------------------
| FIELD_TYPE_STRING | String (CHAR or VARCHAR) field |
-------------------------------------------------------------------------
| FIELD_TYPE_BLOB | BLOB or TEXT field (use max_length to |
| | determine the maximum length) |
-------------------------------------------------------------------------
| FIELD_TYPE_SET | SET field |
-------------------------------------------------------------------------
| FIELD_TYPE_ENUM | ENUM field |
-------------------------------------------------------------------------
| FIELD_TYPE_NULL | NULL-type field |
-------------------------------------------------------------------------
| FIELD_TYPE_CHAR | Deprecated: use FIELD_TYPE_TINY instead   |
-------------------------------------------------------------------------

IS_NUM() 매크로(macro)를 이용하여 필드가 정수형(numeric type)인가를 테스트할 수 있다.
IS_NUM()에 형식값(type value)를 인수로 넘겼을 때 필드가 정수형이면 'TRUE'를 리턴한다:

if (IS_NUM(field->type)) {
    printf("Field is numeric\n");
}

unsigned int length
- 필드의 길이(width)

unsigned int max_length
- 결과 셋에 대한 필드의 최대 길이(maximum width). mysql_list_fields() 함수를
  사용하는 경우 이 멤버에는 필드의 최대 길이가 저장된다.

unsigned int flags
- 필드에 대한 Different bit-flags. 플래그 값은 0 혹은 다음의 비트 셋(bit set) 중에
  하나이다.

-----------------------------------------------------------------
|  플래그 값  | 의미 |
-----------------------------------------------------------------
|  NOT_NULL_FLAG | Field can't be NULL |
-----------------------------------------------------------------
|  PRI_KEY_FLAG | Field is part of a primary key |
-----------------------------------------------------------------
|  UNIQUE_KEY_FLAG | Field is part of a unique key |
-----------------------------------------------------------------
|  MULTIPLE_KEY_FLAG | Field is part of a key |
-----------------------------------------------------------------
|  UNSIGNED_FLAG | Field has the UNSIGNED attribute |
-----------------------------------------------------------------
|  ZEROFILL_FLAG | Field has the ZEROFILL attribute |
-----------------------------------------------------------------
|  BINARY_FLAG | Field has the BINARY attribute |
-----------------------------------------------------------------
|  AUTO_INCREMENT_FLAG | Field has the AUTO_INCREMENT attribute|
-----------------------------------------------------------------
|  ENUM_FLAG | Field is an ENUM (deprecated) |
-----------------------------------------------------------------
|  BLOB_FLAG | Field is a BLOB or TEXT (deprecated) |
-----------------------------------------------------------------
|  TIMESTAMP_FLAG | Field is a TIMESTAMP (deprecated) |
-----------------------------------------------------------------

BLOB_FLAG, ENUM_FLAG, TIMESTAMP_FLAG 플래그들은 이들 플래그들이 자신의 형식
(type)의 속성을 표시하기 보다는 필드의 형식을 표시하기 때문에 이 플래그들을 사용하는
것은 좋지 않다. 그 대신 'field->type' 값을 FIELD_TYPE_BLOB, FIELD_TYPE_ENUM, 혹은
FIELD_TYPE_TIMESTAMP과 비교하는 것이 좋다. 아래의 예제는 플래그 값들의 전형적인
사용법에 대하여 설명한다:

if (field->flags & NOT_NULL_FLAG) {
    printf("Field can't be null\n");
}

플래그 값의 불리언 상태(boolean status)를 결정하는데 다음과 같은 매크로(macro)들을 사용
할 수 있다:

IS_NOT_NULL(flags) 이 필드가 'NOT NULL'로 정의되어 있으면 참
IS_PRI_KEY(flags) 이 필드가 primary key인 경우에 참
IS_BLOB(flags) 이 필드가 BLOB이나 TEXT인 경우에 참

unsigned int decimals
- 정수형 필드(numeric field)인 경우 자리수(number of decimal)


18.3 C API function overview

-------------------------------------------------------------------------------------------------
| Function | Description |
-------------------------------------------------------------------------------------------------
| mysql_affected_rows() | 가장 최근의 UPDATE, DELETE, INSERT 질의에 의한 결과 |
| | 행의 개수 를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_close() | 서버와의 연결을 종료한다. |
-------------------------------------------------------------------------------------------------
| mysql_connect() | 서버와 연결하며 이 함수를 사용하기보다는 |
-------------------------------------------------------------------------------------------------
| |  mysql_real_connect() 함수를 사용하는 것이 권장된다. |
| mysql_create_db() | DB를 생성한다. 이 함수를 사용하기보다는 SQL 명령어인 |
| | CREATE DATABASE 문을 사용하는 것이 좋다. |
-------------------------------------------------------------------------------------------------
| mysql_data_seek() | 질의 결과 셋에서 임의의 행을 찾는다. |
-------------------------------------------------------------------------------------------------
| mysql_debug() | 주어진 문자열로 DBUG_PUSH를 수행한다. |
-------------------------------------------------------------------------------------------------
| mysql_drop_db() | DB를 드롭한다. 이 함수를 사용하기보다는 SQL 명령어인 DROP |
| | DATABASE 문을 사용하는 것이 좋다. |
-------------------------------------------------------------------------------------------------
| mysql_dump_debug_info() | 서버로 하여금 디버깅 정보를 로그에 남기도록 한다. |
-------------------------------------------------------------------------------------------------
| mysql_eof() | 결과셋의 마지막 행이 읽혀졌는가를 표시한다. 이 함수를 |
| | 사용하기보다는 mysql_errno()나 mysql_error()함수가 사용된다. |
-------------------------------------------------------------------------------------------------
| mysql_errno() | 가장 최근에 수행된 MySQL 함수에 대한 에러넘버를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_error() | 가장 최근에 수행된 MySQL 함수에 대한 에러메세지를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_escape_string() | SQL 문 내부의 특수 문자를 처리한다. |
-------------------------------------------------------------------------------------------------
| mysql_fetch_field() | 테이블의 다음 필드의 형식(type)을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_fetch_field_direct() | 주어진 필드 번호에 대한 필드 형식을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_fetch_fields() | 모든 필드 구조에 대한 배열을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_fetch_lengths() | 현재 행의 모든 컬럼들의 길이를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_fetch_row() | 결과셋으로부터 다음 행을 가져온다. |
-------------------------------------------------------------------------------------------------
| mysql_field_seek() | 컬럼커서를 특정 컬럼으로 놓는다. |
-------------------------------------------------------------------------------------------------
| mysql_free_result() | 결과셋에 의해 사용된 메모리를 해제한다. |
-------------------------------------------------------------------------------------------------
| mysql_get_client_info() | 클라이언트의 버전 정보를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_get_host_info() | 현재 연결에 대한 정보를 가진 문자열을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_get_proto_info() | 연결에 사용된 프로토콜 버전을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_get_server_info() | 서버의 버전 넘버를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_info() | 가장 최근에 수행된 질의에 대한 정보를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_init() | MYSQL 구조체를 생성하거나 초기화한다. |
-------------------------------------------------------------------------------------------------
| mysql_insert_id() | AUTO_INCREMENT 필드에 대하여 가장 최근에 생성된 ID를 리턴. |
-------------------------------------------------------------------------------------------------
| mysql_list_dbs() | 간단한 정규식에 의해 매칭되는 DB 이름들을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_list_fields() | 간단한 정규식에 의해 매칭되는 필드 이름들을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_list_processes() | 현재 서버의 쓰레드들의 리스트를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_list_tables() | 간단한 정규식에 의해 매칭되는 테이블 이름들을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_num_fields() | 결과셋 내의 컬럼 개수를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_num_rows() | 결과셋 내의 행 개수를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_ping() | 서버와의 연결이 제대로 수행되고 있나를 체크하며, 필요하면 |
| | 서버와 재연결한다. |
-------------------------------------------------------------------------------------------------
| mysql_query() | Null terminated 문자열로 주어지는 SQL 질의를 수행한다. |
-------------------------------------------------------------------------------------------------
| mysql_real_connect() | MySQL 서버와 연결한다. |
-------------------------------------------------------------------------------------------------
| mysql_real_query() | Counted 문자열로 주어진 SQL 질의를 수행한다. |
-------------------------------------------------------------------------------------------------
| mysql_reload() | 서버로 하여금 grant 테이블을 다시 리로드하게 한다. |
-------------------------------------------------------------------------------------------------
| mysql_row_seek() | mysql_row_tell() 함수가 리턴한 값을 가지고 결과셋 내의 한 |
| | 행을 찾는다. |
-------------------------------------------------------------------------------------------------
| mysql_row_tell() | Row cursor 위치를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_select_db() | 특정 DB에 연결한다. |
-------------------------------------------------------------------------------------------------
| mysql_shutdown() | DB 서버를 셧다운시킨다. |
-------------------------------------------------------------------------------------------------
| mysql_stat() | 서버의 상태를 표시하는 문자열을 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_store_result() | 전체 결과셋을 클라이언트로 가져온다. |
-------------------------------------------------------------------------------------------------
| mysql_thread_id() | 현재 쓰레드의 ID를 리턴한다. |
-------------------------------------------------------------------------------------------------
| mysql_use_result() | 행단위로 데이터를 넘겨받기 위한 결과 셋을 초기화한다. |
-------------------------------------------------------------------------------------------------

서버에 연결할 때는 먼저 mysql_init() 함수를 호출함으로써 connection handler를 초기화한 후,
그 handler와 hostname, user name, password와 같은 다른 정보들을 가지고 mysql_real_connect()
함수를 호출한다. 모든 작업이 끝나면 mysql_close() 함수를 호출함으로써 연결을 종료한다.

연결이 이루어져 있는 동안 클라이언트는 mysql_query()나 mysql_real_query() 함수를 이용하
여 서버에 SQL 질의를 보낼 수 있다. mysql_query()는 질의가 null-terminated string이어야 하
며, mysql_real_query()는 counted string이어야 한다. 만약 string이 바이너리 데이터(중간에
NULL 바이트를 가질 수도 있는)인 경우에는 반드시 mysql_real_query()를 사용하여야 한다.

SELECT 질의가 아닌 질의(INSERT, UPDATE, DELETE)에 대해서는 mysql_affected_row() 함수
를 호출함으로써 얼마나 많은 행이 affect되어졌나를 알 수 있다.

SELECT 질의의 경우, select되어진 행들을 결과셋(result set)으로 얻게 된다(SHOW, DESCRIBE,
EXPLAIN과 같은 문은 행을 리턴하는 것에 있어서 SELECT와 비슷하며, 이들은 SELECT
문과 동일하게 처리되어야 한다)

클라이언트가 결과셋을 처리하는 방법에는 두가지가 있다. 하나는 mysql_store_result() 함수
를 호출함으로써 전체 결과 셋을 한번에 얻어오는 것으로써, 이 함수는 질의에 의해 리턴된
모든 행들을 서버로부터 얻어내어 클라이언트에 저장한다. 두번째는 mysql_use_result() 함수
를 호출함으로써 클라이언트가 행별로 결과셋을 얻어오는 것이다. 이 함수는 행을 얻어오기 위한
작업을 초기화하기만 하며 실제로 서버로부터 행을 가져오지는 않는다.

위 두가지 경우 모두, mysql_fetch_row() 함수를 호출함으로써 행들에 접근하게 된다.
mysql_store_result()의 경우 mysql_fetch_row()는 서버로부터 이미 fetch된 행들에 접근하며,
mysql_use_result()의 경우, mysql_fetch_row()는 실제로 서버로부터 행들을 얻어온다. 각 행의
데이터 값의 크기에 대한 정보는 mysql_fetch_lengths() 함수를 호출함으로써 얻을 수 있다.

결과 셋을 이용한 작업이 끝나면 mysql_free_result()를 호출함으로써 결과 셋을 위해 사용된
메모리를 해제한다.

이 두가지 retrieval 체계는 상호 보완적이다. 클라이언트 프로그램은 각각의 요구에 따라 적
절한 접근 방법을 선택하여야 한다. 실질적으로는 mysql_store_result()가 주로 사용된다.

mysql_store_result()의 이점은 행들이 클라이언트로 fetch된 이후에는 클라이언트가 행들에
순차적으로 접근할 수 있을 뿐만 아니라 mysql_data_seek()나 mysql_row_seek()를 이용하여 결
과 셋 안에서 현행 위치(current row position)를 변경함으로써 결과 셋 내에서 앞뒤로 움직일
수 있다는 것이다. 또한 mysql_num_rows()를 호출함으로써 얼마나 많은 행들이 있나를 알
수도 있다. 다른 한편으로, mysql_store_result()를 위해 요구되는 메모리가 많기 때문에 out-of-
memory 상태를 만날 가능성이 많다.

mysql_use_result()의 이점은 한번에 하나의 행만을 관리하기 때문에 결과 셋을 위한 메모리
가 적게 필요하다는 것이며 또한 더 적은 메모리 할당 부하로 인하여 더 속도가 빠를 수 있
다. 단점은 서버를 tying up하는 것을 피하기 위하여 각 행을 빠르게 처리해주어야 하며 결
과 셋 내에서 랜덤하게 행들에 접근할 수 없고 단지 순차적으로만 접근할 수 있다. 또한 모
든 행들을 받기 전에는 결과 셋 내에 얼마나 많은 행들이 있나를 알 수가 없다. 결과 셋 중
간에 찾고자 하는 정보를 찾았더라도 모든 행을 끝까지 받고 있어야 한다.

API를 이용함으로써 질의가 SELECT인가 아닌가를 모른 상태에서도 클라이언트가 질의에
적절히 대응할 수 있게 할 수 있는데, 이는 mysql_query() (혹은 mysql_real_query())를 호출한
후에 mysql_store_result()를 호출함으로써 가능하다. 만약 결과 셋이 성공(succeed)이면 질의가
SELECT이며 행들을 읽을 수 있다. 만약 실패이면 mysql_num_fields()를 호출하여 result가
정말로 기대되어지는가를 결정할 수 있으며, mysql_num_fields()가 0을 리턴하면 질의는 아무
데이터도 리턴하지 않는다(이것은 질의가 INSERT, UPDATE, DELETE 등임을 의미한다). 만약
mysql_num_fields()가 0이 아니면 질의는 반드시 행을 리턴하여야 하는데 리턴하지 않았음을
의미하며, 이는 질의가 SELECT였으며 수행에 실패하였음을 알려준다.

mysql_store_result()과 mysql_use_result()은 결과 셋을 구성하는 필드들에 대한 정보(필드의 개
수, 이름, 형식 등)를 얻을 수 있게 해준다. mysql_fetch_field()를 각각 호출하여 행 내에서의
필드 정보를 순차적으로 접근하거나, mysql_fetch_field_direct()를 호출함으로써 얻은 행 내의
필드 번호를 통하여 접근할 수 있다. 현쟁의 필드 커서 위치(current field cursor position)는
mysql_field_seek() 함수를 호출함으로써 변경될 수 있다. Setting the field cursor affects subsequent
calls to mysql_fetch_field(). 또한 mysql_fetch_fields()를 호출함으로써 한꺼번에 모든 필드 정보
를 얻을 수도 있다.

에러를 찾고 리포팅하기 위해서 MySQL은 mysql_errno()와 mysql_error() 함수를 통하여 에러
정보에 접근할 수 있게 해준다. 이 두 함수는 가장 최근에 invoke된 성공하거나 실패할 수
있는 함수에 대한 에러 코드 혹은 에러 메시지를 리턴하며, 이를 통하여 언제 에러가 발생
하고 그것이 무엇인가를 알 수 있다.


18.4 C API function descriptions

아래의 함수 설명에 있어서 NULL로 표시한 인수나 리턴값은 C 프로그래밍 언어에서의
NULL의 의미이며, MySQL에서의 NULL 값을 의미하는 것이 아니다.

어떤 값을 리턴하는 함수들은 보통 포인터나 정수를 리턴한다. 만약 별 다른 표시가 없다면
포인터를 리턴하는 함수들은 성공하였을 때 NULL이 아닌 값을, 에러를 표시하기 위해서는
NULL 값을 리턴한다. 정수를 리턴하는 함수의 경우에는 성공하였을 경우 0을, 에러인 경우
에는 0이 아닌 값을 리턴한다.

함수가 에러를 리턴한 경우에는 mysql_errno(), mysql_error() 함수를 이용하여 에러를 체크할
수 있다.

18.4.1 mysql_affected_rows()
my_ulonglong mysql_affected_rows(MYSQL *mysql)

18.4.1.1 Description
마지막으로 수행된 UPDATE, DELETE, INSERT 질의에 의한 행의 수를 리턴하며, 주로
UPDATE, DELETE, INSERT 문에 대한 mysql_query() 함수가 호출된 후 즉시 호출된다.
SELECT 문의 경우 mysql_affected_rows() 함수는 mysql_num_row() 함수처럼 동작한다.

mysql_affected_rows() 함수는 현재 매크로(macro)로 구현되어 있다.

18.4.1.2 Return values
0보다 큰 정수는 affected되거나 retrieved된 행의 수를 의미한다. 0은 WHERE 조건에 합당
하는 레코드가 없거나 아무 질의도 아직 수행되지 않았음을 의미한다. -1은 질의가 에러를
리턴하였거나 혹은 SELECT 질의인 경우 mysql_affected_rows() 함수가 mysql_store_result() 함
수의 호출 이전에 호출되었음을 의미한다.

18.4.1.3 Errors
없음.

18.4.1.4 Example
mysql_query(&mysql,"UPDATE products SET cost=cost*1.25 WHERE group=10");
printf("%d products updated",mysql_affected_rows(&mysql));


18.4.2 mysql_close()
void mysql_close(MYSQL *mysql)

18.4.2.1 Description
현재 열려있는 서버와의 연결을 끊는다. 만약 연결 핸들(connection handle)이 mysql_init()이나
mysql_real_connect()에 의해서 자동으로 할당되었다면 mysql_close()는 mysql에 의해 지정된
연결 핸들을 deallocation한다.

18.4.2.2 Return values
없음.

18.4.2.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.3 mysql_connect()
MYSQL *mysql_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd)

18.4.3.1 Description
이 함수를 사용하는 것은 권장되지 않으며, 대신 mysql_real_connect() 함수가 주로 사용된다.

mysql_connect() 함수는 호스트에서 돌아가고 있는 MySQL DB 엔진과의 연결을 시도한다.
Mysql_connect()는 mysql_get_client_info() 함수를 제외한 다른 모든 API 함수를 수행하기 이
전에 반드시 성공적으로 수행되어져야 한다.

함수의 인수들이 가지는 의미는 mysql_real_connect() 함수와 동일하다.

18.4.3.2 Return values
mysql_real_connect() 함수와 동일.

18.4.3.3 Errors
mysql_real_connect() 함수와 동일.


18.4.4 mysql_create_db()
int mysql_create_db(MYSQL *mysql, const char *db)

18.4.4.1 Description
'db' 인수로 주어진 이름의 데이터베이스를 생성한다.

이 함수를 사용하는 것은 권장되지 않으며, 대신 'CREATE DATABASE'와 같은 SQL 문을
mysql_query() 함수를 이용하여 수행하는 것이 좋다.

18.4.4.2 Return values
데이터베이스가 성공적으로 생성된 경우 0, 에러가 발생한 경우 0이 아닌 값을 리턴한다.

18.4.4.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.4.4 Example
if(mysql_create_db(&mysql, "my_database"))
{
   fprintf(stderr, "Failed to create new database.  Error: %s\n", mysql_error(&mysql));
}


18.4.5 mysql_data_seek()
void mysql_data_seek(MYSQL_RES *result, unsigned int offset)

18.4.5.1 Description
결과 셋 내에서 임의의 행을 찾는다. 이를 위해서는 결과 셋 구조체가 질의에 의한 전체 결
과를 포함하고 있어야 하며, 따라서 mysql_data_seek() 함수는 mysql_use_result() 함수와는 사
용할 수 없고 mysql_store_result() 함수와 사용한다.

Offset 인수는 0에서 mysql_num_rows(result)-1 사이의 값을 가져야 한다.

18.4.5.2 Return values
None.

18.4.5.3 Errors
None.


18.4.6 mysql_debug()
void mysql_debug(char *debug)

18.4.6.1 Description
debug 인수로 주어진 문자열을 가지고 DBUG_PUSH를 수행한다. mysql_debug() 함수는 Fred
Fish debug 라이브러리를 사용한다. 이 함수를 사용하기 위해서는 반드시 클라이언트 라이브
러리를 디버깅을 지원하도록 컴파일하여야 한다. 19.10 절에서 MySQL 서버의 디버깅에 대하
여 논의하며, 19.11절에서 MySQL 클라이언트의 디버깅에 대하여 논의한다.

18.4.6.2 Return values
None.

18.4.6.3 Errors
None.

18.4.6.4 Example
아래와 같은 호출은 클라이언트 라이브러리로 하여금 클라이언트의에 '/tmp/client.trace' 파일
에 trace file을 생성하게 해준다:

mysql_debug("d:t:O,/tmp/client.trace");


18.4.7 mysql_drop_db()
int mysql_drop_db(MYSQL *mysql, const char *db)

18.4.7.1 Description
db 인수로 주어진 이름의 데이터베이스를 드롭시킨다.

이 함수를 사용하는 것은 권장되지 않으며, 대신 'DROP DATABASE'와 같은 SQL 문을
mysql_query() 함수를 이용하여 수행하는 것이 좋다.

18.4.7.2 Return values
데이터베이스가 성공적으로 드롭된 경우 0을, 에러가 발생한 경우 0이 아닌 값을 리턴한다.

18.4.7.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.7.4 Example
if(mysql_drop_db(&mysql, "my_database"))
  fprintf(stderr, "Failed to drop the database: Error: %s\n", mysql_error(&mysql));


18.4.8 mysql_dump_debug_info()
int mysql_dump_debug_info(MYSQL *mysql)

18.4.8.1 Description
서버로 하여금 로그에 디버깅 정보를 기록하게 한다. 연결되어 있는 사용자(connected user)는
이 작업을 위한 권한을 가지고 있어야 한다.

18.4.8.2 Return values
명령이 성공하면 0, 에러가 발생하면 0이 아닌 값을 리턴한다.

18.4.8.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.9 mysql_eof()
my_bool mysql_eof(MYSQL_RES *result)

18.4.9.1 Description
이 함수를 사용하는 것은 권장되지 않으며, 대신 mysql_errno() 함수나 mysql_error() 함수를
사용한다.

mysql_eof() 함수는 결과 셋의 마지막 행이 읽혀졌나를 판단한다.

mysql_store_result() 함수로부터 성공적으로 결과 셋을 얻었다면 클라이언트는 한번의 작업으
로 전체 셋을 얻게된다. 이 경우 mysql_fetch_row() 함수로부터 리턴되는 NULL은 항상 결과
셋의 마지막에 도달하였음을 의미하게 되며 mysql_eof() 함수를 호출할 필요가 없다.

한편으로 mysql_use_result() 함수를 사용하여 결과 셋을 얻었다면 셋의 행들은
mysql_fetch_row() 함수를 호출할 때마다 서버로부터 하나씩 얻어진다. 이 과정 중에 연결 에
러가 발생할 수 있기 때문에 myql_fetch_row() 함수가 리턴하는 NULL 값은 반드시 결과 셋
의 마지막에 도달하였음을 의미한다고 볼 수 없다. 이 경우 mysql_eof() 함수를 사용하여 무
엇이 일어났나를 결정할 수 있다. 이때 mysql_eof() 함수는 결과 셋의 마지막에 도달한 경우
라면 0이 아닌 값을 리턴하며, 에러인 경우에는 0을 리턴하게 된다.

표준 mySQL 에러 함수인 mysql_errno()와 mysql_error() 함수가 더 많은 정보를 제공하기 때
문에 이들을 사용하는 것이 좋다…


18.4.9.2 Return values
에러이면 0을, 결과 셋의 마지막에 도달하였으면 0이 아닌 값을 리턴한다.

18.4.9.3 Errors
None.

18.4.9.4 Example
다음은 mysql_eof()의 사용예를 보여준다:

mysql_query(&mysql,"SELECT * FROM some_table");
result = mysql_use_result(&mysql);
while((row = mysql_fetch_row(result)))
{
    // do something with data
}
if(!mysql_eof(result))  // mysql_fetch_row() failed due to an error
{
    fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
}

However, you can achieve the same effect with the standard MySQL error functions:

mysql_query(&mysql,"SELECT * FROM some_table");
result = mysql_use_result(&mysql);
while((row = mysql_fetch_row(result)))
{
    // do something with data
}
if(mysql_errno(&mysql))  // mysql_fetch_row() failed due to an error
{
    fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
}


18.4.10 mysql_errno()
unsigned int mysql_errno(MYSQL *mysql)

18.4.10.1 Description
mysql 인수에 의해 지정된 연결에 대하여 mysql_errno()는 가장 최근에 수행된 API 함수에
대한 에러 코드를 리턴한다. 0을 리턴하면 아무 에러도 발생하지 않음을 의미한다. 클라이언
트 에러 메시지 넘버들은 MYSQL의 'errmsg.h' 헤더 파일에 나열되어 있으며, 서버 에러 메
시지 넘버들은 'mysqld_error.h' 파일에 있다.

18.4.10.2 Return values:
에러 코드 값을 리턴. 아무 에러도 없으면 0을 리턴한다.

18.4.10.3 Errors
None.


18.4.11 mysql_error()
char *mysql_error(MYSQL *mysql)

18.4.11.1 Description
mysql 인수에 의해 지정된 연결에 대하여 mysql_error()는 가장 최근에 수행된 API 함수에
대한 에러 메시지를 리턴한다. 비어 있는 문자열("")을 리턴하면 아무 에러도 발생하지 않음
을 의미한다. 이것은 다음의 두가지 테스트가 동일함을 의미한다:

if(mysql_errno(&mysql)) {
    // an error occurred
}

if(mysql_error(&mysql)[0] != '\0') {
    // an error occurred
}

클라이언트 에러 메시지의 언어는 MySQL 클라이언트 라이브러리를 재컴파일함으로써 변경
될 수 있다. 현재 몇가지 다른 언어로 된 에러 메시지를 선택할 수 있으며, 9.1 절에서는
MySQL에 의해 지원되는 언어들을 다룬다.

18.4.11.2 Return values
에러를 기술하는 문자열. 에러가 없는 경우에는 비어있는 문자열을 리턴한다.

18.4.11.3 Errors
None.


18.4.12 mysql_escape_string()
unsigned int mysql_escape_string(char *to, const char *from, unsigned int length)

18.4.12.1 Description
from 인수에 있는 문자열을 서버로 넘겨질 escaped SQL 문으로 인코딩하여 to 인수에 넣는다.
인코딩되어지는 문자들은 NUL(ASCII 0), `\n', `\r', `\', `'' 등이다(7.1절에서는 문자열과 숫자들을
사용하는 방법에 대하여 다룬다).

from 인수인 문자열은 length 인수에서 주어진 바이트 수만큼의 길이(terminating NULL을 제
외한)를 가져야 한다. to 인수는 반드시 적어도 length 인수에서 주어진 길이의 2배에 1을
더한 만큼의 바이트가 할당되어야 한다. mysql_escape_string() 함수가 리턴할 때 to 인수의 내
용은 null-terminated 문자열이 된다. 리턴값은 인코딩되어진 문자열의 길이이며, 이것은
terminating null 문자가 포함되지 않은 길이다.

to 인수에 들어가는 문자열은 null-terminated 문자열이지만 이 문자열을 strlen() 함수나
strcpy() 함수에서 사용하여서는 안된다. 만약 from 인수로 주어진 문자열이 null을 포함하고
있다면 mysql_escape_string() 함수는 이 문자를 '\'을 앞에 붙여서 to 인수에 넣게 되며, 이것
을 위의 함수들은 여전히 terminating null로 인식하게 된다.

또한 이러한 내부적인 null 바이트는 mysql_query()에 의해서 terminating null로 여겨지기 때
문에 질의를 적절하게 수행할 수 없게 된다. 따라서 mysql_escape_query() 함수를 이용하여
질의를 만든 경우 mysql_query() 함수를 사용하기 보다는 mysql_real_query() 함수를 사용하는
것이 좋다.

18.4.12.2 Example
char query[1000],*end;

end = strmov(query, "INSERT INTO test_table values(");
*end++ = '\";
end += mysql_escape_string(query,"What's this",11);
*end++ = '\";
*end++ = ',';
*end++ = '\";
end += mysql_escape_string(query,"binary data: \0\r\n",16);
*end++ = '\";
*end++ = ')';

if (mysql_real_query(&mysql,query,(int) (end - query))) {
   fprintf(stderr, "Failed to insert row, Error: %s\n",
           mysql_error(&mysql));
}

예제에서 사용된 strmov() 함수는 mysqlclient 라이브러리에 포함되어 있으며, strcpy() 함수와
비슷하게 동작을 하지만 첫번째 인수의 terminating null에 대한 포인터를 리턴하는 것이 다
르다.

18.4.12.3 Return values
terminating null 문자를 제외한 to 인수에 들어간 값의 길이

18.4.12.4 Errors
None.


18.4.13 mysql_fetch_field()
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)

18.4.13.1 Description
결과 셋의 한 컬럼의 정의(definition)를 MYSQL_FIELD 구조체에 담아서 리턴한다. 결과 셋
의 모든 컬럼들에 대한 정보를 얻고자 하는 경우에는 이 함수를 반복하여 호출한다. 더 이
상의 필드가 남아있지 않으면 mysql_fetch_field() 함수는 NULL을 리턴한다.

새로운 SELECT 질의가 수행될 때마다 mysql_fetch_field()는 새로운 첫번째 필드에 대한 정
보를 리턴하기 위해 초기화된다. mysql_fetch_field() 함수에 의해 리턴되는 필드는 또한
mysql_field_seek() 함수의 호출에 의해 영향을 받는다.

SELECT 문을 수행하기 위해 msyql_query()를 호출하였지만 mysql_store_result()를 호출하지
않은 경우, mysql_fetch_field()를 호출하여 BLOB 필드의 길이를 요청하게 되면 MySQL은 디
폴트 blob 길이인 8K 바이트를 리턴한다. 일단 한번 결과를 얻어오게 되면 field->max_length
는 주어진 질의에 있는 컬럼의 가장 큰 값의 길이를 가지게 된다.

18.4.13.2 Return values
현재 컬럼에 대한 MYSQL_FIELD 구조체를 리턴하며, 더 이상 남은 필드가 없으면 NULL을
리턴한다.

18.4.13.3 Errors
None.

18.4.13.4 Example
MYSQL_FIELD *field;

while((field = mysql_fetch_field(result)))
{
    printf("field name %s\n", field->name);
}


18.4.14 mysql_fetch_fields()
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)

18.4.14.1 Description
결과 셋에 대한 모든 MYSQL_FIELD 구조체의 배열을 리턴한다. 각각의 구조체는 결과 셋
내의 각 컬럼들에 대한 필드 정의에 대한 정보를 가지고 있다.

18.4.14.2 Return values
결과 셋의 모든 컬럼들에 대한 MYSQL_FIELD 구조체의 배열

18.4.14.3 Errors
None.

18.4.14.4 Example
unsigned int num_fields;
unsigned int i;
MYSQL_FIELD *fields;

num_fields = mysql_num_fields(result);
fields = mysql_fetch_fields(result);
for(i = 0; i < num_fields; i++) {
   printf("Field %u is %s\n", i, fields[i].name);
}


18.4.15 mysql_fetch_field_direct()
MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *result, unsigned int fieldnr)

18.4.15.1 Description
결과 셋 내에서 fieldnr 인수로 주어진 필드 번호의 필드에 대한 필드 정의를 MYSQL_FIELD
구조체로 리턴한다. 이 함수를 이용하여 임의의 컬럼에 대한 정의를 얻어올 수 있다. fieldnr
값은 0에서 mysql_num_fields(result)-1 사이의 값을 가져야 한다.

18.4.15.2 Return values
지정된 필드에 대한 MYSQL_FIELD 구조체

18.4.15.3 Errors
None.

18.4.15.4 Example
unsigned int num_fields;
unsigned int i;
MYSQL_FIELD *field;

num_fields = mysql_num_fields(result);
for(i = 0; i < num_fields; i++) {
    field = mysql_fetch_field_direct(result, i);
    printf("Field %u is %s\n", i, field->name);
}


18.4.16 mysql_fetch_lengths()
unsigned long *mysql_fetch_lengths(MYSQL_RES *result)

18.4.16.1 Description
결과 셋 내의 현재 행의 컬럼들의 길이를 리턴한다. 만약 필드 값들을 복사하고자 하는 경
우 이 길이 정보는 최적화(optimization)을 위해 유용하게 사용할 수 있다. strlen() 함수를 호
출할 필요가 없기 때문이다. 특히 결과 셋이 이진 데이터를 포함하고 있는 경우에는 strlen()
함수가 NULL 문자를 포함하고 있는 필드에 대하여 잘못된 결과를 리턴할 수 있기 때문에
데이터의 크기를 결정하는데 이 함수를 사용하여야 한다.

빈 컬럼이나 NULL 값을 가지는 컬럼에 대한 길이는 0이 된다. 이 두가지 경우를 구분하는
방법은 mysql_fetch_row() 함수에 대한 설명을 참조한다.

18.4.16.2 Return values
각 컬럼(null termination character를 제외한)의 크기를 가지고 있는 unsigned long 정수형의 배
열. 에러가 발생한 경우에는 NULL을 리턴한다.

18.4.16.3 Errors
mysql_fetch_lengths()는 결과 셋의 현재 행에 대해서만 유효하다. mysql_fetch_row() 함수를 호
출하기 전에 이 함수를 호출하거나 결과 셋 내의 모든 행들을 얻어온 후에 호출하는 경우에
NULL을 리턴한다.

18.4.16.4 Example
MYSQL_ROW row;
unsigned long *lengths;
unsigned int num_fields;
unsigned int i;

row = mysql_fetch_row(result);
if (row) {
    num_fields = mysql_num_fields(result);
    lengths = mysql_fetch_lengths(result);
    for(i = 0; i < num_fields; i++) {
         printf("Column %u is %lu bytes in length.\n", i, lengths[i]);
    }
}


18.4.17 mysql_fetch_row()
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

18.4.17.1 Description
결과 셋의 다음 행을 얻어온다. mysql_store_result() 함수를 호출한 후에 사용한 경우, 더 이
상 얻어올 행들이 없으면 mysql_fetch_row()는 NULL을 리턴한다. mysql_use_result() 함수를
호출한 후에 사용한 경우, 더 이상 얻어올 행들이 없거나 에러가 발생하였을 때 NULL을
리턴한다.

행 내부의 값들의 개수는 mysql_num_fields(result)에 의해 주어진다. mysql_fetch_row()의 호출
에 의하여 행이 얻어졌을 때 행 내부의 값들은 row[0]부터 row[mysql_num_fields(result)-1]까
지의 값들로 참조될 수 있다. 행 내부에 NULL 값이 있는 경우에는 NULL 포인터로 표시된다.

행 내부의 필드 값들의 길이들은 mysql_fetch_lengths() 함수를 호출함으로써 얻어질 수 잇다.
비어있는 필드나 NULL을 포함하는 필드들은 모두 0의 길이를 가지며, 필드 값에 대한 포
인터를 체크함으로써 이 두가지 경우를 구분할 수 있다. 만약 포인터가 NULL이면 해당 필
드가 NULL인 경우이며, 아니면 비어있는 필드임을 의미한다.

18.4.17.2 Return values
다음 행에 대한 MYSQL_ROW 구조체. 더 이상 얻어올 행이 없거나 에러가 발생한 경우
NULL을 리턴한다.

18.4.17.3 Errors
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.17.4 Example
MYSQL_ROW row;
unsigned int num_fields;
unsigned int i;

num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result))) {
   unsigned long *lengths;
   lengths = mysql_fetch_lengths(result);
   for(i = 0; i < num_fields; i++) {
       printf("[%.*s] ", (int) lengths[i], row[i] ? row[i] : "NULL");
   }
   printf("\n");
}


18.4.18 mysql_field_seek()
MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

18.4.18.1 Description
필드 커서를 offset 인수로 주어진 위치로 설정한다. 다음 mysql_fetch_field() 함수의 호출은
해당 offset로 이동한 만큼에 해당되는 컬럼에 대한 필드 정보를 얻어오게 된다.

행의 첫부분으로 보내기 위해서는 offset을 0으로 주고 함수를 호출하면 된다.

18.4.18.2 Return values
필드 커서의 이전 값(previous value)

18.4.18.3 Errors
None.


18.4.19 mysql_field_tell()
MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *result)

18.4.19.1 Description
마지막 mysql_fetch_field() 함수에 의해 사용된 필드 커서의 위치를 알려준다. 이 리턴값을
mysql_field_seek() 함수의 offset 인수로 사용할 수 있다.

18.4.19.2 Return values
필드 커서의 현재 변위(current offset)

18.4.19.3 Errors
None.


18.4.20 mysql_free_result()
void mysql_free_result(MYSQL_RES *result)

18.4.20.1 Description
mysql_store_result(), mysql_use_result(), mysql_list_dbs() 등에 의한 결과셋을 위해 할당되었던
메모리를 해제한다. 결과 셋을 가지고 작업을 끝내고 나면 반드시 mysql_free_result() 함수를
호출하여 메모리를 해제해 주어야 한다.

18.4.20.2 Return values
None.

18.4.20.3 Errors
None.


18.4.21 mysql_get_client_info()
char *mysql_get_client_info(void)

18.4.21.1 Description
클라이언트 라이브러리 버전(client library version)에 대한 정보를 표시하는 문자열을 리턴한다.

18.4.21.2 Return values
MySQL client library version을 표시하는 문자열

18.4.21.3 Errors
None.


18.4.22 mysql_get_host_info()
char *mysql_get_host_info(MYSQL *mysql)

18.4.22.1 Description
서버 호스트 네임을 포함하는 현재 사용되고 있는 연결(connection)의 형식(type)을 기술하는
문자열을 리턴한다.

18.4.22.2 Return values
서버 호스트 네임(server host name)과 연결 형식(connection type)을 나타내는 문자열

18.4.22.3 Errors
None.


18.4.23 mysql_get_proto_info()
unsigned int mysql_get_proto_info(MYSQL *mysql)

18.4.23.1 Description
현재 연결에 사용되고 있는 프로토콜의 버전을 리턴한다.

18.4.23.2 Return values
현재 연결에 사용되고 있는 프로토콜 버전을 나타내는 unsigned integer

18.4.23.3 Errors
None.


18.4.24 mysql_get_server_info()
char *mysql_get_server_info(MYSQL *mysql)

18.4.24.1 Description
서버 버전 넘버(server version number)를 표시하는 문자열을 리턴한다.

18.4.24.2 Return values
서버 버전 넘버를 표시하는 문자열

18.4.24.3 Errors
None.


18.4.25 mysql_info()
char *mysql_info(MYSQL *mysql)

18.4.25.1 Description
가장 최근에 수행된 질읭 peogks 정보를 제공하는 문자열을 리턴한다. 문자열의 형식(format)
은 질의의 타입에 따라 달라지며, 아래와 같다. 문자열은 질의에 대한 적절한 값들을 포함하
게 된다.

INSERT INTO ... SELECT ...
String format: Records: 100 Duplicates: 0 Warnings: 0
INSERT INTO ... VALUES (...),(...),(...)...
String format: Records: 3 Duplicates: 0 Warnings: 0
LOAD DATA INFILE ...
String format: Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
ALTER TABLE
String format: Records: 3 Duplicates: 0 Warnings: 0

18.4.25.2 Return values
가장 최근에 수행된 질의에 대한 부가적인 정보를 표현하는 문장열. 해당 질의에 대하여 아
무런 정보도 얻을 수 없는 경우 NULL을 리턴한다.

18.4.25.3 Errors
None.


18.4.26 mysql_init()
MYSQL *mysql_init(MYSQL *mysql)

18.4.26.1 Description
mysql_real_connect() 함수를 위한 MYSQL 객체를 할당(allocate)하거나 초기화(initialize)한다.
만약 mysql 인수가 NULL 포인터이면 mysql_init() 함수는 새로운 객체를 할당, 초기화하여
그 객체를 리턴한다. NULL 포인터가 아니면 객체는 초기화된 후 객체의 주소가 리턴된다.
만약 mysql_init() 함수가 새로운 객체를 할당하게 되면 그 객체는 연결을 닫기 위해
mysql_close() 함수가 호출될 때 해제되게 된다.

18.4.26.2 Return values
초기화된 MYSQL * handle. 새로운 객체를 할당하기 위한 메모리가 부족한 경우 NULL을 리
턴한다.

18.4.26.3 Errors
메모리가 부족한 경우 NULL이 리턴된다.


18.4.27 mysql_insert_id()
my_ulonglong mysql_insert_id(MYSQL *mysql)

18.4.27.1 Description
AUTO_INCREMENT 필드에 대하여 가장 최근에 생성된 ID를 리턴한다. 이 함수는
AUTO_INCREMENT 필드를 포함하는 테이블에 INSERT 질의를 수행한 이후에 사용된다.

18.4.27.2 Return values
가장 최근에 갱신된 AUTO_INCREMENT 필드의 값

18.4.27.3 Errors
None.


18.4.28 mysql_kill()
int mysql_kill(MYSQL *mysql, unsigned long pid)

18.4.28.1 Description
서버로 하여금 pid 인수로 주어진 쓰레드(thread)를 죽이도록(kill) 요청한다.

18.4.28.2 Return values
성공인 경우 0을, 에러가 발생한 경우 0이 아닌 값을 리턴한다.

18.4.28.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.29 mysql_list_dbs()
MYSQL_RES *mysql_list_dbs(MYSQL *mysql, const char *wild)

18.4.29.1 Description
wild 인수로 지정된 간단한 정규식(simple regular expression)에 매치되는 서버 상의 데이터베
이스 이름들을 포함하고 있는 결과 셋을 리턴한다. wild 인수는 '%', '_'와 같은 와일드카드 문
자를 포함할 수 있으며 모든 데이터베이스 이름을 얻고자 하는 경우 NULL을 지정할 수 있
다. mysql_list_dbs() 함수를 호출하는 것은 'SHOW databases [LIKE wild]'와 같은 질의를 수행하
는 것과 비슷하다.

반드시 mysql_free_result() 함수를 이용하여 결과 셋을 해제시켜 주어야 한다.

18.4.29.2 Return values
성공한 경우 MYSQL_RES 결과 셋을 리턴하며, 에러인 경우 NULL을 리턴한다.

18.4.29.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_OUT_OF_MEMORY
Out of memory.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.30 mysql_list_fields()
MYSQL_RES *mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)

18.4.30.1 Description
wild 인수로 지정된 간단한 정규식(simple regular expression)에 매치되는 테이블 상의 필드명
들을 포함하고 있는 결과 셋을 리턴한다. wild 인수는 '%', '_'와 같은 와일드카드 문자를 포함
할 수 있으며 모든 필드명을 얻고자 하는 경우 NULL을 지정할 수 있다. mysql_list_fields()
함수를 호출하는 것은 'SHOW fields FROM table [LIKE wild]'와 같은 질의를 수행하는 것과 비
슷하다.

반드시 mysql_free_result() 함수를 이용하여 결과 셋을 해제시켜 주어야 한다.

18.4.30.2 Return values
성공한 경우 MYSQL_RES 결과 셋을 리턴하며, 에러인 경우 NULL을 리턴한다.

18.4.30.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.31 mysql_list_processes()
MYSQL_RES *mysql_list_processes(MYSQL *mysql)

18.4.31.1 Description
현재의 서버 쓰레드들을 기술하는 결과 셋을 리턴한다. 이것은 'mysqladmin processlist'에 의
한 결과와 동일한 정보를 보여준다.
반드시 mysql_free_result() 함수를 이용하여 결과 셋을 해제시켜 주어야 한다.

18.4.31.2 Return values
성공한 경우 MYSQL_RES 결과 셋을 리턴하며, 에러인 경우 NULL을 리턴한다.

18.4.31.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.32 mysql_list_tables()
MYSQL_RES *mysql_list_tables(MYSQL *mysql, const char *wild)

18.4.32.1 Description
wild 인수로 지정된 간단한 정규식(simple regular expression)에 매치되는 현재 데이터베이스
상의 테이블명들을 포함하고 있는 결과 셋을 리턴한다. wild 인수는 '%', '_'와 같은 와일드카
드 문자를 포함할 수 있으며 모든 테이블명을 얻고자 하는 경우 NULL을 지정할 수 있다.
mysql_list_tables() 함수를 호출하는 것은 'SHOW tables [LIKE wild]'와 같은 질의를 수행하는
것과 비슷하다.

반드시 mysql_free_result() 함수를 이용하여 결과 셋을 해제시켜 주어야 한다.

18.4.32.2 Return values
성공한 경우 MYSQL_RES 결과 셋을 리턴하며, 에러인 경우 NULL을 리턴한다.

18.4.32.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.33 mysql_num_fields()
unsigned int mysql_num_fields(MYSQL_RES *result)
혹은,
unsigned int mysql_num_fields(MYSQL *mysql)

18.4.33.1 Description
결과 셋 내의 컬럼의 개수를 리턴한다.

mysql_num_fields()를 호출할 때 결과 셋에 대한 포인터 혹은 연결 핸들을 가지고 호출할 수
있다. 만약 mysql_store_result() 함수가 NULL을 리턴한 경우(즉 결과 셋 포인터를 얻어올 수
없을 때) 연결 핸들을 사용하게 되며, 이 경우 mysql_num_fields() 함수를 호출함으로써
mysql_store_result() 함수가 비어있지 않은 결과(non-empty result)를 생성하였나의 여부를 결정
할 수 있다. 이것은 클라이언트 프로그램으로 하여금 질의가 SELECT (혹은 SELECT-like) 문
인가 아닌가를 알지 못하는 상태에서 적절한 행동을 취할 수 있도록 해준다. 아래에 예가
있다.

18.4.33.2 Return values
결과 셋 내의 필드 개수를 표시하는 unsigned integer.

18.4.33.3 Errors
None.

18.4.33.4 Example
MYSQL_RES *result;
unsigned int num_fields;
unsigned int num_rows;

if (mysql_query(&mysql,query_string)) {
    // error
}
else {   // query succeeded, process any data returned by it
    result = mysql_store_result(&mysql);
    if (result) {   // there are rows
          num_fields = mysql_num_fields(result);
        // retrieve rows, then call mysql_free_result(result)
    }
    else {   // mysql_store_result() returned nothing; should it have?
        if(mysql_num_fields(&mysql) == 0) {
            // query does not return data
            // (it was not a SELECT)
            num_rows = mysql_affected_rows(&mysql);
        }
        else {   // mysql_store_result() should have returned data
            fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
        }
    }
}

또 다른 대안은 mysql_num_fields(&mysql) 대신에 mysql_errno(&mysql)을 호출하는 것이다.
이 경우, 질의가 SELECT 문인가를 msyql_num_fields()의 리턴값으로 결정하기보다는
mysql_store_result()로부터의 에러를 직접 체크하게 된다.


18.4.34 mysql_num_rows()
my_ulonglong mysql_num_rows(MYSQL_RES *result)

18.4.34.1 Description
결과 셋 내의 행의 개수를 리턴한다.

mysql_num_rows() 함수의 사용 여부는 결과 셋을 얻기 위해서 mysql_store_result() 함수를 사
용하는가  mysql_use_result() 함수를 사용하는가에 달려있다. 만약 mysql_store_result() 함수를
사용한다면 mysql_num_rows() 함수는 즉시 호출될 수 있다. 만약 mysql_use_result() 함수를
사용한다면 mysql_num_rows() 함수는 결과 셋 내의 모든 행들이 retrieve되기 이전에는 올바
른 값을 리턴하지 못한다.

18.4.34.2 Return values
결과 셋 내의 행의 개수

18.4.34.3 Errors
None.


18.4.35 mysql_ping()
int mysql_ping(MYSQL *mysql)

18.4.35.1 Description
서버에 대한 연결이 제대로 동작하고 있나를 확인하며, 만약 연결이 끊어진 경우에는 자동
으로 재연결을 시동한다.

이 함수는 클라이언트가 너무 오랫동안 쉬고 있을 때 서버가 연결을 끊었나를 체크하고 필
요하다면 다시 연결하기 위해 사용될 수 있다.

18.4.35.2 Return values
서버가 살아있으면 0, 에러인 경우 0이 아닌 값을 리턴한다.

18.4.35.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.36 mysql_query()
int mysql_query(MYSQL *mysql, const char *query)

18.4.36.1 Description
null-terminated 문자열인 query 인수에 지정된 SQL 질의를 수행한다. 질의는 반드시 하나의
SQL 문으로 이루어져야 하며, 질의문에 세미콜론(;)이나 '\g'를 붙여서는 안된다.

mysql_query()는 이진 데이터를 포함하는 질의에는 사용할 수 없다. 이진 데이터는 중간에
NULL 문자를 포함할 수 있으며 이경우 mysql_query() 함수는 거기서 질의 문자열이 끝난 것
으로 인식하기 때문에 이경우에는 mysql_real_query() 함수를 사용하여야 한다.

18.4.36.2 Return values
성공이면 0, 에러이면 0이 아닌 값을 리턴.

18.4.36.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.37 mysql_real_connect()
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd,
const char *db, uint port, const char *unix_socket, uint client_flag)

18.4.37.1 Description
mysql_real_connect() 함수는 호스트에서 돌아가고 있는 MySQL 데이터베이스 엔진에 연결을
시도한다. mysql_real_connect()는 mysql_get_client_info() 함수를 제외한 다른 모든 API 함수를
수행하기 이전에 반드시 성공적으로 수행되어져야 한다.

사용하는 인수들은 다음과 같다:

mysql 인수는 MYSQL connection 구조체이거나 NULL이 될 수 있다. 만약 mysql 인수가
NULL이면 C API는 자동으로 연결 구조체를 위한 메모리를 할당하고 mysql_close()가 호출
될 때 이를 해제한다. 이경우 단점은 연결이 실패한 경우 에러 메시지를 얻어올 수 없다는
것이다(mysql_errno()나 mysql_error() 함수로부터 에러 메시지를 얻기 위해서는 유효한
MYSQL 포인터를 제공하여야 한다). mysql 인수가 NULL이 아니면 이미 존재하는 MYSQL
구조체의 주소가 되어야 한다. 이 경우, mysql_real_connect() 함수를 호출하기 전에 반드시
mysql_init() 함수를 호출하여 MYSQL 구조체를 초기화해 주어야 한다. 다음의 예를 보라.
host 인수는 호스트명이 되거나 IP 어드레스가 될 수 있다. 만약 host 인수가 NULL이거나
"localhost"인 경우 로컬 호스트로의 접속으로 간주된다. 만약 OS가 소켓(socket-Unix)이나 파
이프(pipe-Win32)를 지원한다면 서버와의 연결을 위하여 TCP/IP 대신 이들을 사용할 수 있다.
user 인수에는 사용자의 MySQL 로그인 아이디를 넣어준다. User 인수가 NULL이면 현재 사
용자로 간주된다. Unix 환경에서는 현재 시스템 로그인명이 사용되며, Windows ODBC에서는
현재 사용자명이 명확히 지정되어야 한다. 15.4절에서는 ODBC 관리 프로그램에서 각 필드
들을 어떻게 채울 것인가에 대하여 논의한다.
passwd 인수에는 사용자에 대한 패스워드를 넣어준다. 만약 passwd가 NULL이면 user 테이
블에서 패스워드 필드가 비어있는 사용자들만이 매치를 위해 체크되어진다. 이것은 데이터
베이스 관리자로 하여금 데이터베이스 사용자가 자신의 패스워드를 명시하였나에 따라서 다
른 권한을 가지도록 하는 MySQL 권한 시스템을 설정할 수 있도록 해준다. 주의할 것은
mysql_real_connect() 함수를 호출하기 전에 패스워드를 암호화하려고 하지 말아야 한다는 것
이며, 패스워드의 암호화는 클라이언트 API에 의하여 자동으로 수행된다.
db 인수는 사용할 데이터베이스의 이름을 넣어준다. 만약 db 인수가 NULL이면 디폴트 데
이터베이스에 연결을 시도하게 된다.
port 인수가 0이 아니면 port 인수에 명시된 포트 번호를 TCP/IP 연결을 위한 포트 번호로
사용하게 된다. host 인수가 연결의 형식을 결정한다는 것에 주의한다.
unix_socket 인수가 NULL이 아니면 이 인수 문자열이 사용될 socket이나 named pipe가 된다.
client_flag 값은 보통 0이지만 매우 특별한 경우에 다음의 플래그들의 조합으로 설정할 수
있다.

-----------------------------------------------------------------------------------------
| Flag name     | Flag meaning |
-----------------------------------------------------------------------------------------
| CLIENT_FOUND_ROWS | affected row의 갯수가 아닌 found row의 갯수를 리턴한다. |
-----------------------------------------------------------------------------------------
| CLIENT_NO_SCHEMA  | db_name.tbl_name.col_name 형식의 문법(syntax)을 허용하지 않는다. |
|     | 이것은 ODBC를 위한 것으로서, 만약 이와 같은 문법을 사용하면 파서가|
|     | 에러를 발생시키게 된다. 이것은 ODBC 프로그램에서 버그를 찾아낼 때 |
|     | 유용하게 사용할 수 있다. |
-----------------------------------------------------------------------------------------
| CLIENT_COMPRESS   | 압축 프로토콜(compression protocol)을 사용한다. |
-----------------------------------------------------------------------------------------
| CLIENT_ODBC     | 클라이언트가 ODBC 클라이언트임을 알려주며, 이것은 mysqld가 좀더 |
|     | ODBC에 적합하도록 해준다. |
-----------------------------------------------------------------------------------------

18.4.37.2 Return values
연결이 성공하면 MYSQL * 연결 핸들(connection handle)을 리턴하며, 연결에 실패하면 NULL
을 리턴한다. 연결이 성공한 경우 리턴 값은 첫번째 인수에 NULL을 지정하지 않았다면 그
인수와 동일하다.

18.4.37.3 Errors
CR_CONN_HOST_ERROR
MySQL 서버로의 연결에 실패
CR_CONNECTION_ERROR
로컬 MySQL 서버로의 연결에 실패
CR_IPSOCK_ERROR
IP 소켓의 생성에 실패
CR_OUT_OF_MEMORY
메모리가 없음(Out of memory).
CR_SOCKET_CREATE_ERROR
Unix 소켓의 생성에 실패
CR_UNKNOWN_HOST
해당 호스트명에 대한 IP 주소를 찾을 수 없음.
CR_VERSION_ERROR
일치하지 않는 프로토콜 버전을 사용하는 클라이언트 라이브러리를 가지고 서버에 접속
하려 시도함으로 인하여 프로토콜 불일치가 발생함. 이것은 매우 오래된 클라이언트
라이브러리를 사용하여 새로운 버전의 서버에 접속하고자 하는 경우에 발생한다. 이런
경우에는 서버를 시동할 때 '--old-protocol' 옵션을 넣어서 시동하면 해결할 수 있다.
CR_NAMEDPIPEOPEN_ERROR;
Win32 환경에서 named pipe를 생성하는데 실패함.
CR_NAMEDPIPEWAIT_ERROR;
Win32 환경에서 named pipe를 기다리는데 실패함.
CR_NAMEDPIPESETSTATE_ERROR;
Win32 환경에서 pipe 핸들러를 얻는데 실패함.

18.4.37.4 Example
MYSQL mysql;

mysql_init(&mysql);
if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0)) {
    fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(&mysql));
}


18.4.38 mysql_real_query()
int mysql_real_query(MYSQL *mysql, const char *query, unsigned int length)

18.4.38.1 Description
query 인수에 지정된 SQL 질의를 수행하며, query 인수는 length 인수에 지정된 길이를 가져
야 한다. 질의는 하나의 SQL 문으로 이루어져야 하며, 세미콜론이나 '\g'를 SQL문에 붙여서
는 안된다.

이진 데이터를 포함하는 질의 데이터인 경우 mysql_query() 함수가 아닌 mysql_real_query()
함수를 사용하여야 한다. 또한 mysql_real_query()함수는 질의문의 길이를 얻기 위한 strlen()
함수를 수행하지 않기 때문에 mysql_query() 함수에 비하여 수행 속도가 빠르다.

18.4.38.2 Return values
질의에 성공하면 0, 에러가 발생하면 0이 아닌 값을 리턴한다.

18.4.38.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.39 mysql_reload()
int mysql_reload(MYSQL *mysql)

18.4.39.1 Description
MySQL 서버로 하여금 grant 테이블을 다시 읽도록 요청한다. 현재 연결되어 있는 사용자는
반드시 권한 설정을 다시 읽어야 한다.

이 함수를 사용하는 것은 권장되지 않으며, 대신 'FLUSH PRIVILEGES' SQL 문을
mysql_query() 함수를 이용하여 수행하는 것이 좋다.

18.4.39.2 Return values
성공하면 0, 에러면 0이 아닌 값을 리턴한다.

18.4.39.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.40 mysql_row_seek()
MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset)

18.4.40.1 Description
결과 셋 내에 행 커서(row cursor)를 임의의 위치로 설정한다. 이를 위해서는 결과 셋 구조체
가 전체 질의 결과를 가지고 있어야 하며, 따라서 mysql_row_seek() 함수는 mysql_use_result()
함수와는 사용할 수 없고 mysql_store_result() 함수와 사용할 수 있다.

offset 인수는 mysql_row_tell() 함수나 mysql_row_seek() 함수를 호출한 리턴값이 되어야 하며,
이 값은 단순한 행 번호를 의미하는 것이 아니다. 만약 행 번호를 이용하여 결과 셋 내에서
행을 찾고자 하는 경우에는 mysql_data_seek() 함수를 사용하여야 한다.

18.4.40.2 Return values
행 커서(row cursor)의 이전값(previous value). 이 값은 mysql_row_seek() 함수의 인수로 넘겨진
다.

18.4.40.3 Errors
None.


18.4.41 mysql_row_tell()
MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result)

18.4.41.1 Description
마지막 mysql_fetch_row() 함수 호출에 의한 행 커서의 현재 위치를 리턴한다. 이값은
mysql_row_seek() 함수의 인수로 넘겨진다.

mysql_row_tell() 함수는 반드시 mysql_store_result() 함수 뒤에 사용되어야 하며,
mysql_use_result() 함수 뒤에는 사용할 수 없다.

18.4.41.2 Return values
행 커서의 현재 변위(The current offset of the row cursor).

18.4.41.3 Errors
None.


18.4.42 mysql_select_db()
int mysql_select_db(MYSQL *mysql, const char *db)

18.4.42.1 Description
db 인수에 지정한 데이터베이스를 mysql 인수가 가진 연결에 대한 현재 작업 데이터베이스
가 되도록 한다. 이후의 질의에 대해서 여기서 지정한 데이터베이스가 데이터베이스를 명시
하지 않은 테이블 참조에 대한 디폴트 데이터베이스로 사용된다.

연결되어 있는 사용자가 db 인수에 지정된 데이터베이스를 사용할 권한을 가지고 있다는 것
이 인증되지 않으면 mysql_select_db() 함수는 실패한다.

18.4.42.2 Return values
성공이면 0, 에러이면 0이 아닌 값

18.4.42.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.43 mysql_shutdown()
int mysql_shutdown(MYSQL *mysql)

18.4.43.1 Description
데이터베이스 서버로 하여금 셧다운되도록 요청하며, 현재 연결된 사용자가 셧다운 권한을
가지고 있어야 한다.

18.4.43.2 Return values
성공이면 0, 에러이면 0이 아닌 값을 리턴한다.

18.4.43.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.44 mysql_stat()
char *mysql_stat(MYSQL *mysql)

18.4.44.1 Description
'mysqladmin status' 명령어에 의해 제공되는 정보와 비슷한 정보를 포함하고 있는 문자열을
리턴한다. 이 문자열에는 구동시간(uptime), 실행되고 있는 쓰레드 수, 질문(question), 재시동
(reload), 열려있는 테이블 등에 대한 정보가 포함되어 있다.

18.4.44.2 Return values
서버 상태를 기술하는 문자열. 에러이면 NULL을 리턴한다.

18.4.44.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.45 mysql_store_result()
MYSQL_RES *mysql_store_result(MYSQL *mysql)

18.4.45.1 Description
데이터를 얻어오는 질의(SELECT, SHOW, DESCRIBE, EXPLAIN)의 수행에 대하여
mysql_store_result() 혹은 mysql_use_result() 함수를 호출한다.

mysql_store_result() 함수는 전체 질의 결과를 클라이언트로 읽어오며, MYSQL_RES 구조체를
할당하고 결과를 이 구조체에 넣어준다. 아무 행도 리턴되지 않으면 빈 결과 셋(empty result
set)이 리턴된다(빈 결과 셋은 NULL 리턴 값과는 다르다).

mysql_store_result() 함수를 호출하면 mysql_num_rows() 함수를 호출하여 결과 셋 내에 얼마
나 많은 행들이 있는가를 알아 볼 수 있다.
mysql_fetch_row() 함수를 호출하여 결과 셋으로부터 행들을 얻어올 수 있으며, 혹은
mysql_row_seek()와 mysql_row_tell() 함수를 통하여 결과 셋 내에서의 현행 위치를 얻거나 위
치를 설정해줄 수 있다.

결과셋을 통한 작업이 끝나면 반드시 mysql_free_result() 함수를 호출해준다.

18.4.45.2 Return values
결과가 저장된 MYSQL_RES 결과 구조체(result structure). 에러이면 NULL을 리턴.

18.4.45.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_OUT_OF_MEMORY
Out of memory.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.

18.4.46 mysql_thread_id()
unsigned long mysql_thread_id(MYSQL *mysql)

18.4.46.1 Description
현재 연결에 대한 쓰레드 ID를 리턴한다. 이 값은 mysql_kill() 함수의 인수로 사용되어 쓰래
드를 kill 하는데 사용될 수 있다.

18.4.46.2 Return values
현재 연결에 대한 쓰레드 ID.

18.4.46.3 Errors
None.

18.4.47 mysql_use_result()
MYSQL_RES *mysql_use_result(MYSQL *mysql)

18.4.47.1 Description
데이터를 얻어오는 질의(SELECT, SHOW, DESCRIBE, EXPLAIN)의 수행에 대하여
mysql_store_result() 혹은 mysql_use_result() 함수를 호출한다.

mysql_use_result() 함수는 결과 셋을 얻어오는 작업을 초기화하지만 mysql_store_result() 함수
처럼 실제로 결과 셋을 읽어서 클라이언트에게 넘겨주지는 않는다. 대신 mysql_fetch_row()
함수를 각각 호출함으로써 각 행이 하나씩 얻어진다. 이것은 질의의 결과를 임시 테이블이
나 지역 버퍼에 저장하지 않고 서버로부터 직접 읽어오게 되며, 이는 mysql_store_result() 함
수에 비하여 좀더 빠르고 훨씬 적은 양의 메모리를 차지한다. 클라이언트는 현재 행에 대한
메모리와 max_allowed_packet 바이트까지 증가할 수 있는 통신 버퍼(communication buffer)만
을 할당하게 된다.

하지만 클라이언트 측에서 각 행별로 많은 작업을 수행하고 있거나 사용자가 ^S(stop scroll)
을 입력할 수도 있는 스크린으로 결과를 내보내는 경우에는 mysql_use_result() 함수를 사용
해서는 안된다. 이것은 서버를 멈추게 하고 다른 쓰레드들로 하여금 데이터가 얻어지고 있
는 테이블을 갱신하는 것을 막게 된다.

mysql_use_result() 함수를 사용할 때는 NULL 값이 리턴될 때까지 mysql_fetch_row() 함수를
수행해야 한다. 그렇지 않으면 아직 얻어오지 않은 행들이 다음 질의에 대한 결과 셋으로
넘어가서 리턴되게 된다. C API는 'Commands out of sync' 에러를 주게 된다.

mysql_use_result() 함수로부터 리턴되는 결과에 대해서 mysql_data_seek(), mysql_row_seek(),
mysql_row_tell(), mysql_num_rows(), mysql_affected_rows()과 같은 함수들을 사용할 수 없으며,
혹은 mysql_use_result() 함수가 종료할 때까지 다른 질의를 수행할 수 없다(그러나 모든 행들
을 fetch한 후에는 mysql_num_rows() 함수가 실제로 fetch되어진 행의 개수를 리턴한다).

결과 셋에 대한 작업이 끝나면 반드시 mysql_free_result()를 호출하여야 한다.

18.4.47.2 Return values
MYSQL_RES 결과 구조체(result structure). 에러이면 NULL을 리턴한다.

18.4.47.3 Errors
CR_COMMANDS_OUT_OF_SYNC
Commands were executed in an improper order.
CR_OUT_OF_MEMORY
Out of memory.
CR_SERVER_GONE_ERROR
The MySQL server has gone away.
CR_SERVER_LOST
The connection to the server was lost during the query.
CR_UNKNOWN_ERROR
An unknown error occurred.


18.4.48 mysql_query() 함수가 성공하였는데 mysql_store_result() 함수가 가끔 NULL을 리턴하
는 이유는 무엇인가?

이런 경우가 있을 수 있으며 이것은 다음 중 하나의 상황이 발생하였음을 의미한다:

malloc()이 실패한 경우(예를 들어 결과 셋이 너무 큰 경우).
데이터를 읽을 수 없는 경우(연결에 에러가 생기는 등).
질의가 아무 데이터도 리턴하지 않는 경우(INSERT, UPDATE, DELETE 문 등의 경우).

질의문이 비어있지 않은(non-empty) 결과를 생성하였나는 mysql_num_fields() 함수를 호출함
으로써 체크해볼 수 있다. 만약 mysql_num_fields() 함수가 0을 리턴하면 결과셋이 빈 것이
고 가장 마지막 질의가 INSERT, DELETE와 같이 값을 리턴하지 않는 질의문임을 의미한다.
mysql_num_fields() 함수가 0이 아닌 값을 리턴하는 경우는 질의문이 비어있지 않는 결과를
생성해야만 함을 의미한다. 자세한 내용은 mysql_num_fields() 함수의 설명을 참조한다.

mysql_errno() 함수나 mysql_error() 함수를 호출함으로써 에러를 테스트해볼 수 있다.

18.4.49 What results can I get from a query?

질의의 결과로 리턴되는 결과 셋에 덧붙여 다음과 같은 정보들을 또한 얻을 수 있다:
- mysql_affected_rows()는 INSERT, UPDATE, DELETE 문을 수행할 때 가장 최근에 수행된
질의에 의해 affected된 행들의 개수를 리턴한다. 예외는 DELETE가 WHERE 구문없이
사용되어 테이블이 truncate되는 경우이다. 이 경우 mysql_affected_rows() 함수는 affected
된 레코드의 숫자로서 0을 리턴한다.
- mysql_num_rows()는 결과 셋 내의 행의 개수를 리턴한다. mysql_store_result() 함수와 함께
사용되는 경우에는 mysql_store_result()가 리턴되자마자 최대한 빨리 mysql_num_rows()가
호출되어진다. mysql_use_result()와 함께 사용되는 경우에는 mysql_fetch_row()가 모든 행
에 대해서 수행된 후에만 mysql_num_rows()가 호출될 수 있다.
- mysql_insert_id()는 AUTO_INCREMENT 인덱스를 가진 테이블에 행을 추가한 경우 가장
최근에 새로 생성된 ID를 리턴한다.
- 몇몇 질의들(LOAD DATA INFILE ..., INSERT INTO ... SELECT ..., UPDATE)은 부가적인 정
보를 리턴한다. 이 결과들은 mysql_info()에 의하여 리턴된다. mysql_info()는 리턴할 부가
적인 정보가 없는 경우 NULL을 리턴한다.

18.4.50 How can I get the unique ID for the last inserted row?
AUTO_INCREMENT 속성을 가지는 컬럼을 포함하고 있는 테이블에 새로운 레코드를 삽입
하는 경우, mysql_insert_id() 함수를 호출함으로써 가장 최근에 생성된 ID를 얻어올 수 있다.

다음의 코드를 수행함으로써 AUTO_INCREMENT 인덱스가 사용되었나를 체크해 볼 수 있다.
또한 질의가 AUTO_INCREMENT 인덱스를 가진 INSERT 문인가를 체크할 수 있다:

if (mysql_error(&mysql)[0] == 0 && mysql_num_fields(result) == 0 && mysql_insert_id(&mysql) != 0)
{
    used_id = mysql_insert_id(&mysql);
}

하나의 테이블에서 생성된 ID를 다른 테이블에 삽입하는데 사용하고자 하는 경우 다음과
같은 SQL 문을 사용한다:

INSERT INTO foo (auto, text) VALUES(NULL, 'text');             # generate ID by inserting NULL
INSERT INTO foo2 (id, text) VALUES(LAST_INSERT_ID(), 'text');  # use ID in second table


18.4.51 Problems linking with the C API
어떤 시스템에서는 C API를 linking하여 컴파일할 때 다음과 같은 에러가 발생할 수 있다:

gcc -g -o client test.o -L/usr/local/lib/mysql -lmysqlclient -lsocket -lnsl

Undefined       first referenced
symbol          in file
floor            /usr/local/lib/mysql/libmysqlclient.a(password.o)
ld: fatal: Symbol referencing errors. No output written to client

위와 같은 에러가 발생하는 경우에는 컴파일 시에 -lm을 추가함으로써 math 라이브러리를
함께 포함해 준다.


18.4.52 How to make a thread-safe client
클라이언트는 거의 thread-safe하다. 가장 큰 문제점은 'net.c'에서 소켓을 읽는 서브루틴들이
interrupt-safe하지 못하다는 것이다. 이것은 서버로부터 읽는 작업이 오래 걸릴 때 클라이언
트가 작업을 중단할 수 있는 기능을 원할 것이라는 생각에서 그렇게 작성되어졌다.

표준 클라이언트 라이브러리는 쓰레드 옵션없이 컴파일되어진다.

Thread-safe 클라이언트를 만들기 위해서는 -lmysys, -lstring, -ldbug 라이브러리와 서버가 사용
하는 net_serv.o를 함께 사용한다.

Threaded client를 사용하면 'thr_alarm.c' 파일에 있는 루틴들을 활용할 수 있다. mysys 라이브
러리의 루틴들을 사용할 때 기억해야할 단 한가지는 my_init() 함수를 가장 먼저 호출해야
한다는 것이다!

mysql_real_connect()를 제외한 모든 함수들은 현재 thread-safe하다. 다음의 내용에서는 thread-
safe 클라이언트 라이브러리를 컴파일하는 방법과 그것을 thread-safe 방식으로 사용하는 방
법에 대하여 기술한다(여기서는 mysql_real_connect() 함수에 대한 예를 설명하며,
mysql_connect()의 경우에도 동일하다).

mysql_real_connect() 함수를 thread-safe하게 만들기 위해서는 다음의 명령으로 클라이언트를
재컴파일하여야 한다:

shell> CPPFLAGS=-DTHREAD_SAFE_CLIENT ./configure ...

pthread 라이브러리가 디폴트로 포함되어지지 않기 때문에 표준 클라이언트(standard client)를
링킹할 때 정의되지 않은 심볼(undefined symbols)로 인한 에러가 발생할 수 있다.

결과로 나오는 'libmysqld.a' 라이브러리는 이젠 thread-safe하다. 이것은 두개의 thread가
mysql_real_connect()에 의해 리턴된 동일한 연결 핸들(connection handle)을 동시에 질의하지
않는 한 클라이언트 코드가 thread-safe하다는 것을 의미한다; 클라이언트/서버 프로토콜은
주어진 연결에 대하여 동시에 하나의 요청만을 허용한다. 동일한 연결에 대하여 복수개의
thread를 사용하길 원하는 경우에는 mysql_query()와 mysql_store_result()의 호출 묶음(call
combination)에 대하여 mutex lock을 해야 한다.

일단 mysql_store_result()가 준비되면 lock은 해제될 수 있으며 다른 thread들은 동일한 연결
에 대하여 query를 할 수 있다(다시 말해서, 서로 다른 thread들이 적절한 locking 프로토콜
을 사용하는 한 mysql_store_result()과 함께 생성된 서로 다른 MYSQL_RES 포인터들을 사용
할 수 있다). POSIX thread로 프로그램한다면 mutex lock을 생성하고 해제하는데
pthread_mutex_lock()와 pthread_mutex_unlock() 함수를 사용할 수 있다.

mysql_store_result()가 아닌 mysql_use_result()를 사용하는 경우에는 lock이 mysql_use_result()
와 mysql_fetch_row()에 대한 호출을 surround할 필요가 있다. 그러나 threaded client는
mysql_use_result()를 사용하지 않는 것이 가장 좋다.



19. 타 DB와 비교
19.1 Mysql/mSQL 비교

이번장은 Mysql 개발자가 쓴 글이므로  이점을 염두에 두고 보아야  한다.
그렇지만 개발자들이 알고 있는대로 솔직하게 작성되었다.

지원되는 함수, 타입, 제한사항등은 crash-me 웹 페이지를 참고하면 된다.

<성능>
속도 비교와 관련해서는 Mysql 벤치마크를 참고한다. (11장)  mSQL은 스레
드 생성 때문에 발생하는 과부하가 없고, 파져(parser)가  작으며, 기능이
적고 보안이 간단하다. 그래서 다음과 같은 경우에는 mSQL의  속도가 빠르
다.
- 연결/해제를 반복하면서 각 연결때마다 간단한 질의를 하는 테스트
-몇개의 컬럼과 키만 있는 아주 간단한 테이블에  자료을 입력(INSER)하는
경우
- CREATE TABLE, DROP TABLE
- 인덱스 없이 SELECT 하는 경우(테이블 검색이 매우 간단)

이런 작업들은 매우 간단해서, 시작시  높은 부하가 걸리는 경우에  좋다.
연결이 되고나서는 Mysql이 더 높은 성능을 보여준다.

그 외에는 다음과 같은 면에서 Mysql이 mSQL( 및 다른 SQL 프로그램) 보다
빠르다.
- 복합적인 SELECT 연산
- 대량의 자료를 검색 (Mysql은 성능이 뛰어나고 빠르며  안전한 프로토콜
을 사용한다)
-  가변길이  문자열을  가진  테이블.  Mysql은  효율적으로  되어있으며
VARCHAR 컬럼에 인덱스를 사용할 수 있다.
- 많은 컬럼을 가진 테이블을 다루는 경우
- 레코드 길이가 큰 테이블을 다루는 경우
- 많은 표현식(expression)을 가진 SELECT 문을 사용하는 경우
- 거대한 테이블에서 SELECT문을 사용하는 경우
- 동시에 다중으로 연결을  처리해야할 때. Mysql은 완전한  멀티스레드를
지원한다. 각 연결은 자신의 스레드를 가지며 이는 스레드에서  다른 스레
드를 기다릴 필요가 없다는 것을 의미한다. (현재의 스레드가 다른 스레드
에서 접근하기 원하는 테이블을  수정하고 있는 경우는 제외)  mSQL에서는
하나의 연결이 성립되면 그 연결에서 질의를 수행하든 하지 않든 상관없이
첫 번째 연결이 끝날때까지 다른 것들은 기다려야한다. 첫 번째 연결이 해
제되면 다음 연결이 성립되고 또 다른 것들은 다시 기다려야한다.
- 조인. mSQL에서는 SELECT에서 테이블의 정렬 순서를  변경하면 엄청나게
느려진다. 벤치마킹 프로그램을 사용하였을 때, 그 시간은 Mysql보다 최대
15000배 느렸다. mSQL에서는 최적의 순서에 따른 테이블을  정열하기 위한
조인 최적화기가 없기 때문이다. 그렇지만, 테이블을 mSQL2의 적절한 정열
순서에 따라 정확하게 테이블을 구성하고 WHERE 가 간단하고  인덱스 컬럼
을 사용하면 조인은 상대적으로 빨라진다. 11장 Mysql 벤치마킹 참고.
-  ORDER BY and GROUP BY.
- DISTINCT
- TEXT 나  BLOB 컬럼 사용

<SQL 특징>
-  GROUP BY, HAVING. mSQL은 GROUP BY를 지원하지 않는다. Mysql은  완전
하게 GROUP BY 와 HAVING을  지원하며 다음의 함수를 지원한다.  COUNT(),
AVG(), MIN(), MAX(),  SUM() and STD().  COUNT(*)는 하나의  테이블에서
SELECT를 사용하고, 컬럼은 검색하지 않으며  WHERE 문이 없을 경우  매우
빠르게 최적화되어있다. MIN() 과 MAX()는 문자열 인자를 가진다.
- INSERT 와 UPDATE에서 계산가능.
        예)Mysql> UPDATE SET x=x*10+y WHERE x<20;
- 알리아싱. Mysql에는 컬럼 알리아싱이 있다.
- 컬럼 이름 한정. Mysql에서 컬름 이름이 질의에 사용된 테이블에서 유일
하다면, 완전한 한정자를 쓸 필요가 없다. (** table_name.column_name 이
런 식으로 하지 않아도 된다는 말입니다**)
- SELECT문에서 다양한 함수 지원. 7.3 함수 참조.

<디스크 공간 효율성>
테이블을 얼마나 작게 만들 수  있는가를 말한다. Mysql에는 매우  정밀한
타입이 많으므로 매우 적은 공간만을 차지하도록 테이블을 만들  수 있다.
예를 들어 유용한 데이터타입중 하나는 MEDIUMINT로 3 바이트 long이다. 1
억건의 레코드가 있는 경우, 각 레코드당 1 바이트를 절약하는  것은 매우
중요하다. mSQL2는 지원하는 데이터 타입이 제한되어있어서 테이블을 작게
만들기가 어렵다.
<안정성>
안정성을 객관적으로 판단하는 것은 쉬운 일이 아니다.  Mysql의 안정성은
1.5장 참고. 우리는(Mysql 개발팀)은 mSQL의 안정성에 대한 경험이 없으므
로 이에 대해서는 말할 것이 없다.
<가격>
주요한 주제중의 하나가 라이센스이다. Mysql은 mSQL보다 유연한 라이센스
정책을 가지고 있으며 가격도 저렴하다. 어떤 제품을 선택하든  최소한 라
이센스나 이메일 지원에 대한 비용을 고려해야한다. (물론  판매하는 제품
에 Mysql이 포함되어있으면 라이센스가 반드시 필요하다)
<펄 인터페이스>
Mysql은 몇가지 추가된 기능과 함께 mSQL과 동일한 펄  인터페이스를 가지
고 있다.
<JDBC(Java)>
Mysql은 현재 4가지 JDBC 드라이버가 있다.
- The gwe driver: A Java interface by GWE technologies (not supported
anymore).
- The jms driver: An improved gwe driver by Xiaokun Kelvin ZHU
- The twz driver:  A type 4  JDBC driver by  Terrence W. Zellers  and
educational use.
- The mm driver: A type 4 JDBC driver by Mark Matthews{{</LI>
}}
추천하는 드라이버는 twz나 mm 드라이버이다. 둘다 훌륭하게  작동하는 것
으로 보고되었다.
mSQL에 JDBC 드라이버가 있는 것은 알고 있지만 그에 대한 비교 경험은 없
다.

<개발속도>
Mysql은 매우 작은 규모의 개발팀을 가지고 있지만, 모두 C와  C++ 코딩을
매우 빠르게 하는데  익숙해있다. 스레드, 함수, GROUP BY 등등  mSQL에는
아직 구현되지   않은 것들이  많아서 따라오려면   멀었다. mSQL의  최근
'HISTORY' 파일과 Mysql 레퍼런스 매뉴얼의 뉴스 섹션을 비교해보자. 어떤
것이 빠르게 개발되고 있는지 명확할 것이다.

<유틸리티 프로그램>
mSQL과 Mysql에는 매우 다양한 서드-파티 툴이 있다. mSQL에서 Mysql로 포
팅하는 것이 매우 쉽기 때문에, mSQL에서 사용가능한 대부분의 애플리케이
션은 Mysql에서도 사용할 수 있다.
Mysql에는 간단한 mSQL2Mysql 프로그램이 들어있는데 mSQL과 Mysql 사이의
대부분의 C-API 함수의 스펠링을 바꿀 수 있다. mSQL에서 Mysql 로 클라이
언트 프로그램을 포팅하는 것은 일반적으로 그다지 시간이 걸리지 않는다.

19.1.1 mSQL 툴을 Mysql로 바꾸기
경험상 보았을 때, mSQL C-API를 사용하는 mSQL-tcl 과  mSQLjava를 Mysql
C-API  에서 작동할 수 있도록 변환하는 것은 몇시간이면 충분하다.

변환과정은 다음과 같다:

1. 소스에서 mSQL2Mysql 스크립트를 실행한다. 여기에는 replace 프로그램
이 필요한데, Mysql과 함께 배포된다.
2. 컴파일
3. 모든 컴파일 에러 수정

mSQL C API와 Mysql C API 의 차이점은 다음과 같다.
- Mysql uses  a Mysql structure  as a connection  type (mSQL uses  an
int).
-  Mysql_connect()   takes a  pointer  to a   Mysql structure  as  a
parameter. It is easy  to define one globally  or to use malloc()  to
get one. Mysql_connect() also takes  2 parameters for specifying  the
user and password. You may set these to NULL, NULL for default use.
- Mysql_error() takes the  Mysql structure as  a parameter. Just  add
the parameter to your  old mSQL_error() code  if you are porting  old
code.
-  Mysql returns an  error number and  a text error  message for all
errors. mSQL returns only a text error message.
-  Some  incompatibilities exist  as  a result  of Mysql   supporting
multiple connections to the server from the same process.{{</LI>
}}
(
M
  ysql은 동일한 프로세스에서 서버에 다중 연결을 지원하므로 호환되지 않는 부분이  존재한다.)

19.1.2 mSQL 과 Mysql  클라이언트/서버 통신 프로토콜 차이점
mSQL과 Mysql을 둘다 지원하지 못하거나 힘든 몇가지 차이점이 있다.

Mysql 프로토콜이  mSQL 프로토콜과 다른 몇가지 주요 차이점은 다음과 같
다.
- 메시지 버퍼에 많은 검색 행을 가지고 있다.
- 메시지 버퍼는 질의나 결과가 현재의 버퍼보다 크면, 서버와 클라이언트
에서 설정한 제한선까지 동적으로 확장이 될 수 있다.
- 중복되거나 분실된 패킷을 잡아 모든 패킷의 숫자를 셀 수 있다.
- 모든 컬럼 값은 아스키로 전송된다. 컬럼과 행의 길이는  바이너리 코딩
(1, 2, 3 바이트)으로 꾸려져 전송된다.
- Mysql can read  in the result  unbuffered (without having to  store
the full set in the client).
- 단일 쓰기/읽기 락이 30초이상 걸리면, 서버에서 연결을 해제한다.
- 연결이 8시간 이상 쉬고 있으면, 서버에서 연결을 해제한다.

19.1.3  How mSQL 2.0 SQL syntax differs from Mysql
(** 굳이 번역하지 않습니다. 심심하면 한번 읽어보세요. mSQL  써본지 워
낙 오래되었고 그다지 쓸 일이 없어서요**)

Column types
Mysql
Has the following  additional types  (among others;  see see  section 
7.6)
ENUM type for one of a set of strings.
SET type for many of a set of strings.
BIGINT type for 64-bit integers.{{</LI>
}}

Mysql also supports the following additional type attributes:
UNSIGNED option for integer columns.
ZEROFILL option for integer columns.
AUTO_INCREMENT option for integer columns that are a PRIMARY KEY.
DEFAULT value for all columns.{{</LI>
}}

mSQL2
mSQL column types correspond to the Mysql types shown below:{{<TBODY>
}}

mSQLtype        Corresponding Mysql type
CHAR(len)       CHAR(len)
TEXT(len)       TEXT(len). len is the maximal length. And LIKE works.
INT             INT. With many more options!
REAL            REAL. Or   FLOAT. Both  4- and   8-byte versions  are
available.
UINT            INT UNSIGNED
DATE            DATE. Uses ANSI SQL format rather than mSQL's own.
TIME            TIME
MONEY   DECIMAL(12,2). A fixed-point value with two decimals.{{</TBODY>
}}

{{</DD>
}}Index creation
Mysql
Indexes may be specified at table creation time with the CREATE TABLE
statement.
mSQL
Indexes must  be  created after   the table has   been created,  with
separate CREATE INDEX statements.{{</DD>
}}

To insert a unique identifier into a table
Mysql
Use AUTO_INCREMENT as a column type specifier.
mSQL
Create a SEQUENCE on a table and select the _seq column.{{</DD>
}}
To obtain a unique identifier for a row
Mysql
Add a PRIMARY KEY or UNIQUE key to the table.
mSQL
Use the  _rowid column.  Observe  that _rowid  may change   over time
depending on many factors.{{</DD>
}}

To get the time a column was last modified
Mysql
Add a TIMESTAMP column to the table. This column is automatically set
to the current date and time  for INSERT or UPDATE statements if  you
don't give the column a value or if you give it a NULL value.
mSQL
Use the _timestamp column.{{</DD>
}}
NULL value comparisons
Mysql
Mysql follows ANSI SQL and a comparison with NULL is always NULL.
mSQL
In mSQL, NULL = NULL  is TRUE. You must  change =NULL to IS NULL  and
<>NULL to IS NOT NULL when porting old code from mSQL to Mysql.{{</DD>
}}

String comparisons
Mysql
Normally,  string  comparisons   are performed   in  case-independent
fashion with the sort order  determined by the current character  set
(ISO-8859-1 Latin1 by default). If you don't like this,  declare your
columns with the  BINARY attribute,  which causes  comparisons to  be
done according to the ASCII order used on the Mysql server host.
mSQL
All string comparisons are  performed in case-sensitive fashion  with
sorting in ASCII order.{{</DD>
}}

Case-insensitive searching
Mysql
LIKE is a case-insensitive  or case-sensitive operator, depending  on
the columns involved.  If possible,  Mysql uses indexes  if the  LIKE
argument doesn't start with a wildcard character.
mSQL
Use CLIKE.{{</DD>
}}
Handling of trailing spaces
Mysql
Strips all spaces at the end of CHAR and VARCHAR columns. Use  a TEXT
column if this behavior is not desired.
mSQL
Retains trailing space.{{</DD>
}}
WHERE clauses
Mysql
Mysql correctly prioritizes everything (AND is evaluated  before OR).
To get mSQL behavior in Mysql, use parentheses (as shown below).
mSQL
Evaluates everything from left to right. This means that some logical
calculations with more  than three arguments  cannot be expressed  in
any way. It also means you must change some queries when  you upgrade
to Mysql. You do this easily by adding parentheses. Suppose  you have
the following mSQL query:
Mysql&gt; SELECT * FROM table WHERE a=1 AND b=2 OR a=3 AND b=4;
To make Mysql  evaluate this the  way that mSQL  would, you must  add
parentheses:
Mysql&gt; SELECT  *  FROM table   WHERE (a=1  AND (b=2   OR (a=3  AND
(b=4))));
{{</DD>
}}Access control
Mysql
Has tables to  store grant  (permission) options per  user, host  and
database.
mSQL
Has a file `mSQL.acl'  in which you  can grant read/write  privileges
for users.


19.2 PostgreSQL과 Mysql 비교
PostgreSQL은 사용자-정의 타입, 트리거, 룰, 트랜잭션 지원 등 몇가지 향
상된 기능을 가지고 있다. 그렇지만 ANSI SQL 과 ODBC의 표준 타입이나 함
수 지원이   미약하다. 지원되거나  지원되지 않는   제한, 타입,  함수는
crash-me               웹               페이지를               참고하
자.(http://www.Mysql.com/crash-me-choose.htmy)

일반적으로 PostgreSQL은 Mysql보다 느리다. 11장 [벤치마크] 참고.  이것
은 대부분 트랜잭션 시스템 때문이다. 정말로 트랜잭션이 필요하고 속도를
희생할 생각이 있다면 PostgreSQL을 고려해볼 수 있다.

**참고
http://www.postgresql.org/comp-comparison.html
여기에 가면 간략하게나마 PostgreSQL과 타 DB와 비교자료가 있습니다.
http://database.sarang.net/database/database.phtml
여기에는 위 자료 번역본이 있습니다.

이 포스트를..

덧글 쓰기 엮인글 쓰기

본문스크랩 MySQL 사용자권한과 DCL 7 - 1 MySQL 의 권한 시스템 php

2007/01/16 10:02

http://blog.naver.com/husmile/10013055432

출처 블로그 > 박재진 님의 블러그
원본 http://blog.naver.com/yuzuhara/140029954351

- MySQL 의 권한 시스템의 주요 기능은 MySQL 서버로의 접속 권한 관리와 DATABASE 에서의

- SELECT, UPDATE 그리고 DELETE 와 같은 SQL 및 각종 명령의 실행 권한을 관리하는 곳이다.


- MySQL 에서 사용자를 인증하고 권한을 부여하는 과정은 다음과 같이 두 단계로 나뉘서

- 실시된다.


- 1 단계 : 먼저 MySQL 에 접속하는 사용자가 접근 가능한 사용자인지 사용자명, 비빌번호와 사용

- 자가 접속하는 컴퓨터의 호스트명을 검사한다. 다시 말해 사용자명이 같아도 접속하는 호스트가

- 다르면 서로 다른 사용자로 취급한다. 예를 들어 aaa.com 에서 접속한 사용자 GUEST 와

- bbb.com 에서 접속한 사용자 GUEST 는 사용자명은 같아도 서로 다른 사용자이다. 이렇게 관리

- 하는 이유는 사용자명과 비밀번호만 알면 어느 컴퓨터에서든지 접속이 가능하게 되는 것을 방지

- 하기 위해서이다. 사용자명과 호스트명이 확인되면 해당 사용자의 비밀번호를 확인하여 접속을

- 허락한다.


- 2 단계 : 사용자명과 호스트명을 검사하여 접속을 허락한 다음 SQL 등에 대한 요청을 받게되면

- 해당 사용자에 맞는 권한을 검사하여 요청을 실행하게 된다. 예를 들어 해당 사용자에게 A 테이

- 블에 대한 SELECT 권한과 테이블에 대한 DROP 권한이 부여되도록 설정되어 있다면 그 사용자

- 는 A 테이블에 대하여 SELECT 와 DROP 을 실행할 수 있다.


- MySQL 은 이러한 권한 시스템을 운영하기 위해 권한 관리 테이블을 사용한다. 테이블을 사용

- 하는 MySQL 의 권한 관리 방식은 진보적이면서 비표준적이다. 다시 말해 권한 관리 하는 방법이

- 매우 쉽고 강력하면서도 그것이 업계 표준은 아니라는 것이다.


- MySQL 의 권한 관리 테이블은 mysql 이라는 DATABASE 에 존재하는 user, db, host,

- tables_priv, columns_priv 테이블이 그것이다.


- 먼저 user, db 그리고 host 테이블의 칼럼들은 다음과 같다.


+------------------+---------------------+-----------------------+---------------------+

| 테이블명              | user                        | db                              | host                         |

+------------------+---------------------+-----------------------+---------------------+

| 권한 범위 칼럼들   | Host                        | Host                           | Host                         |

|                           | User                        | Db                             | Db                            |

|                           | Password                | User                           |                                |

| 권한 칼럼들          | Select_priv               | Select_priv                  | Select_priv                |

|                           | Insert_priv                | Insert_priv                   | Insert_priv                 |

|                           | Update_priv              | Update_priv                 | Update_priv               |

|                           | Delete_priv               | Delete_priv                  | Delete_priv                |

|                           | Index_priv                | Index_priv                   | Index_priv                  |

|                           | Alter_priv                  | Alter_priv                    | Alter_priv                   |

|                           | Create_priv               | Create_priv                 | Create_priv                |

|                           | Drop_priv                  | Drop_priv                    | Drop_priv                  |

|                           | Grant_priv                 | Grant_priv                   | Grant_priv                 |

|                           | References_priv        |                                  |                                |

|                           | Reload_priv              |                                   |                                |

|                           | Shutdown_priv          |                                  |                                |

|                           | Process_priv            |                                   |                                |

|                           | File_priv                   |                                   |                               |

+------------------+---------------------+-----------------------+---------------------+


- tables_priv 와 columns_priv 테이블의 칼럼들은 다음과 같다.


+------------------+---------------------+----------------------+

| 테이블명              | tables_priv                | columns_priv             |

+------------------+---------------------+----------------------+

| 권한 범위 칼럼들   | Host                         | Host                         |

|                           | Db                            | Db                           |

|                           | User                         | User                        |

|                           | Table_name               | Table_name              |

|                           |                                 | Column_name           |

| 권한 칼럼들          | Table_priv                 | Column_priv              |

|                           | Column_priv               |                               |

| 그 외 칼럼들         | Timestamp                 | Timestamp                |

|                           | Grantor                      |                               |

+------------------+----------------------+---------------------+


- 그럼 여기서 mysql 이라는 DATABASE 에 접속하여 각각의 테이블의 구조를 확인해보겠다.

- 먼저 mysql DATABASE 에 접속하여 다음과 같이 SHOW 명령으로 어떤 테이블들이 존재하는지

- 알아보자


mysql> use mysql
Database changed


mysql> show tables;
+-----------------+
| Tables_in_mysql |
+-----------------+
| columns_priv      |
| db                     |
| func                  |
| host                  |
| tables_priv         |
| user                  |
+-----------------+
6 rows in set (0.00 sec)


- 이제 다음과 같이 DESC 명령으로 user, db, host 테이블 구조를 확인해보자.

- 이 때 권한 칼럼들의 칼럼 타입이 ENUM 이라는 것을 유심히 보아두기 바란다.


mysql> desc user;
+-----------------------+---------------------------------+-----+-----+--------+------+
| Field                           | Type                                          | Null | Key | Default | Extra |
+-----------------------+---------------------------------+-----+-----+--------+------+
| Host                           | varchar(60) binary                        |       | PRI |            |         |
| User                           | varchar(16) binary                        |       | PRI |            |         |
| password                   | varchar(16)                                  |       |       |            |         |
| Select_priv                  | enum('N','Y')                               |       |      | N         |         |
| Insert_priv                   | enum('N','Y')                               |       |      | N         |         |
| Update_priv                 | enum('N','Y')                               |       |      | N         |         |
| Delete_priv                  | enum('N','Y')                               |       |      | N         |         |
| Create_priv                  | enum('N','Y')                              |        |      | N         |        |
| Drop_priv                    | enum('N','Y')                               |       |      | N         |         |
| Reload_priv                 | enum('N','Y')                               |       |      | N         |         |
| Shutdown_priv             | enum('N','Y')                               |       |      | N         |         |
| Process_priv               | enum('N','Y')                               |       |      | N         |         |
| File_priv                      | enum('N','Y')                               |       |      | N         |         |
| Grant_priv                   | enum('N','Y')                               |       |       | N         |         |
| References_priv           | enum('N','Y')                               |       |      | N         |         |
| Index_priv                   | enum('N','Y')                               |       |       | N         |         |
| Alter_priv                     | enum('N','Y')                               |      |       | N         |         |
| Show_db_priv              | enum('N','Y')                               |       |       | N         |        |
| Super_priv                   | enum('N','Y')                               |       |       | N         |        |
| Create_tmp_table_priv   | enum('N','Y')                               |       |       | N         |        |
| Lock_tables_priv          | enum('N','Y')                               |       |       | N         |        |
| Execute_priv                | enum('N','Y')                               |       |       | N        |         |
| Repl_slave_priv            | enum('N','Y')                               |       |       | N        |         |
| Repl_client_priv            | enum('N','Y')                               |       |       | N        |         |
| ssl_type                      | enum('','ANY','X509','SPECIFIED') |       |       |           |         |
| ssl_cipher                   | blob                                            |       |       |           |         |
| x509_issuer                 | blob                                            |        |      |            |        |
| x509_subject                | blob                                            |       |       |            |        |
| max_questions             | int(11)                                         |        |      | 0         |         |
| max_updates               | int(11) unsigned                            |       |       | 0         |         |
| max_connections         | int(11) unsigned                            |       |       | 0         |         |
+-----------------------+----------------------------------+-----+-----+--------+------+ 31 rows in set (0.19 sec)


mysql> desc db;
+-----------------------+-----------------+------+-----+---------+-------+
| Field                           | Type                 | Null   | Key  | Default   | Extra  |
+-----------------------+-----------------+------+-----+---------+-------+
| Host                           | char(60) binary   |         | PRI  |              |          |
| Db                              | char(64) binary   |         | PRI  |             |           |
| User                           | char(16) binary   |         | PRI  |              |          |
| Select_priv                  | enum('N','Y')      |         |       | N           |          |
| Insert_priv                   | enum('N','Y')      |         |       | N           |          |
| Update_priv                 | enum('N','Y')      |         |       | N           |          |
| Delete_priv                  | enum('N','Y')      |         |       | N           |          |
| Create_priv                  | enum('N','Y')     |         |        | N          |          |
| Drop_priv                     | enum('N','Y')     |         |       | N           |          |
| Grant_priv                    | enum('N','Y')     |         |       | N           |          |
| References_priv           | enum('N','Y')      |        |        | N          |          |
| Index_priv                    | enum('N','Y')     |         |       | N           |          |
| Alter_priv                     | enum('N','Y')     |         |        | N          |          |
| Create_tmp_table_priv   | enum('N','Y')      |         |       | N           |          |
| Lock_tables_priv          | enum('N','Y')      |         |       | N           |          |
+-----------------------+-----------------+------+-----+---------+-------+
15 rows in set (0.01 sec)


mysql> desc host;
+-----------------------+-----------------+------+-----+---------+-------+
| Field                           | Type                 | Null   | Key  | Default   | Extra  |
+-----------------------+-----------------+------+-----+---------+-------+
| Host                           | char(60) binary   |         | PRI  |              |          |
| Db                              | char(64) binary   |         | PRI  |              |         |
| Select_priv                  | enum('N','Y')      |         |       | N           |          |
| Insert_priv                   | enum('N','Y')      |         |       | N           |          |
| Update_priv                 | enum('N','Y')      |         |       | N           |          |
| Delete_priv                  | enum('N','Y')      |         |       | N           |          |
| Create_priv                  | enum('N','Y')     |         |       | N           |          |
| Drop_priv                    | enum('N','Y')      |         |       | N           |          |
| Grant_priv                   | enum('N','Y')      |         |       | N           |          |
| References_priv           | enum('N','Y')     |         |        | N          |           |
| Index_priv                   | enum('N','Y')      |         |       | N           |          |
| Alter_priv                    | enum('N','Y')      |         |        | N          |          |
| Create_tmp_table_priv   | enum('N','Y')      |         |       | N           |          |
| Lock_tables_priv          | enum('N','Y')      |         |       | N           |          |
+-----------------------+-----------------+------+-----+---------+-------+
14 rows in set (0.00 sec)


- 참고로 tables_priv 나 columns_priv 테이블에서 권한 칼럼들의 칼럼 타입은 ENUM 이 아니라

- SET 을 사용하고 있다.


- 사용자가 MySQL 의 권한 테이블을 사용하는 방식을 요약하면 다음과 같다.


- user 테이블은 MySQL 서버에 접속하기 위해 사용자가 사용자명과 비밀번호 및 호스트명을

- 가지고 접속에 대한 인증을 받을 때 사용한다. user 테이블에는 권한 범위 칼럼들 이외에도 권한

- 칼럼들이 있는데 그 권한 칼럼들을 이용하여 전체 DATABASE 들에 대한 권한을 설정할 수 있다.

- 예를 들어 user 테이블에 해당 사용자에 대한 Select_priv 칼럼의 권한이 Y 로 되어있다면 해당

- 사용자는 모든 DATABASE 에 대해 SELECT 문을 사용할 수 있는 권한을 갖게 된다. 이 단계에

- 대한 보다 자세한 설명은 다음 페이지 "1단계 : 사용자 접속 인증" 에서 다루고 있다.


- db 테이블과 host 테이블은 해당 사용자의 사용자명과 호스트명을 검사하여 어느 DATABASE 에

- 어떤 권한을 사용할 수 있는지에 대한 범위를 지정하는데 사용한다.


- 먼저 db 테이블은 해당 사용자가 어떤 DATABASE 에 어떤 권한을 획득하게 할 것인가를 결정

- 한다. 이 때 먼저 사용자의 권한이 이미 user 테이블의 권한 칼럼으로부터 Y 로 설정되어 있다면

- db 테이블에서 해당 권한을 설정하는 것은 무의미하다. 왜냐하면 user 테이블에서 Y 라고 설정된

- 권한은 모든 DATABASE 에 대한 권한을 획득하는 것이기 때문이다. 그러므로 db 테이블에 권한

- 을 설정하는 것은 user 테이블에서 해당 권한이 N 으로 되어있을 때만 의미를 가진다.


- 그리고 host 테이블은 db 테이블에서의 host 칼럼에 대한 확장 테이블이다. 임의의 DATABASE

- 에 대해 호스트에 따라 다양한 권한을 부여하고자 할 때 사용한다. db 테이블의 Host 칼럼을 공백

- 으로 남겨두면 호스트에 대한 권한 설정은 host 테이블로 넘어가게 되는 것이다. 이 단계에 대한

- 보다 자세한 설명은 다음 페이지의 "2단계 : 권한 부여" 에서 다루고 있다.


- 사용자 접속 권한 말고도 Reload_priv 나 Shutdown_priv 와 같은 관리자 권한 설정은 user테이블

- 에서만 설정이 가능하다. 이러한 권한은 DATABASE 하고는 상관이 없는 권한이므로 db 나 host

- 등의 다른 테이블에서 다뤄질 필요가 없는 것이다. 예를 들어 mysqladmin shutdown 과 같은

- 명령을 실행했을 때 user 테이블에 Shutdown_priv 권한이 N 이면 db 나 host 테이블을 살펴보지

- 않고 바로 권한이 없다는 에러를 출력하게 된다.


- 또한 user 테이블에서만 다뤄지는 권한으로 파일과 관련된 File_priv 권한이 있는데 이는 사용자

- 가 서버의 파일에 접근할 수 있게 할 것인가를 결정한다. 예를 들어 어떤 사용자의 File_priv 권한

- 이 N 으로 되어있으면 그 사용자는 LOAD DATA INFILE 과 같이 파일을 다루는 문장은 사용할 수

- 가 없다.


- 지금까지 권한 인증 과정에 대해 개략적으로 살펴보았으므로 이제 각 단계별로 구체적으로 어떻

- 게 동작하는지 알아보도록 하자.


- 1 단계 : 사용자 접속 인증

- MySQL 에서는 다음 2 가지에 근거하여 사용자의 접속을 인증한다.


- 어느 호스트에서 접속하는 사용자인가

- 사용자명이 무엇인가


- 이러한 인증은 user 테이블로부터 이루어지는데 이 때 사용되는 칼럼은 Host, User, Password

- 이다. MySQL 서버는 접속을 시도하는 사용자의 호스트명과 사용자명, 그리고 비밀번호를 확인

- 하여 접속을 허락할 것인지를 결정한다.


+--------------------------------------------------------------------------------------+

|                                                                                                                                 |

|     사용자명(User), 비밀번호(Password),                                                                       |

|     호스트명(Host) 으로 접속 시도                                                                                  |

|                         |                                                                                                       |

|                   MySQL 서버--------------------> 접속 권한이 없으면                                  |

|                         |                                           Access denied 에러출력 접속 불가            |

|              접속 권한이 있으면                                                                                         |

|        접속을 허용하고 권한을 부여                                                                                  |

|                                                                                                                                 |

+--------------------------------------------------------------------------------------+

- 사용자 접속 과정


- 다음은 user 테이블에서 사용자 접속 권한의 범위를 지정하기 위해 사용되는 값에 대하여 설명

- 하고 있다.


- Host 칼럼에는 호스트 이름이나 IP 주소 혹은 로컬 컴퓨터를 의미하는 'localhost' 가 온다.

- Host 칼럼에는 '%' 나 '_' 와 같은 와일드 카드 문자를 사용할 수있다.

- Host 칼럼에는 '%' 는 모든 호스트를 의미한다.

- Host 칼럼이 공백이면 호스트에 관한 권한 설정은 host 테이블로 위임된다. Host 테이블에서

- 호스트에 관한 권한 설정을 하면 임의의 DATABASE 에 대해 호스트별로 다양한 권한을 부여할

- 수 있다.

- User 칼럼이 공백으로 되어있으면 모든 사용자를 의미한다.

- Password 가 공백으로 되어있다고 해서 모든 비밀번호를 허용하는 것은 아니다. Password 가

- 공백이면 해당 사용자는 비밀번호를 사용하지 않는다는 의미이다. 이 때는 비밀번호 인증을 거치

- 지 않고 접속해야만 접속이 허용된다.


- 다음은 각각의 Host 칼럼과 User 칼럼의 설정에 따라 매치되는 사용자명 및 호스트명을 나타낸

- 표이다.


+----------------------------+---------------+-----------------------------------------+

| Host 칼럼의 값                     | User 칼럼의 값 | 매치되는 사용자 및 호스트                        |

+----------------------------+---------------------------------------------------------+

| 'thomas.loc.gov'                  | 'fred'              | thomas.loc.gov 로부터 접속한                   |

|                                          |                       | fred 라는 사용자                                     |

| 'thomas.loc.gov'                 | ' '                   | thomas.loc.gov 로부터 접속한 모든 사용자  |

| '%'                                    | 'fred'               | 모든 호스트에 해당하는 fred 라는 사용자     |

| '%'                                    | ' '                   | 모든 호스트의 모든 사용자                         |

| '%.loc.gov'                         | 'fred'              | loc.gov 도메인의 모든 호스트에서 접속한     |

|                                          |                      |  fred 라는 사용자                                      |

| 'x.y.%'                               | 'fred'              | x.y.com 이나 x.y.edu 등에서 접속한            |

|                                          |                      |  fred 라는 사용자                                      |

| '144.155.166.177'                  | 'fred'              | IP 주소 144.155.166.177 로부터 접속한         |

|                                          |                      |  fred 라는 사용자                                      |

| '144.155.166.%'                    | 'fred'              | IP 주소 144.155.166 클래스 C subnet 에 속하|

|                                          |                      |  는모든 호스트에서 접속한 fred 라는 사용자  |

| '144.155.166.0/255.255.255.0' | 'fred'              | IP 주소 144.155.166 클래스 C subnet에 속하 |

|                                          |                      |  는 모든 호스트에 접속한 fred 라는 사용자    |

|                                          |                      | (255.255.255.0 은 netmask 이다.)                |

+----------------------------+---------------+-----------------------------------------+


- 그런데 접속을 받아들일 때 해당 접속은 user 테이블에서 하나 이상의 로우가 매치될 수 있다.

- 예를 들어 thomas.loc.gov by 에서 접속한 fred 는 Host 칼럼 값이 thomas.loc.gov 이고 User

- 칼럼값이 fred 인 로우에도 매치되지만 Host 칼럼값이 % 인 로우에도 매치된다. 이 때 fred 는

- 어떤 로우에 설정된 권한이 적용되는 것일까?



- MySQL 은 이러한 문제를 기동시에 user 테이블은 메모리상에 일정한 규칙대로 정렬함으로써

- 해결한다. '사용자 추가, 삭제 및 권한변경' 에서 다시 설명하겠지만 MySQL 에서 권한을 읽어들

- 일때는 권한 테이블에서 직접 읽는 것이 아니라 MySQL 기동시 권한 테이블로부터 권한을 읽어서

- 메모리상에 올려놓고 거기에서 권한을 읽는 것이다. 이 때 user 테이블은 일정한 규칙에 의해

- 메모리상에 정렬되는데 지금부터 그 규칙을 설명하도록 하겠다.


- 예를 들어 user 테이블에 다음과 같이 로우들이 정렬되어 있다고 가정해보자.


+----------+---------+

| Host        | User      |

+----------+---------+

| %           | root       |

| %           | jeffrey    |

| localhost | root       |

| localhost |              |

+----------+---------+


- 이 user 테이블이 MySQL 이 기동되면서 메모리상에 올라갈 때는 먼저 Host 칼럼의 값이 가장

- 분명하고 특화된 로우부터 정렬된다. 즉, Host 칼럼값이 % 인 것과 같이 특화되지 않은 로우보다

- localhost 와 같이 분명한 로우가 먼저 정렬이 된다. 그러한 식으로 로우를 정렬한 다음, 같은

- Host 칼럼값을 갖는 로우들에 대해서는 User 칼럼의 값이 특화된 로우순으로 정렬을 하게 된다.

- 따라서 앞서와 같은 테이블은 메모리에 올려질 때 다음과 같이 정렬된다.


+----------+---------+

| Host        | User      |

+----------+---------+

| localhost  | root      |

| localhost  |            |

| %            | jeffery   |

| %            | root      |

+----------+---------+


- 만약 사용자명이 jeffery 이고 접속한 호스트가 localhost 인 사용자가 접속한다면 해당하는 권한

- 로우는 앞서와같은 정렬 순서에 따라 Host 칼럼값이 localhost 이고 User 칼럼값이 공백인 로우

- 가 된다.


- 여기 또 하나의 예가 있다. user 테이블에 다음과 같은 로우가 있다고 가정해 보자.


+----------------+---------+

| Host                 | User      |

+----------------+---------+

| %                    | jeffery    |

| thomas.loc.gov  |             |

+----------------+---------+


- 이 로우들은 MySQL 기동시 메모리상에 다음과 같이 정렬될 것이다.


+----------------+---------+

| Host                 | User      |

+----------------+---------+

| thomas.loc.gov  |             |

| %                    | jeffery    |

+----------------+---------+


- 2 단계 : 요청 인증

- 일단 접속에 성공하면 MySQL 서버는 요청을 기다리는 상태가 된다. 요청을 기다리고 있다가

- SQL 과 같은 요청이 들어오면 해당 사용자가 그 SQL 을 실행할 권한이 있는지 체크하여 권한이

- 있으면 SQL 을 실행하고 권한이 없으면 권한이 없다는 에러를 출력시킨다.


- 요청에 대한 실행 권한을 체크하는데 사용하는 테이블은 user, db, host, tables_priv, 그리고

- columns_priv 테이블이다.


- user 테이블은 모든 DATABASE 에 대한 권한을 설정하는 테이블이다. 만약 user 테이블에서

- Delete_priv 칼럼값이 Y 로 세팅되어있다면 그 사용자는 모든 DATABASE 에 대하여 데이터를

- 삭제할 수 있는 권한을 가지게 된다. 따라서 user 테이블의 모든 권한 칼럼값이 Y 로 되어있는

- 사용자는 슈퍼 유저의 권한을 가지는 사용자라고 할 수 있다.


- 요청에 대한 실행 권한을 체크할 때 user 테이블에 Y 로 되어있으면 db 나 host 테이블을 살펴볼

- 것도 없이 바로 해당 요청을 실행하게 된다.


- N 로 되어있으면 db 와 host 테이블로 넘어가서 해당 DATABASE 에 대해 실행 권한이 있는지

- 체크하게 된다.


- db 테이블에서는 User 칼럼과 Host 칼럼으로부터 사용자명과 호스트명이 매치되는 로우를 찾아

- 서 해당 DATABASE 에 대해 실행 권한을 가지는지 체크하게 된다. 만약 Host 칼럼이 공백으로 되

- 어 있으면 host 테이블을 처크해서 해당 DATABASE 에 대해 접속한 호스트별로 다른 권한을

- 부여하게 된다. 요청에 대해 테이블의 권한 칼럼값이 Y 로 세팅되어 있으면 요청을 실행하고 그렇

- 지 않고 N 으로 되어있으면 tables_priv, columns_priv 테이블을 체크해서 권한이 있는지 확인

- 하게 된다.


- tables_priv 와 columns_priv 테이블은 각각 해당 테이블과 칼럼에 대한 권한이 있는지 체크한다.

- 이 때의 칼럼 타입은 ENUM 이 아니고 SET 이다. 따라서 칼럼값은 'Select', 'Insert', 'Update',

- 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter' 중에서 필요한 권한이 세팅되

- 어 있다.


+--------------------------------------------------------------+

|                                                                                             |

| SQL 검사 --> user 테이블 검사 --> 권한이 있으면 --> SQL 실행   |

|                                |                                                            |

|            권한이 없으면 |                                                            |

|                                |                                                            |

|                       db 테이블 검사  --> 권한이 있으면 --> SQL 실행   |

|                                |                                                            |

|            권한이 없으면 |                                                            |

|                                |                                                            |

|           tables_priv 테이블 검사  --> 권한이 있으면 --> SQL 실행   |

|                                |                                                            |

|           권한이 없으면  |                                                            |

|                                |                                                            |

|       columns_priv 테이블 검사  --> 권한이 있으면 --> SQL 실행    |

|                                                                                             |

+--------------------------------------------------------------+

- SQL 실행 권한 검사 과정

출처 : Tong - culguyec님의 기본통

by 뭔일이여 2007. 3. 30. 13:48
스티븐 스필버그 감독은 영화 <뮌헨>을 발표한 후 알고 지내던 유태인 친구를 여러 명 잃었다고 고백했다. 영화 속에서 주인공은 이스라엘 정보기관 모사드의 도움을 받아 폭탄 제조, 문서 위조, 사건 뒤처리 등의 다양한 재주를 가진 6명의 요원으로 팀을 구성한 다음, 1972년 뮌헨 올림픽 선수촌에서 테러를 일으킨 검은 9월단의 배후 요원들을 한 명씩 살해한다.

하지만 시간이 흐르면서 주인공을 비롯한 요원들은 국가를 위한 복수와 비인도적인 살인 행위 사이에서 갈등을 겪게 되고 스스로의 생명마저 위협받자 깊은 회의에 빠져들게 된다. 스필버그 감독은 인간적인‘갈등’과‘회의’를 그렸을 뿐인데 열혈 유태인들은 그것조차 용납하기 어려웠던 모양이다.

아무튼 영화 속의 주인공은 복수의 대상 11명이 은거하고 있는 장소와 그밖에 필요한 정보를 얻기 위해서 일종의‘정보 브로커’와 거래를 한다. 그에게 거액의 돈을 주고 살해할 대상이 숨어 있는 장소에 대한 정보를 얻는 것이다. 재미있는 점은 주인공의 복수가 진행되는 동안 다른 나라의 정보조직에서도 똑같은 정보 브로커에게 접근해서 주인공과 동료들의 신원을 파악하려고 한다는 점이다. 이름도 없고, 얼굴도 없어서 어느 누구에게도 존재가 드러나지 않아야 하는 정보조직 세계의 요원들이 이렇게 ‘정보 브로커’라는 존재를 통해서 오히려 하나의 지점에서 만나는 현상이 벌어진다.

  상황중심이란 개념 이해하기

이렇게 다양한 독립적인 개체들이 자신의 목적을 위해서 공통적으로 통과할 수밖에 없는 지점, 혹은 수행할 수밖에 없는 행동을 상황중심 프로그래밍(Aspect Oriented Programming)에서는 접점(join point)라고 부른다.‘ 상황중심’이란 요즘 프로그래밍 세계에서 주목을 받고 있는 ‘Aspect Oriented’라는 표현을 나름대로 우리말로 옮겨본 것이다.‘ Aspect Oriented’라는 말이 국내에서는‘관점 지향’이라는 말로 표현되기도 하는데, 이것은 그 동안 ‘Object Oriented’를‘객체 지향’이라고 불러온 관성의 영향인 것으로 생각된다.

사실‘관점 지향’이라는 말은 의미가 분명하지 않을 뿐만 아니라 겉으로 드러나는 의미조차 정확하다고 보기 어렵다. ‘관점’을‘지향’한다니? 프로그래밍을 수행하는 사람이 자기 관점을 분명히 세우고 그것을 목표로 전진하라는 말인가?‘ 관점 지향’이라는 말이 국내 프로그래머 사이에서 일정한 합의를 이루고 있는 표현이라면 어쩔 수 없지만, 최소한 이 글에서는‘Aspect Object’를‘상황중심’으로 표현하고자 한다. 이렇게 해야 새로운 방법론이 전하고자 하는 의미가 분명하게 드러나기 때문이다.

상황중심 프로그래밍은 말 그대로 현재의 소프트웨어 코드가 처해 있는 특정한‘상황’에 초점을 맞추는 프로그래밍을 의미한다. 폭발적으로 늘어나는 수요를 감당하지 못해 심각한 위기를 맞이했던 소프트웨어 개발시장은‘모듈(module)’과‘객체(object)’라는 혁명적인 개념을 발견하면서 위기를 극복했다. 방대한 분량의 소프트웨어 코드를 모듈과 객체라는 작고 독립적인 부분으로 분리할 수 있었기 때문에 프로그래머들은 점점 더 복잡한 업무를 수행하는 코드를 만들어 낼 수 있었던 것이다. 하지만 독립적인 모듈과 객체의 수마저 기하급수적인 규모로 증가하면서 예전과는 전혀 다른 문제가 대두되었다.

모듈과 객체는 코드를 추상적이고 부분적인 캡슐로 분리해서 전체적인 코드에 대한 관리가 가능하도록 만들고 필요하면 재사용 할 수 있는 방법까지 제공했다. 즉 모듈과 객체는 코드의 부분을 떼어내서 추상화하는 방법을 제공한 것이다. 하지만 이러한 방법은 모듈과 객체를 가로지르며 존재하는 공통의 관심사(cross-cutting concern)를 효율적으로 추상화하는 방법은 제공하지 않았다. 공통의 관심사란 보안(security), 성능(performance), 기록(logging)과 같은 소프트웨어의 일반적인 속성에서부터 데이터 캐시(cache) 관리나 네트워크 프로토콜의 구현처럼 구체적인 기능에 이르기까지 다양하다.

이러한 공통의 관심사는 특정한 모듈이나 객체가 구현하는 기능에 국한되는 것이 아니라 소프트웨어 시스템 전체에 걸쳐 수평적으로 영향을 미친다. 잘 이해가 되지 않는 독자는 다음 예를 생각해 보면 도움이 될 것이다.

  공통의 관심사

인터넷 붐이 한창이던 90년대에 미국에서는‘수평적 시장(horizontal market)’과‘수직적 시장(vertical market)’이라는 표현이 자주 사용되었다. 수직적 시장이란 어떤 제품이 특정한 분야의 시장에 국한되는 경우를 의미한다. 예를 들어서 책, 의류, 자동차, 컴퓨터, 혹은 의료보험 시스템 등은 다른 분야와 겹치지 않는 자기 자신만의 시장을 형성한다.

이들은 모두 수직적 시장의 예이다. 하지만 웹브라우저와 같은 소프트웨어는 특정한 시장에 국한되지 않고 모든 수직적 시장들 사이에 공통적으로 존재하며 영향을 미친다. 그 자체로는 특정 품목에 대한 시장을 형성하지 않지만 여러 시장에서 동시에 존재하는‘공통의 관심사’가 되는 것이다.

영화 <뮌헨>에서 이스라엘의 모사드, 소련의 KGB, 미국의 CIA, 팔레스타인의 검은 9월단 등은 각자 겹치지 않는 고유의 영역을 구성하고 있지만, 그들이 어떤 인물의 은신처를‘검색’하기 위해서는 다양한 정보를 보유하고 있는‘정보 브로커’를 찾아가야만 했다. 각 국의 정보기관이 수직적 시장을 형성하고 있다면,‘ 정보 브로커’는 웹브라우저와 마찬가지로 수평적 시장을 형성하고 있는 셈이다. 이 경우에‘정보 브로커’는 여러 정보기관들을 가로지르며 공통적으로 존재하는‘공통의 관심사’로서의 역할을 담당한다.

오늘날의 프로그래밍 세계에서 수직적 시장을 구성하는 존재는 말할 것도 없이‘객체’들이다. 객체들은 저마다
주어진 일감을 구현하면서 일이 서로 겹치지 않도록 소프트웨어의 전체 영역을 분할한다. 이렇게 분할을 더욱 효율적으로 만들기 위해서 비슷한 일을 하는 객체를 한곳에 묶어서‘패키지(package)’라고 부르기도 한다. 지금까지 프로그래밍은 이러한 분할을 통해서 충분히 잘 이루어져 왔다.

하지만 이렇게 역할 분담을 통한 균형과 평화가 이루어진 상황에서도 여러 객체 사이에 존재하는‘공통의 관심사’는 존재하기 마련이다. 앞에서 예로 든 보안, 성능, 기록, 캐시, 프로토콜 등이 바로 그들이다. 이밖에 유닛테스트(unit test)나 테스트 자동화 등도 여기에 포함될 수 있을 것이다.

좀 더 이해를 돕기 위해서 하나의 구체적인 상황을 생각해보자. 소프트웨어의 사용자들이 항상 그렇듯이 개발자가 개발한 시스템을 이용하는 사용자 중에는 구체적인 데이터를 제시하지 않으면서 말로만“시스템이 느려 터졌다.

답답해서 못 쓰겠다.”라고 불평을 늘어놓는 사람이 있다. 소프트웨어를 제작하고 관리하는 입장에서는 이렇게 막연하게 불평만 늘어놓는 사용자처럼 속상한 존재가 없다.

구체적으로 어떤 기능을 사용할 때‘느린지’를 알아야 그가 겪고 있는 문제가 PC 하드웨어와 관련된 문제인지, 개발자가 만든 소프트웨어의 문제인지, 네트워크의 문제인지, 혹은 서버나 데이터베이스의 문제인지를 알 수 있고 그에 따른 해결책을 제시할 수 있기 때문이다(물론 사용자가 허락만 해준다면 그가 소프트웨어를 어떻게 사용하는지 직접 관찰할 수도 있을 것이다. 하지만 성격이 곱지 않은 월스트리트의 트레이더에게‘저는 소프트웨어를 제작한 사람인데요, 잠시 옆에서 PC를 사용하는 모습을 관찰해도 될 까요’라고 묻는 것은 자살 행위이다).

그렇지만 사용자가 데이터를 제공해 주지 않는다고 해서 손을 놓고 있을 수는 없으므로 우리는 필요한 데이터를 스스로 구해야 한다는 결론을 내리게 되었다. 그리하여 우리가 구현하기로 한 기능은 사용자가 소프트웨어에서 어떤 동작을 수행할 때마다 맨 처음 GUI의 이벤트 처리 메소드(event handler)에서 출발해서 서버와 데이터베이스에 이르는 과정에 존재하는 각 계층을 통과하는 데 걸린 시간을 측정한 다음 로그 파일과 같은 하나의 장소에 기록하는 것이었다.

  스파이로그

사용자가 GUI 화면에서 주식이나 채권 가격 같은 데이터를 입력하고 OK 버튼을 눌렀다고 해보자. 그러면 소프트웨어의 흐름은 GUI 계층, GUI 계층 아래에 존재하는 네트워크 계층, 실제 네트워크 전송, 서버에서 사용자의 요청을 받아들여서 적절한 컴포넌트( component)에게 전달하는 계층, 데이터베이스에 저장되어 있는 프로시저(stored procedure), 최종적인 데이터를 담고 있는 응답객체를 생성하는 계층, 응답 객체를 GUI 클라이언트에게 전송하는 계층, GUI가 서버의 응답을 받아서 처리하는 계층 등을 차례로 통과한다.

이 때 각 계층에서 소요된 시간을 측정해서 하나의 객체에 저장하는 것이다. 이렇게 처리시간이 기록된 객체는 각 계층을 통과할 때마다 다음 계층에게 전달되면서 값을 축적해 나간다. 필요한 처리 과정이 모두 끝나고 나면 이 객체에 저장된 값은 미리 지정된 포맷에 따라서 로그 파일에 기록되고 객체의 수명은 끝이 난다.

이제 사용자가 시스템의 성능에 대해서 밑도 끝도 없는 불평을 늘어놓으면 로그 파일에 저장되어 있는 데이터를 분석해서 실제로 성능에 문제가 있었는지, 만약 문제가 있었다면 어느 계층에서 문제가 있었는지를 파악할 수 있다.

이렇게 유용한 기능의 이름을‘스파이로그’라고 불러보자. 앞의 설명을 읽으면서‘흠 소프트웨어의 여러 계층을 관통하는 <공통의 관심사>를 설명하려고 애쓰고 있군’하고 생각하는 독자가 있다면 만점이다. ‘공통의 관심사(crosscutting concern)’라는 개념을 이해했다면 상황중심 프로그래밍의 98%를 거의 이해한 것과 다름이 없다.

이러한 스파이로그를 실제로 구현하는 방법은 어렵지 않다. 소프트웨어가 객체지향 기법에 따라서 계층별로 잘 분리되어 있다면 더욱 그러하다. 각 계층의 시작과 끝 부분에서 시간을 측정하는 데 필요한 동작을 수행하기만 하면 되기 때문이다. 하지만 그것이 가능하기 위해서는 최소한 두개의 전제 조건이 필요하다. 하나는 스파이로그를 구현하는 프로그래머가 각 계층의 입구와 출구를 정확하게 파악하고 있어야 한다는 점이고, 두 번째는 스파이로그를 구현하기 위해서는 입구와 출구에 해당하는 객체의 소스 파일이 수정되어야 한다는 점이다. 즉, 입구에 해당하는 위치에서는 앞의 계층에서 전달한 시간 측정용 객체를 받아들인 다음 들어온 시간(time stamp)을 찍고, 출구에 해당하는 위치에서는 같은 객체 위에 나가는 시간을 찍고 나서 뒤에 있는 계층에게 객체를 전달해 주는 것이다.

이런 방법은 기능적으로는 아무런 문제가 없지만 코드의 관리라는 측면에서 보면 문제가 많다. 한 가지만 예를 들자면 이런 식이다. 시스템에 A, B, C, D라는 네 개의 계층이 존재한다고 하자. 하나의 동작(operation)이 완성되려면 A, B, C, D, C, B, A라는 완성된 사이클이 그려져야하고, 스파이로그는 이러한 일곱 단계가 소비하는 시간을 각각 측정해서 기록한다.

그런데 나중에 누가 C 계층을 리팩토링해서 그것을 C1과 C2라는 두 개의 계층으로 분리했다고 가정해보자. 그리고 스파이로그의 존재를 의식하지 못한 그가 C1이 받아들인 객체를 C2에게 전달하는 것을 깜빡 잊었다고 하자. 이와 같은 본의 아닌‘실수’가 도입되는 순간 C1과 C2 사이의 고리가 끊어지면서 스파이로그의 기능은 동작을 멈출 수밖에 없다.

여러 계층이 공유하고 있는‘공통의 관심사’가 단지 한계층에서 발생한 실수 때문에 완전히 동작을 멈춘다는 것은 공정하게 들리지 않는다. 뿐만 아니라 스파이로그의 기능이 여러 소스 파일에 분산되면서 코드의 관리가 어려워진다는 단점도 존재한다. 이러한 상황은 서로 독립적으로 분할되어 있어야 하는‘객체’라는 존재를 중심으로 하는 프로그래밍 방법론으로는 명쾌하게 해결되기 어렵다.

객체는 본질적으로 다른 객체와 나란히 서 있도록 만들어진 존재이지, 다른 객체의 허리를 가로지르며 직교(orthogonal)하도록 만들어진 존재가 아니기 때문이다. 바로 이와 같이‘난처한 상황’에서 힘을 발휘하는 것이‘상황중심’의 프로그래밍이다.

  제록스 팔로알토연구소에서 탄생

상황중심 프로그래밍이라는 개념은 제록스 팔로알토 연구소에서 탄생한 것으로 알려져 있다. 현재 캐나다의 브리티시 콜롬비아 대학의 컴퓨터 사이언스 교수인 그레고르킥잘레스(Gregor Kiczales)는 팔로알토 연구소에서의 연구를 확장해서 현재 상황중심 프로그래밍 세계에서 대표적인 언어로 인정받고 있는 AspectJ를 설계했다. IBM에서도 HyperJ나 관심 변경 환경(Concern Manipulation Environment)과 같은 상황중심 프로그래밍 언어를 발표했지만, 현재 프로그래머 사이에서 널리 받아들여지고 있는 언어는 단연 AspectJ이다.

상황중심 프로그래밍에서 사용하는 개념은 크게 네 가지가 있다. 접점(pointcut), 안내(advice), 내부타입 선언(inter type declaration), 그리고 이들을 모두 묶어서 하나의 단위로 추상화하는 상황(aspect)이 그들이다. 상황중심 프로그래밍이나 이러한 개념들이 의미하는 바는 AspectJ의 홈페이지 등에서 쉽게 접할 수 있다. AspectJ에 대한 책도 이미 적지 않게 나와 있다. 여기에서 이들이 의미하는 바를 간단하게 살펴보자면 이렇다.

우선 접점(pointcut)은 공통의 관심사가 여러 개의 객체나 계층을 가로지를 때 그들과 만나게 되는 지점을 의미한다. 앞에서 살펴본 예에서는 각 계층의 입구와 출구가 접점에 해당하고, 더 앞에서 든 예에서는 모사드, CIA, KGB의 요원들이‘정보 브로커’와 만나는 상황 자체가 접점에 해당할 것이다. 접점은 상황중심 프로그래밍을 수행하는 프로그래머가 이미 존재하는 소프트웨어 시스템을 이해하고 있는 수준, 혹은 핵심을 짚어내는 안목에 따라 제대로 짚어질 수도 있고, 엉뚱한 곳이 접점으로 인식될 수도 있다. 어쨌든 프로그래머가 일단 접점을 골라냈으면 그 다음에 할 일은 그 곳에서 할 일을 정의하는 것이다.

그것이 안내(advice)이다. 상황중심 프로그래밍에서 안내는 객체지향 프로그래밍에서의 메소드에 해당한다고 생각하면 쉽다. 특정한 접점에 이르기 직전이나 혹은 직후에 어떤 일을 할 것인가를 정의하는 알고리즘이 안내의 내용을 이룬다.

내부 타입 정의(inter type declaration)는 약간 복잡하다. 이것은 자바 프로그래밍과 같은 기존의 프로그래밍 방식에 익숙한 사람들에게 개념적인 혼란을 초래하기 때문이다. 자바 언어를 예로 들자면, 어느 객체에게 새로운 인스턴스 변수(instance variable) 혹은 필드(field)를 추가하는 것은 언제나 소스 코드의 수정과 컴파일을 통해서 이루어진다.

프로그램이 실행되고 있는 도중에 새로운 필드를 내 마음대로 추가할 수는 없는 것이다. 자바 런타임(runtime) 내부에서 클래스 이름만 가지고 클래스의 인스턴스를 만들어내는 기능은 있지만 클래스에 이미 정의되어 있지 않은 필드를 더하는 기능은 없다.

그런데 상황중심 프로그램에서 사용하는‘내부 타입 정의’기능은 객체에게 새로운 필드를 동적으로 더하는 것을 가능하게 만든다. 이러한 기능이 필요한 이유는 이미 존재하는 다양한 객체와 계층을 가로지르면서 동작하는 알고 리즘을 작성하기 위해서는 주어진 객체의 정해진 틀을 뛰어넘는 능력이 필요하기 때문일 것으로 추측된다. 사실 필자 역시 상황중심 프로그래밍에 익숙하지 않기 때문에 섣불리 말하기는 어렵지만, 이러한 기능이 바람직한지에 대해서는 의문이 든다.

상황중심 프로그래밍을 구사하는 프로그래머가 어느 객체에게 내부 타입 정의 기능을 이용해서 동적으로 어떤 필드를 추가했다고 해보자. 그는 객체를 정의하고 있는 클래스에 새로운 필드를 사용하는 알고리즘을 추가할 수도 있다. ‘( 내부 타입 정의’기능을 통해서 추가한 필드가 퍼블릭으로 정의되어 있다면 기존의 자바 코드에서 접근하는 것이 가능하기 때문이다.)

이렇게 작성된 소스 코드를 나중에 읽는 다른 프로그래머는 (특히 그가 상황중심 프로그램의 존재를 인식하지 못하고 있다면) 도대체 이 코드가 사용하고 있는 필드가 어디에 정의되어 있는 것인지 알 길이 없다. 이런 식의 혼란은 미묘한 버그의 원인이 될 수 있다.

이런 측면에서 보자면 내부 타입 정의를 이용하는 것은 멀쩡한 객체에게 뼈를 깎고 살을 붙이는 성형수술을 시도하는 것, 혹은 객체의 유전자를 조작해서 없던 장기를 만들어 내는 것에 비유할 만하다. 수술이나 유전자 조작이 필요한 결과를 낳는다면 다행이지만, 잘못된 결과를 낳거나 그것이 남용된다면 차라리 하지 않느니만 못한 일이 될 것이다.

마지막으로, 객체지향 프로그래밍에서 클래스가 변수와 메소드를 한 곳에 묶어서 하나의 객체로 추상화하듯, 상황중심 프로그래밍에서 사용되는 접점, 안내, 내부 타입 정의를 한 곳에 묶어서 추상화하는 것은‘상황(aspect)’이다. 따라서 상황은 객체지향 프로그래밍에서 객체가 중심에 서있듯이 상황중심 프로그래밍에서 가장 중심에 서있는 개념이 된다(이것은 프로그래머들이 혐오하는‘중복’된 표현처럼 들린다. 하지만 달리 표현할 방법이 없다. 상황중심 프로그래밍에서 중심은 상황이기 때문이다).

* 이 기사는 ZDNet Korea의 제휴매체인 마이크로소프트웨어에 게재된 내용입니다.

출처 - ZDNet
by 뭔일이여 2007. 3. 26. 14:07

Feel free to test JavaScript's RegExp support right here in your browser. Obviously, JavaScript (or Microsoft's variant JScript) will need to be enabled in your browser for this to work. Since this tester is implemented in JavaScript, it will reflect the features and limitations of your web browser's JavaScript implementation. If you're looking for a general-purpose regular expression tester supporting a variety of regex flavors, grab yourself a copy of RegexBuddy.

Learn how to use the JavaScript RegExp object.

Regexp:

Subject string:

Replacement text:

Result:

JavaScript RegExp Tester Source Code

<SCRIPT LANGUAGE="JavaScript">
<!--
function demoMatchClick() {
    var re = new RegExp(document.demoMatch.regex.value);
    if (document.demoMatch.subject.value.match(re)) {
        alert("Successful match");
    }
    else { alert("No match"); }
}
function demoShowMatchClick() {
    var re = new RegExp(document.demoMatch.regex.value);
    var m = re.exec(document.demoMatch.subject.value);
    if (m == null) { alert("No match"); }
    else {
        var s = "Match at position " + m.index + ":\n";
        for (i = 0; i < m.length; i++) { s = s + m[i] + "\n"; }
        alert(s);
    }
}
function demoReplaceClick() {
    var re = new RegExp(document.demoMatch.regex.value, "g");
    document.demoMatch.result.value = document.demoMatch.subject.value.replace(re, document.demoMatch.replacement.value);
}
// -->
</SCRIPT>
<FORM ID="demoMatch" NAME="demoMatch" METHOD=POST ACTION="javascript:void(0)">
<P>Regexp: <INPUT TYPE=TEXT NAME="regex" VALUE="\bt[a-z]+\b" SIZE=50></P>
<P>Subject string: <INPUT TYPE=TEXT NAME="subject" VALUE="This is a test of the JavaScript RegExp object" SIZE=50></P>
<P><INPUT TYPE=SUBMIT VALUE="Test Match" ONCLICK="demoMatchClick()">
<INPUT TYPE=SUBMIT VALUE="Show Match" ONCLICK="demoShowMatchClick()"></P>
<P>Replacement text: <INPUT TYPE=TEXT NAME="replacement" VALUE="replaced" SIZE=50></P>
<P>Result: <INPUT TYPE=TEXT NAME="result" VALUE="click the button to see the result" SIZE=50></P>
<P><INPUT TYPE=SUBMIT VALUE="Replace" ONCLICK="demoReplaceClick()"></P>
</FORM>
by 뭔일이여 2007. 3. 23. 19:21

정확히 말하면 ECMA 스크립트의 특징이지만 뭐… ^^

첫번째, 객체의 생성

var arr = [];
var obj = {};
var str = "";
var arr1 = [1,2,3];
var obj1 = {prop1 : 'value1', "prop2" : 'value2'};


Object는 {} 로, Array는 []로 생성할 수 있다. object 를 생성할 때 property 의 이름은 따옴표를 따로 해주지 않아도 prop1의 경우처럼 그냥 사용할 수 있다. 하지만, 혹시라도 있을지 모르는 문제점(prop1이 변수로 선언되어있다던가 하는…)을 미리 방지하기 위해서 따옴표를 붙여주도록 하는게 좋다. 단, 충돌이 없음이 확실하다면 생략해도 무방하다.

두번째, object property의 접근

var obj = { "prop1" : "value1", "prop2" : "value2" };
alert(obj.prop1);
alert(obj["prop1"]);


. 으로 호출하는 방법, 문자열로 인덱스를 지정하는 방법. 둘 다 사용가능하다. 따라서 다음과 같은 것도 가능하다.

var i=2;
alert(obj["prop"+i]);

세번째, or 의 사용

var val = predefined_value || "value";


or 연산자로 연결된 값을 처음부터 비교해서 false와 동등하게 처리되는 값이 아니라면 반환한다. false와 동등하게 처리되는 값에는 undefined, null, 숫자0, false가 있다. 위 코드에서는 predefined_value 라는 변수가 정의되어있지 않으면 “value”이라는 값을 val 이라는 변수에 할당한다. 보통 IE와 FF의 이벤트 처리가 다른데 그럴 경우에 다음과 같이 사용하기도 한다.

function eventHandler(e) {
  var evt = e || window.event;
// ... some code
}

네번째, 괄호()의 사용

(function(str){
  alert(str);
})("str");


괄 호는 괄호안의 내용을 해석/실행해서 결과값을 리턴하는 역할이다. (1+2) 라고 하면 괄호는 1+2를 계산해 3 이라는 값을 리턴하는 것과 마찬가지라는 뜻. 따라서 위처럼 anonymous 함수를 만들어놓고 바로 실행할 수도 있게된다(괄호를 통해 함수객체가 반환되었기 때문).
____________________________________________________
추가 - 2007.3.25


아래 코멘트들을 보고 혹시 헛갈려 하시는 분들이 있을까봐 정리해드립니다.
----------------------------------------
var obj = new Object; 와
var obj = {}; 은 같은 표현입니다.

{}을 이용하면 연관배열처럼 사용할 수는 있지만 여전히 Object 타입이며, 연관배열 타입이라는 것은 존재하지 않습니다. 보는 관점에 따라서 javascript에 객체란 없으며 모두 연관배열처럼 구성되어있다는 입장도 있습니다. 마치, PHP의 클래스들이 배열로 구성된 것과 같은 이치입니다. 하지만, {}가 Object 타입의 인스턴스라는 것에는 이의가 없습니다. 있다면, 다른 분들이 말씀해주실 것으로 압니다.

제 견해로는 아무리 느슨해도 객체는 객체입니다. 유연함이 가능한 스크립트언어의 특성일 뿐, 연관배열이 아닌 동적 프로퍼티 구성이 가능한 것으로 봐야 한다는게 제 의견입니다. 자바스크립트는 내장 함수도 재정의할 수 있을 정도로 유연한 언어입니다.

참고로, PHP에서도 연관배열이 따로 존재하지만,
$inst = new Klass;
$inst->a = "bc";
$inst->b = "de";

와 같이 동적으로 프로퍼티를 생성하는게 가능합니다.
----------------------------------------
var obj = {
  "a" : "bc",
  "b" : "de",
  "f" : function() {
      alert(this.a);
  }
};
obj.f();

{}이 Object 타입이 아니라 단순한 연관배열일 뿐이라면 this 는 window 객체가 되어야 하지만 결과는 그렇지 않습니다. 위 표현은 다음과 같이 변경할 수도 있습니다.

var obj = new Object;
obj.a = "bc";
obj.b = "de";
obj.f = "function() {
    alert(this.a);
}
obj.f();

완전히 같은 경우입니다. {}은 new Object 와 같은 결과이며, {프로퍼티이름:값}은 new Object를 만들고 프로퍼티와 값을 작성해준 경우입니다. 이는 ECMA-262 문서에 나와있는 내용입니다.

따라서, {}을 연관배열 표현이라고 부르는 것은 잘못된 견해라고 봅니다. 메소드가 없다면 연관배열 혹은 해시라고 부르는 것처럼 사용할 수도 있습니다만, 그렇다고 해서 {}이 연관배열의 표현인 것은 아닙니다.

{}은 Object의 인스턴스를 생성하는 Object literal 입니다.
혹시라도 오해없으시길 바랍니다.
______________________________________

참고로, 지금 Mozilla에서 준비하고 있는 Tamarin 프로젝트에서 ECMA4 엔진을 개발중이며 이 엔진의 결과로 Javascript2 가 나옵니다. Javascript2에는 class 가 생길거라고 하는군요.

Taramin 프로젝트에 대해서 쓰다가 좀 길어져서 별도의 글로 다시 작성합니다. ^^;;
  License
이 게시물은 저작자에게 모든 권리가 있습니다.

   TP™날나리코더   07-03-21 22:17  
퍼가요...
   칼솜™   07-03-21 22:50  
유용한 정보 감사합니다.
그런데 버전 낮은 브라우저도 지원하나요?
   BL   07-03-21 23:24  
본적은 있는데 설명을 들으니까 더 .. 신기하네요..  거참.. ㅎㅎ
   초싸가지인   07-03-21 23:59  
구글소스에 보니 저 마지막 부분있든데.. 흐..이제 이해가 되네요
고니님 자바스크립 강좌란이 있었음 하는 바램..
   지아쁠젝또   07-03-22 00:50  
마지막까지 설명을 해주신 것들이 잘 몰랐던 건데 이렇게 간단히 설명을 해주시니 정말 도움이 많이 됐습니다.
   TP™ 아쿠아   07-03-22 08:26  
솥아님 소스보고 깨달은것
솥아님 ㄳㄳ~
   Innocence   07-03-22 09:19  
좋은 정보 감사드립니다.
어떤책에서 JSON 표기법이라고 해서 봤는데.
보니 더 이해서 ^^;
   딸기키우자   07-03-22 09:52  
잘 봤습니다.

고운하루보내세요
   iamSeeker   07-03-22 09:57  
좋은 정보 감사합니다~
   피곤해   07-03-22 10:03  
좋은 정보 감사합니다.
   시련   07-03-22 10:12  
좋은 정보 감사합니다.
   호랑이풀   07-03-22 10:43  
감사요
   Roddy   07-03-22 10:54  
아주 유용한 정보를 알기쉽게 잘 정리하셨네요, var obj = {} 만 잘 사용하면 여러모로 많이 편리하더군요.

var APP1 = {};
APP1.aaa = function(a) { alert(a) };
APP1.bbb = function(config)
{
    alert(config.a);
    alert(config.b);
}
APP1.bbb({a : 1, b : 2});
   명랑폐인   07-03-22 11:39  
평소 궁금했었는데... 감사합니다.
   부비컴   07-03-22 11:52  
좋은데요 감사합니다.
   낭망백수   07-03-22 12:32  
{} 이건 연관배열 표현인데, ajax in action 에 따르면 Javascript 에서 객체는 배열로 표현된답니다.
꾸벅~!
     
   comefeel   07-03-22 13:19  
ㅎㅎ 옛날부터 알고잇었는데 절케 쉽게 갈켜주다니 ~ ㅋㅋ 난저거 뭔지 몰라서

알려고 삽질좀 했는데 ㅋㅋㅋ 참 정보는 좋아여  ~
     
   행복한고니   07-03-22 13:36  
배열 비슷하게 표현된다고 해서 그게 배열인 것은 아닙니다. 연관배열처럼 보이는 Object type 입니다.

var obj = new Object; 이 표현이나
var obj = {}; 이것은 똑같은 표현입니다.
          
   낭망백수   07-03-22 23:05  
^^; 연관배열로 객체가 구현되어있다는 뜻입니다.
실제로 객체지향언어가 아닌 것도 아시리라 생각합니다.
꾸벅~!
               
   comefeel   07-03-23 00:05  
JS는 제한적이지만  객체지향 개향 스크립트 언어라 알고 있습니다.

뭐 컴파일 언어랑 크게 다른 면은 없다고 생각이 드네요 ^-^

아차 딴지는 아닙니다.
               
   행복한고니   07-03-23 01:20  
객체...라는게 객체지향언어에만 있는건 아닙니다만...

아직까지는 자바스크립트가 객체지향언어가 아니라는 것에는 동의하지만, 객체가 연관배열로 구성되어있다는 말이나 객체지향언어가 아니라는 말은 이해가 안되는군요. 객체가 연관배열로 구성되어있고 그렇기 때문에 객체지향언어가 아니라는 건가요?

내부적으로 어떻게 구성이 되어있든 엄연히 자바스크립트에서 배열과 Object 는 다른 겁니다. 정확히 무슨 말씀을 하시는건지 이해가 안되는군요. 첫번째줄과 두번째줄의 의도를 모르겠습니다.
                    
   숨어지내리   07-03-23 17:11  
낭만백수님의 말이 맞습니다. ㅡㅡ;

var obj = new Object();
var obj= {};

는 엄연히 다릅니다. 똑같다고 보시는것은 무리가 있습니다.

var obj = {};
alert(obj === new Object());

-> false

ㅡㅡ;;
typeof 에만 object 만 나오는것이니깐요.  {} 은 연관배열형태로 구성됩니다.
                         
   행복한고니   07-03-23 17:43  
테스트를 하려면 제대로 하셔야죠.
alert(({} === {}));
alert((new Object === new Object));
alert(({} === new Object));

세개다 false 입니다. equality 하고 identity 하고 착각하신 것 같습니다.

그리고 Object 가 {} 으로 만들어진다는 말은 자바스크립트의 상위 스펙인 ECMA 표준문서에 있는 내용입니다.
                         
   행복한고니   07-03-23 17:49  
아... 하나더요.

Object.prototype.someFunc = function() { alert('hello~') };

({}).someFunc();
(new Object).someFunc();

실행해보면 알겠지만 Object에 prototype을 정의해둬도 {} 에서도 똑같이 사용할 수 있습니다. {}와 new Object는 같은 의미입니다.
                         
   숨어지내리   07-03-23 18:23  
// 행복한 고니

Object 와 배열은 다르다는걸 알고 계시네요. 헌데,
object 가 {} 으로 만들어진다는 것은 전혀 납득할수가 없습니다.

제가 예로 든 내용도 문제가 있을테이지만, 행복한 고니님의 예제도 썩 좋아보이지 않습니다.

Object.prototype.someFunc = function() { alert('hello~') };

({}).someFunc();
(new Object).someFunc();
(new Array).someFunc();

똑같이 나오는데,

허면, {} = new Object = new Array  가 되는것인지요?

제가 보는 관점은 Object - {}
                                  - Array

와 같이 상속처럼 구현되어져 있고 , {} 은 연관배열(배열의 형태는 필드명에 의한 문자열 인덱스 배열(associative array; 혹은 연상배열) 로 구성된다는 겁니다.

ECMA 표준문서에 나와 있다는데 제가 찾아봐도 그런내용은 없고,
{} 이게 상위라는 말은 전혀 납득이 되질않습니다.

ECMA 에 표기되어 있다하는데, 그부분을 명확히 보여주시어 중생을 가르쳐 주시기 바랍니다.
                         
   행복한고니   07-03-23 18:40  
Array 가 Object 를 상속받는 거라서 그렇게 나오긴 하는군요.
예를 든 것은 적절하지 않았던 것 같습니다.

이건 어때요?

alert(({}).constructor);
alert((new Object).constructor);
alert(([]).construcotr);
alert((new Array).construcotr);
 
그 어느 책에서도 "연관배열 타입"이라는 것을 가르치지 않습니다. 그렇게 보일뿐이라니까요. 대체 존재하지도 않는 타입을 있다고 생각하시는 이유가 뭔지 모르겠습니다. -_-;;

자바스크립트와 관련된 표준문서는 ECMA-262입니다.
11.1.5 절 보세요. Object Initialiser 입니다. 그 위에는 Array Initialiser 구요. PDF 로는 53페이지, 쪽번호를 기준으로 하면 41페이지군요.
PDF는 아래 주소에서 구할 수 있습니다.
http://www.ecma-international.org/publications/standards/Ecma-262.htm

MDC에 있는 Javascript 타입이니까 참고하세요.
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference
                         
   숨어지내리   07-03-23 19:11  
alert(({}).constructor);
alert((new Object).constructor);
alert(([]).construcotr);
alert((new Array).construcotr);

^^; 위와 같이 예제를 주었는데, array 와 당연히 다를것입니다.
아까도 말씀드렸듯이
 
Object - {}
          - Array

위와 같이 서로 다른 생성자를 생성하고 있고, {} 은 object 를 상속만 받았다고 보입니다.

그리고 당연히 type 에는 연관배열타입은 없습니다. ^^;
하지만, 연관배열이라고 지칭하는 표현이 있기 때문에 그렇게 말씀드린것입니다.

형(type)과 형태는 다른표현입니다. ^^;


더 자세한 예제는 아래 예제를 보는게 더 빠를것 같네요.

http://www.quirksmode.org/js/associative.html

보여주신 ECMA 에 대한 문서 내용은 object 처럼 사용할수 있다라는것이지,
{} 가 object 를 만들어진다는 말은 없네요. ㅡㅡ,. 어딘지 자세히 알려주세요..ㅠㅠ
                         
   MC_BirdShim   07-03-23 20:24  
숨어지내리님 말씀은
Obejct를 Array,{}가 상속받았다는 뜻인가요?.
[]는 Array를 상속 받은 것이구요?.
내용 뜻을 잘 이해를 못 하겠어서 여쭙는 거였구요.. ^^;;

잘 하지도 못하는 실력으로 나서는거 같아 송구스러운데..
개인적인 느낌으로는 {}는 완전히 Object와 같던데요?.

prototype.js에서 $()을 document.getElementById 처럼 사용할수 있다라고 하는 뉘앙스랑 비슷하게 느껴져서요..
                         
   낭망백수   07-03-23 20:48  
객체지향언어의 기본적인 특성을 자바스크립트는 갖추고 있지 않습니다.
이점은 정확히 아시리라 생각합니다.
그렇게 본다면,
객체가 연관배열보다 기반이 되어서 연관배열이 객체로 구현되었다고 보기보다는
반대로 객체(실제로 '객체지향'의 객체가 아니라 type 이 'object'일 뿐인)가
보편적인 개념의 type인 연관배열로 구현되어있다고 보는게 맞다는 것이
제 의견입니다.

최소한 Ajax in action 저자의 견해라면 충분히 권위있다고 생각하구요.
제가 공부하고 있는 시점에서 봐도 그렇다고 동의합니다.
굳이 자바스크립트를 객체지향언어(;oopl)로 분류한다고 하면
prototype-based oopl 로 분류를 할 수가 있는데
그마저도 정확히 prototype-based oopl 인 것은 아니라고 합니다.
prototype-based oopl 은 class-based oopl 보다 제가 훨씬 모르는 분야라서
더 이상 설명드리긴 어렵네요.

일단 견해로 받아들이시면 좋겠습니다.

어쨋든 자바스크립트가 제대로 된 객체를 표현하는 것이 아님은 인정하시리라
생각합니다.

꾸벅~!
                    
   행복한고니   07-03-23 20:48  
이해를 잘 못하셨나본데요...

{} 와 Object 가 같고,
[] 와 Array 가 같다는 의미입니다.
constructor 에서 어떤 내용이 출력되는지 보셨는지요?

저... 그리고 주신 페이지 제목만 딱 해석하면요...
"연관배열로서의 Object" 거든요? Object 지만, 연관배열처럼 사용할 수 있다라는 뜻입니다. -_-;;

ECMA 문서를 드렸는데도 없다고 하시니 답답합니다.
Object inialiser 라고 나와있지 않습니까? Object 를 생성할 때 쓴다는 건데요?

var obj = { aaa : "hello" , test : function(){ alert(this.aaa); } };

단순히 연관배열이라면 obj.test(); 를 했을 때, 어째서 그와 같은 결과가 나오는지 다시 한번 잘 생각해보십시오. 단순히 데이터를 저장하는 용도로 사용되는게 아니란 말입니다.

정말... 클래스도 구조체라고 하실 분들이군요.
                         
   낭망백수   07-03-23 21:04  
'연관배열로 구현되어있다'를 좀 과대해석하시는 느낌입니다.
연관배열이 객체로 구현되어 있다고 하는 것 보다는 보다 타당한 분석아닌가요?
(제대로 된 객체가 아니잖아요. ^^;)
서로 무지해서 그런건 아님은 인정하실테니 견해가 다른 걸로 하죠. ㅎㅎ
                         
   숨어지내리   07-03-23 21:47  
객체를 구조체로 말하는 짱구는 없을것으로 생각됩니다. ^^;

고니님 말씀이 틀렸다는게 아니라, 그렇게 보이는것입니다.

{} 는 분명 Object 를 implements 했을뿐이고, 그렇게 보이는것입니다.

아까 말했듯이 행복한 고니님이 말한

' Object 가 {} 으로 만들어진다는 말은 ' 이부분이 ECMA 에 어디에 있는지를

알려달라고 말씀드린것입니다. ^^;

물론 Array 또한 Object 를 implements 한것이고요..

alert 에서 구현이 Object 로 구현되었다고 해서 {} 이 Object 라고 표현하는것은
분명 다르다고 말씀드립니다.
                         
   행복한고니   07-03-23 22:54  
낭망백수 // 낭망백수님은 최초에 적었던 코멘트를 다시 보세요. "{}은 연관배열표현인데..." 라고 했습니다. 제 글과는 달리 {}는 다른 용도인 것처럼 볼 수도 있는 표현이었다고 생각합니다.
Ajax in Action 의 저자는 "자바스크립트에는 객체처럼 보이는 연관배열만이 존재한다"라는 입장이고요. 자바스크립트에 객체가 없다...라는 입장이라면 이 글에서 적합한 토론은 아닌 것 같고요, 둘 중에 한명은 오해가 있었다는 뜻이 되겠죠. 본문의 글은 {} 과 new Object 는 같은 의미다 라는게 제 글의 뜻이었으니까, 거기에 집중하시거나 다른 포럼을 열어주세요.
그게 아니라 {}은 Object와 다르고, {}은 연관배열이다라는 입장이라면 숨어지내리 님과 같은 입장이니 같이 얘기해보시죠.

그리고, 권위를 말씀하시는데, 권위를 따지자면 전 자바스크립트를 만든 Eich씨가 Object 라고 명명한 것을 더 신뢰하겠습니다. 권위자의 관점이라고 모두 옳다고 볼 수는 없다는게 이미 수십년의 역사가 증명해주는데(권위자들끼리도 잘 싸웁니다), 그 사람이 만든 것도 아닌 것을 가지고 권위를 들먹여서 근거를 댈 필요는 없을 것 같은데요?

숨어지내리 // Object initialiser 라니까요. -_-;;
Object 타입을 만들때 저렇게도 할 수 있다고 나와있다는 뜻입니다. initialiser 라는 뜻도 제가 알려드려야 하는 것은 아니잖습니까? 제가 알려드린 곳은 제대로 읽어보셨는지요?  바로 다음페이지 첫 머리에 {} 은 new Object 를 실행하고 결과를 리턴한다...라고 되어있습니다.

The production ObjectLiteral : { } is evaluated as follows:
1. Create a new object as if by the expression new Object().
2. Return Result(1).

제가 제 주장의 근거를 대었으니 {}가 Object 를 implement 했으며 {}와 Object는 서로 다른 것이다라는 근거를 들어주세요.
                         
   숨어지내리   07-03-24 04:55  
--------------------------------------------------------------------------------------------------
먼저 딴지라는 생각보단, 견해라고 생각하시고, 댓글을 보아주셨으면 합니다.^^
고니님의 견해와 실력은 인정하니깐요. ^^;
단지 제가 생각하는 내용에 대한 부분을 정리하면,


저렇게 만들수도 있다라는것에 대해 반론을 제기하는것이 아니라,
{} 와 new Object 는 다르다는 것입니다. (물론 결과적으로는 같습니다.

'new Object 를 실행하고 결과를 리턴한다...라고 되어있습니다. ' 라고 하셨는데,
영어를 해석하면

1. new Object() 객체에 의한것처럼 새로운 객체를 생성한다.
2. Result(1) 을 반환한다.

라고 해석되는것 같은데요. ? ^^;
저게 어떻게 실행해서 결과를 리턴한다라고 해석이 되는지요? ㅡㅡ;
이해할수가 없군요.

또한 제가 문의 드렸던 고니님께서 말씀하신

'그리고 Object 가 {} 으로 만들어진다는 말은 자바스크립트의 상위 스펙인 ECMA 표준문서에 있는 내용입니다. '

위의 부분이 도대체 어떤부분에 대해 해석을 하셨기에 답변을 하셨는지
여쭤보았는데, 엉뚱하게도, 그부분은 알려주시지를 않고 있군요.
만들어진다라는 표현에 대해 말씀을 드리는것입니다.


이런 비슷한 내용으로 토론을 한 내용을 링크로 보여드리면,

http://www.thescripts.com/forum/thread459033.html

위의 주소이며,

내용은 여러가지 이겠으나, 위의 주소를 잘 찾아보시면

The objects created by Object literals inherit directly from
the core Object object, not from the core Array object. They inherit
indirectly from the Object object, though, through the prototype chain

위와 같이 말하는 내용들을 보실수 있을것입니다.
'Core Object 의 object 로 부터 직접적으로 literals 에 의해 상속되어진것입니다.'

물론 공인된 문서가 아니라고 말할수 있으나, 이렇게 구현되어져 있기 때문에
행복한 고니님이 테스트 하는 결과가 나오는 것입니다.

그래서

"
Object.prototype.someFunc = function() { alert('hello~') };

({}).someFunc();
(new Object).someFunc();
(new Array).someFunc();

똑같이 나오는데,

허면, {} = new Object = new Array  가 되는것인지요?

"

와 같이 이러한 결과가 나오는것이고요..ㅡㅡ;

그러니... ECMA 문서에 표기된 내용만 알려주시면 됩니다. ^^;
그러면, 제가 생각하는 내용이 틀린게 되는것이니깐요. ^^ㅎㅎ
                         
   행복한고니   07-03-24 10:55  
숨어지내리 // 저 죄송한데요... literal 이라는 단어를 모르실 분은 아니라고 보는데요?

{} 과 new Object 가 다르다는 말은,
[] 과 new Array 가 다르며,
""과 new String 이 다르다는 말과 같겠군요.
/표현/과 new RegExp 가 다르다는 말도 될 것 같습니다.
1과 new Number(1)은 다른 것이라는 의미도 되겠네요.

literal 이라는 단어가 그 문서에서 어떤 용도로 쓰였는지(사실 모든 언어 스펙에서 같은 의미이지만), 한번 잘 살펴보세요. 정말로 1 과 new Number(1)이 다른 걸까요? literal 의 의미도 제가 설명해드려야 하나요? {}은 Object literal 이다 라는 말로 이해하실거라고 생각하고 말씀드렸었는데, 아닌가보군요.

근거로 들었던 것은 누군지도 모르는 어떤 사람의 견해일 뿐이잖습니까? 어째서 그게 주장의 근거가 되는지 모르겠군요. new Object 와 {} 가 다른 점을 한번 설명해주세요. 뭐가 다른가요? 어떠한 주장의 근거도 가지고 있지 못하면서 계속 "주장"만 고집하시는군요.

{} 이게 new Object 를 실행한 것과 같은 결과를 리턴한다는데, 그 이상의 다른 말이 필요한지도 모르겠습니다. 그 어떤 문서에서도 {}과 new Object의 차이점을 본 적이 없는데, 무슨 상속을 왜 받은건가요? 표준 문서 어디에 상속이라는 내용이 나와있는지, Object literal 이라는 말이 다르게 해석될 수 있는 이유와 new Object 를 실행한 것과 같은 결과가 어떻게 중간에 상속이 되었다는 뜻으로 해석될 수 있는지와 같은 주장의 근거를 들어주세요.

다시 한번 더 근거도 없이 주장만 하신다면 그냥 그렇게 생각하고 계시라는 말밖에는 드릴 말씀이 없습니다. "{} 은 new Object와 같다" 이런 문장이 없으면 전혀 수긍하지 않으실 분이니까요.

P.S// 이왕이면 constructor 가 같은 이유도 좀 들어주세요? 그 코드는 제가 적절하지 않았다고 인정했던 코드인데요?

P.S2// 생성자가 같으면서도 서로 다른 자료형일 수 있는 예를 하나 들어주시기 바랍니다. 어느 언어라도 상관없습니다.
                         
   낭망백수   07-03-24 13:59  
행복한고니 // ^^; 그냥 웃어 넘기겠습니다. 꾸벅~!
                         
   숨어지내리   07-03-24 14:00  
// 행복한 고니

참 희한하군요.

제가 원한건 ECMA 에 대한 부분을 계속 요구하는데도 말씀이없고,
참 이상한 의견만 내놓는 군요. ^^; ㅎ

{} 와 new Object 는 inherit 되었으니, 당연히 같은 결과가 나오는데,
엄밀히 따지면 다르니, 결과가 같다고 똑같다고 표현하시는것 자체에 무리가 있다라는 것이고, 영어 해석에 대해 너무 편하신대로 해석하시는것은 아닌지
의문이 드네요..^^;

inherit 에 대해서 다시한번 고민해 보셔야 할듯 합니다. 왜 construct 가 같은지..
{} 가  object 를 inherit 했는지는 아래에 코드를 실행해 보시고요.

alert(({}));
alert(Object);

Object 는 core Object 입니다. {} 는 object object 가 되어있을것입니다.ㅡㅡ;
즉 Object 와 {} 는 엄밀히 따지자면 다르다는것입니다.

자꾸 자기주장을 굽히지 않으면서 결과가 같다하여, 자기주장만이 옳고
책에 나와있지 않으니, 수긍할수 없다하니. 참으로다가 고집이 장난이 아닙니다.

자 이제, 이제 제가 보여드린 코드가 상속인지, 정말 object 와 같은지 보여드린것이니,
제가 문의한 고니님이 ECMA 문서에 표기된 Object가 {} 에 의해 만들어진다라는 표현을 알려주시고, 있다 없다 제대로 된 의사전달 해주시고,

있다면, 도대체 ECMA 문서의 몇번째라인부터인지 자세히 알려주십시요.

자신의 편의대로 생각대로 해석한것인지 아니면, 정말 문법에 맞게 해석한것인지가 나올꺼 같네요.

문서에 없더라도 브라우저의 System 상에서 구현이 되어 나오는사항을 가지고 그렇게 우기시는건 도대체 어디서 배운것인지 알다가도 모를일입니다.

ps. 남을 깔아뭉개는 것만이 이기는게 아니라, 모르는것은 같이 배우는게
현명한 판단입니다. 잘못된 견해가 다른분들에게는 정설로 받아들여질수 있으니깐요.

ps2. "생성자가 같으면서도 서로 다른 자료형일 수 있는 예를 하나 들어주시기 바랍니다"
위와 같이 형(type)이 다르다고 하진 않았습니다. ^^; ㅎㅎ 다만, 생성자가 같은 이유는 {} 이  inherit 되었기 때문이다. 라는 것이고요.
                         
   낭망백수   07-03-24 14:44  
숨어지내리 //
근데 제 말에 동의하시는 듯 하시더니, 또 약간은 다르시군요. ^^;

그리고,

행복한고니 //
"Object 가 {} 으로 만들어진다는 말은 자바스크립트의 상위 스펙인 ECMA 표준문서에 있는 내용입니다."
라고 말씀하셨습니다.

'Object 가 {} 으로 만들어진다'가 제가  정작 드리려는 말씀이었습니다.
(물론 {} 로 연관배열이 만들어진다는 것도 동의하시리라 생각합니다.)

꾸벅~!
                         
   숨어지내리   07-03-24 15:01  
낭만백수 //

ㅋㅋ ^^; 제가 먼저 고니님께 물어봤습니다.~~ 차례를 지켜주세요~ ㅎ
                         
   행복한고니   07-03-24 15:01  
숨어지내리//

저기 말이죠... 제 글의 본문을 제대로 읽으셨나요?
Object는 {}으로 생성할 수 있다는 글이요? 읽으셨나요?
{}는 Object와 같은게 아니라 new Object와 같은건데요?

님이 처음에 쓴 글을 보시죠.
______________
var obj = new Object();
var obj= {};

는 엄연히 다릅니다. 똑같다고 보시는것은 무리가 있습니다.
______________
라고 했습니다. 그리고 두 가지가 다르다는 것을 보이기 위해서 다음과 같은 예제도 작성하셨죠.
______________
var obj = {};
alert(obj === new Object());

-> false
______________

그런데, 이제와서 왜 갑자기 {} 와 Object를 비교하세요? 말을 번복하시는게 아니라면 일관성있게 주장해주세요. 저는 new Object와 {}가 같다는 입장이었으니까요. 누가 클래스와 인스턴스가 같다고 주장한답니까? Object 의 type은 function 이거든요?

다시 한번 정리해드리자면, {}로 Object의 인스턴스를 생성할 수 있고, 이것은 new Object 와 같다는 것이 제 입장입니다. 본문에도 그렇게 썼구요. 하지만 님의 의견은 제 입장과는 분명히 달랐었죠.
______________
Object - {}
          - Array
______________
이것처럼 {}가 마치 Object와는 별개의 타입(연관배열이라고 하셨죠?)으로 구성된 것으로 말씀하셨었습니다.

저는 제 주장에 대한 근거로 두가지 방법으로 생성한 객체들의 constructor 가 같다고도 했습니다. ECMA에도 Object 타입의 initializer로 {}가 사용될 수 있다고 써있다고도 알려드렸습니다. 님의 주장이 받아들여지려면 비슷한 의미로 Array initializer 인 [] 은 Array 타입과는 또 다른 타입이어야 맞는 말이 되는 겁니다.

저는 분명 제 주장에 대한 근거를 들었습니다. 거기에 대해서 "Object는 {}로 생성한다"라는 밥을 떠먹여주기를 바라는 문장을 찾으신건지, 인정을 하시려고 안하더군요. 고집인건지 정말 이해를 못하신건지 모르겠지만, 그래서 링크 하나 더 드려보죠.
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object
자바스크립트 1.2 부터 객체의 literal 이 생겨서 new Object는 {}로도 생성할 수 있다고 주석에 나와있습니다.

그런데, {}은 연관배열이고 new Object와는 다르다는 주장의 근거를 못본 것 같네요. System상에서 그렇게 구현이 되어있다는데, 단 한번도 근거를 들어준 적이 없습니다. 제발 주장의 근거를 들어주세요. 엉뚱하게 Object와 {}를 비교하지는 마시고요. 제 주장은 처음부터 지금까지 똑같으니까요.
_______________________
자꾸 자기주장을 굽히지 않으면서 결과가 같다하여, 자기주장만이 옳고
책에 나와있지 않으니, 수긍할수 없다하니. 참으로다가 고집이 장난이 아닙니다.
_______________________
"결과가 같다하여" 이 부분만 "근거도 없는데" 라고만 바꾸면 제가 딱 님에게 해드리고 싶은 말이네요. 책은 이미 ECMA 표준문서를 예로 들었습니다. initializer 의 단어 의미를 몰라서라면 이해할 수도 있습니다. 단어의 뜻을 모르신다면 제가 다시 설명드리겠습니다. 단어자체를 몰라도 구글에서 조금만 찾아봐도 어떤 의미로 사용되는지 아실텐데, 검색은 잘 안하시나보네요.

P.S// 고집만 피운다고 토론이 되는게 아닙니다. 주장이 되려면 근거가 있어야죠.
P.S2// 모르는건 같이 배우는게 현명하지만, 이번 경우엔 제가 일방적으로 당연한 걸 설명하는 입장이라고 생각하고 있습니다.
                         
   행복한고니   07-03-24 15:04  
낭망백수 //
어떤 입장이신가요?
1. Ajax in Action 의 저자처럼 Javascript 엔 객체가 없다.
2. new Object 와 {}은 다른 것이고, {}은 연관배열이다.

제가 예시로 든게 적절하지 않다면 먼저 간단하게 요약부터 해주세요.
제 입장은 "new Object 와 {}은 같은 결과를 도출하고, 둘 다 Object의 인스턴스이다" 입니다.

그 뒤에 다시 토론하죠.
                         
   낭망백수   07-03-24 15:22  
행복한 고니 //
예시에 대해선 전혀 언급할 필요가 없지않나요?
님의 '객체가 {}로 만들어진다'를
저는 '{}로 객체가 표현된다'라고 말하고 있는 중이고,
결론적으로 이견이 아니라고 말씀드린게 제 마지막 커멘트입니다.
유일하게 다른 부분은...
저는 '{}'가 '연관배열표현'이라고 말씀드린 것입니다.
저또한 객체를 생성할때 JSON 및 다른 JS프레임웍과 혼용하기 위해
'{}' 를 즐겨쓰고 있습니다.
(이부분에서 배열로 이해하는 것이 상당히 효과적입니다. 개인적으로... ^^)
실용론에 있어서는 다르지 않다는 뜻이지요.
다만 그 내면을 어떻게 보는가 하는 관점의 문제일 뿐입니다.

이만하면 된 것 아닐까요? ^^;

꾸벅~!

ps; 객체가 연관배열이라고 볼 수 있는 근거는 '행복한고니'님 본문의
프라퍼티 접근 예제입니다. 두줄만 발췌하죠.

var obj = { "prop1" : "value1", "prop2" : "value2" };
alert( obj["prop1"] );
                         
   행복한고니   07-03-24 15:32  
낭망백수 // 저는 {}는 Object 이고 그냥 연관배열 처럼 보일뿐이라는 입장이라 {}가 연관배열 표현이라는 것에 동의를 못하고 있는겁니다. {}를 연관배열로 보시려면 new Object 로 생성된 것도 연관배열로 보셔야 합니다.
그냥 연관배열처럼 보일 뿐이고 두 가지는 같은 표현이며, Object 라는 것이 저의 주장입니다. 그래서 정확한 입장을 물어본겁니다.

1번이신가요, 2번이신가요? 아니면 다른 의견이신가요?

P.S//
var obj = new Object;
obj["toString"] <- 이런 것도 됩니다. 따라서 객체로 보건, 연관배열로 보건 같이 봐야한다는 거죠.
                         
   숨어지내리   07-03-24 15:41  
// 행복한 고니

참..ㅡㅡ; 그새 또 말과 주장이 바뀌어 버리셨네..ㅋ
이제 증명했더니 {} 가 object 의 instance 네요.. ㅋ

" Object가 {} 에 의해 만들어진다 " 라고 까지 하셨는데.. ㅡㅡ;


///////////////////////////////////////////////////////////////////////
var obj = new Object();
var obj= {};

는 엄연히 다릅니다. 똑같다고 보시는것은 무리가 있습니다.
______________
라고 했습니다. 그리고 두 가지가 다르다는 것을 보이기 위해서 다음과 같은 예제도 작성하셨죠.
______________
var obj = {};
alert(obj === new Object());

-> false
______________

그런데, 이제와서 왜 갑자기 {} 와 Object를 비교하세요? 말을 번복하시는게 아니라면 일관성있게 주장해주세요. 저는 new Object와 {}가 같다는 입장이었으니까요. 누가 클래스와 인스턴스가 같다고 주장한답니까? Object 의 type은 function 이거든요?
///////////////////////////////////////////////////////////////////////////////////////

제가 말씀드리고 싶은 부분입니다..
주장의 일관성 있는 부분 부탁드립니다. ㅡㅡ;

"{} 와 Object 가 같고,
[] 와 Array 가 같다는 의미입니다. "

이게 고니님의 주장이었습니다.
전 Object 와 같을수밖에 없는이유는 inherit 되었기 때문이다. 라고 말한거고요.
헌데 다시 instance 라고 말바꾸시는건 고니님인데요.. ㅡㅡ;


그리고

"제가 예로 든 내용도 문제가 있을테이지만, 행복한 고니님의 예제도 썩 좋아보이지 않습니다."

와 같이 말씀을 드려 문제가 있음을 말씀드렸는데도.. 그부분은 생략이시네요.ㅎ



///////////////////////////
"{} 이게 new Object 를 실행한 것과 같은 결과를 리턴한다는데, 그 이상의 다른 말이 필요한지도 모르겠습니다. 그 어떤 문서에서도 {}과 new Object의 차이점을 본 적이 없는데, 무슨 상속을 왜 받은건가요? 표준 문서 어디에 상속이라는 내용이 나와있는지, Object literal 이라는 말이 다르게 해석될 수 있는 이유와 new Object 를 실행한 것과 같은 결과가 어떻게 중간에 상속이 되었다는 뜻으로 해석될 수 있는지와 같은 주장의 근거를 들어주세요"

" 제 입장은 "new Object 와 {}은 같은 결과를 도출하고, 둘 다 Object의 인스턴스이다" 입니다.  "
//////////////////////////

아깐 위와 같이 상속된 부분을 증명해 보라더니.. ㅡㅡ;

제가 상속된 부분을 증명하기 위해서 비교를 한것이고요.

alert(({}));
alert(Object);


결국 위와 같이 상속된것을 증명했더니,
인스턴스이다라고 하신건가요? 그렇게 왔다갔다 하는건가요? .. 참... 깝깝합니다...

"Object가 {} 에 의해 만들어진다" 라고 했는데..
이젠 {} 는 Object 의 인스턴스이다? 참.. 깝깝합니다.



///////////////////////////////////////////////////////////////////////////
다시 한번 정리해드리자면, {}로 Object의 인스턴스를 생성할 수 있고, 이것은 new Object 와 같다는 것이 제 입장입니다. 본문에도 그렇게 썼구요. 하지만 님의 의견은 제 입장과는 분명히 달랐었죠.
______________
Object - {}
          - Array
______________
이것처럼 {}가 마치 Object와는 별개의 타입(연관배열이라고 하셨죠?)으로 구성된 것으로 말씀하셨었습니다.
/////////////////////////////////////////////////////////////////////////////

고니님의 주장은 인스턴스가 아니었습니다. 왜 상속얘기가 나오는지
도무지 이해할수 없다고 까지 하셨습니다.

그리고 제가 object 와는 별개의 타입이라고 한적은 없는것 같은데요.
연관배열형태라고 했지요.. ㅡㅡ;
형태(form)와 형(type)을 구분짓지 못하시군요.. ㅡㅡ;

주장을 바꾸시니, 참 토론이 무색하네요.


" 자 이제, 이제 제가 보여드린 코드가 상속인지, 정말 object 와 같은지 보여드린것이니,
제가 문의한 고니님이 ECMA 문서에 표기된 Object가 {} 에 의해 만들어진다라는 표현을 알려주시고, 있다 없다 제대로 된 의사전달 해주시고,
있다면, 도대체 ECMA 문서의 몇번째라인부터인지 자세히 알려주십시요. "

이거나 알려주세요..ㅡㅡ;
                         
   행복한고니   07-03-24 15:48  
숨어지내리 //
제 글 본문 보시라니까요.
제가 단 한번 오해가 있을만한 표현을 썼던 것은 인정하겠습니다.
______________________
{} 와 Object 가 같고,
[] 와 Array 가 같다는 의미입니다.
______________________
그럼 다른 글은 어때요? 다른 모든 글에서는 {}를 new Object 와 비교하고 있었는데요? 본문의 글도 Object 를 생성할 때라고 했습니다. 비록 제 표현에 문제가 있었을지라도 []과 같이 사용했기때문에 의미 정도는 파악했다고 생각했는데, 말꼬리를 잡자는 것도 아니고... 원...

new Object와 {} 가 다르다면서요? 근데 이제 제가 말을 바꿨다고 하시는군요. ㅎㅎ 제가 처음에 썼던 표현이나 보세요. 낭망백수님의 글에 달았던 코멘트입니다.
______________________
배열 비슷하게 표현된다고 해서 그게 배열인 것은 아닙니다. 연관배열처럼 보이는 Object type 입니다.

var obj = new Object; 이 표현이나
var obj = {}; 이것은 똑같은 표현입니다.
______________________
이래도 제가 말을 바꾼 건가요? 오해가 있을만한 글귀가 있었다고 말 꼬투리를 잡는 걸로 밖에 안보이네요. ㅎㅎ

표준문서에서 new Object 를 실행한 것과 같은 결과라는데 대체 어쩌다가 그게 내부적으로 상속된다라고 생각하셨을까요? 아니, 그 전에 말 바꾸는 것을 보니 이미 자신의 주장이 잘못된다는 사실을 아시는 것 같습니다.

더 이상은 말을 섞지 않아도 되겠군요. 쌩뚱맞게 클래스하고 인스턴스하고 비교해놓고 "내말이 맞지" 이러지 마시고요, 단 한번이라도 제대로 된 근거좀 가져오세요. ECMA를 못 믿겠다면 생성자가 같다는 사실은 어떻고 MDC에 있는 문서는 또 어때요?

제가 들었던 근거를 내버려두고서라도 코드상에서 모든 결과가 같다고 말하고 있는데, 혼자서만 다르다고 말하고 계시거든요? 그렇다면 다르다는 증거를 대는게 이치상 맞는 것 아닌지 생각해보게 되는군요.

아.. 그것도 이제는 애초에 했던 말을 바꾸셔서 클래스하고  인스턴스하고 다르다고 주장하고 계시더랬죠. 그 말은 맞습니다. 클래스하고 인스턴스하고 같다고 생각하는 사람이 어딨겠습니까. ㅎㅎ
                         
   숨어지내리   07-03-24 16:37  
^^; 참 알다가도 모르겠습니다.

" Object가 {} 에 의해 만들어진다 " 라고 까지 하셨는데.. ㅡㅡ;
이렇게 까지 말씀하신 분이

말꼬리를 잡는다니.. ㅡㅡ; 누가 누구의 말꼬리를 잡는지 모르겠습니다.

표현이 똑같을지 모르지만, 내부적으로 다를수 있으니
똑같다고 말할수는 없을거 같다라는 의견을 내드렸는데,..


"그리고 Object 가 {} 으로 만들어진다는 말은 자바스크립트의 상위 스펙인 ECMA 표준문서에 있는 내용입니다. "

위와 같이 해박한 지식으로  말씀하시어 ECMA부분을 찾아봐도 이부분을 찾을수 없어, 어디부분인지 알려달라 했습니다. ㅡㅡ;
Object 가 {} 에 의해 만들어진다는 말에 동의할수가 없었기 때문입니다.

initializer 라는것은 알고 있습니다.. 헌데 Object 라는 놈이 {} 에 의해 만들어진다라는게 문서상에 있나해서 여쭙다가, 상속이 되어진것이라 생각한것이고,

그부분을 증명해달라 해서 증명해드렸더니. instance 다 라고 정리하시니..

더이상 할말이 없네요 ^^;

그리고 제가 말씀드린 부분은 ECMA 문서에 없나봅니다?
답변이 없으신걸로 봐서는요..ㅡㅡ;

ㅎㅎ 암튼.. 재미있는 토론이었습니다. ㅋ
                         
   행복한고니   07-03-24 16:57  
숨어지내리 //
표현에 오해가 있을 수도 있음을 인정했는데도, 똑같은 것 밖에 물고늘어질게 없나보네요? 최초에 제가 했던 말과 최초에 님께서 했던 말을 잘 보세요 전 계속 그것에 관한 토론을 하고 있다고 생각했는데, 중간에 몇몇 부분에 제 표현에 오해가 있었다고 해서 최초의 주장이 사라져버리는건가요?

ECMA에 왜 없다고 자꾸 물어보는지 알겠군요. Object 클래스 자체로 이해하고 있었군요. Object 가 생성된다는 의미를 저는 Object 객체가 생성된다라고 사용해왔고 코드를 통해 설명할 때는 분명 new Object 를 사용했었으며, 처음부터 지금까지 계속 같은 말만 하고 있습니다. 비록 표현에 오해가 있을 수 있다해도 말이죠.

그러니 그 부분을 자꾸 요구했던 것이로군요. 당연히 없을 수 밖에요. Object 는 이미 내장객체인데 그게 어떻게 {}으로 생성될 수 있겠습니까? 제 본문의 글을 본 사람중에 Object 타입 자체를 만들어낸다고 해석하신 분은 님밖에 없을 겁니다.

제가 작성한 코드 중 오해가 없을만한 코드 부분은 쏙 빼놓고, 적절하지 않았다고 했던 코드만을 예로 들고, 최초에 썼던 제 글에 대해서는 언급조차 안하고, 자신이 "연관배열이다"라고 말했던 부분은 어느새 온데간데 없고, 제 글을 보고나서 님께서 예로 든 코드에도 {} === new Object 가 있습니다. 이미 제 주장을 충분히 이해했다는 뜻인데도, 이제 와서 제 주장이 마치 달라졌다는 것처럼 말을 하는군요.

중간에 MC_BirdShim 님의 말씀도 저와 같은 말입니다.
____________________
개인적인 느낌으로는 {}는 완전히 Object와 같던데요?.
____________________
이 말이 설마 Object 라는 내장 객체 타입과 {}이 같다는 뜻이겠습니까? Object의 인스턴스가 {}와 같다는 의미죠.

단 한번도 자신의 주장은 근거조차 대지 못해놓고 이제와서 제 말에 오해가 있을만한 부분이 있으니 딱 걸렸다라고 생각하셨나보죠? 아니면 처음에는 이해했는데 갑자기 제 주장을 잘못 받아들이게 됐거나요.

토론은 커녕 시간낭비만 했군요.
연관배열에 대해서는 단 한번도 말씀하지 않더군요. ㅎㅎ 처음에 주장했던 연관배열은 어떻게 된건가요? ㅎㅎ

재밌네요. 어거지도 이만하면 상줄만 합니다. 쇼펜하우어의 논쟁에서 이기는 법을 마스터하셨군요. 이미 잘 알고 계시겠지만 링크걸어둡니다.
http://jjowker.egloos.com/457219
                         
   maggot   07-03-24 17:21  
뭐... 다 끝나가는 토론에 다시 불을 지피자는 건 아닙니다만,
제가 보기에도 Object() 와 {} 는 같은 표현같네요
링크거신 ecma spec 에도
{propertyName and Value} 는 Object() 로 object 인스턴스 생성하고
{ 과 } 사이의 표현식을 해석해서 기생성된 object 인스턴스에 적용후
반환 하는 것으로 이해되구요

alert(({}))
alert(Object)
로 비교할게 아니라

alert(({}))
alert(Object())
로 비교해야 맞다고 보여집니다
                         
   숨어지내리   07-03-24 17:43  
참 재미있는 히스토리입니다. ^^ ㅎㅎ

제가 예제를 잘못한것처럼 고니님도 예제를 잘못들어 놓으시고,
ECMA 에 대한내용을 말씀하시니 Object 로 이해 되지 않을까요? ^^

저만 그래서, 낭만백수님도 이러한 질문을 올린것일까요?

'Object 가 {} 으로 만들어진다'가 제가  정작 드리려는 말씀이었습니다.
(물론 {} 로 연관배열이 만들어진다는 것도 동의하시리라 생각합니다.)


상속문제를 들먹이시더니, 이제는 제가 무지해서 앞뒤를 잘못해석한거였군요.^^

말씀하신 주소는 고니님도 만만찮게 속하는 것 같습니다. ^^ㅎ
                         
   comefeel   07-03-24 18:05  
maggot 님

끼지말아주세여 ;
여기서 마물 ㅤㄷㅙㅅ으면 합니다.
   아리프리   07-03-22 13:17  
호오 잘 보았습니다...감사드립니다.
   드렁큰수달스   07-03-22 14:08  
감사합니다 좋은 정보 얻어 갑니다.
   전진하는아르고   07-03-22 15:40  
고니님 잘봤습니다. ^^
얼마전 JSON 표기법을 공부하면서 JS 의 이상한 표현법을 보고 신기하다라고 생각했는데..
이거 보니 새록새록하네요.. ㅎㅎ
   時建方進   07-03-22 17:06  
잘봤슴당~감사요~
   TP™ 아쿠아   07-03-23 23:11  
열띤 토론듯.
     
   행복한고니   07-03-24 16:58  
토론이 아니었습니다 -_-;;
          
   숨어지내리   07-03-25 17:12  
맞습니다.. ^^ 쇼팬하우어의 논쟁이었습니다. 고니님 말대로 상받으셔야 할듯합니다.

http://jjowker.egloos.com/457219
   행복한고니   07-03-24 18:11  
숨어지내리 //
{} === new Object 이런 예제를 들었을 때부터 이미 제 주장을 이해해놓고서는 이제와서 말꼬리라니...

제 주장을 지금 말꼬리 잡는 식으로 이해했다면 이렇게 예제를 드셨겠죠.
{} === Object

그 바로 아래쪽에서 적절하지 않다는 말은 제가 비교를 하려면 똑바로 하라며 비교대상이 될만한 예제를 들어준 것에 대해서 말씀하신게 아니던가요? 그 예제에서 제가 {} === Object 라고 하던가요?

제가 최초에 적었던 코멘트와 님께서 최초에 적었던 코멘트를 대비시켜드리죠. 처음이 제 것이고 그 다음이 님의 것입니다. 이 주장에 대해서는 적절하지 않거나 잘못되었다고 시인한 적이 단 한번도 없었죠.
------------------------------------------
var obj = new Object; 이 표현이나
var obj = {}; 이것은 똑같은 표현입니다.
------------------------------------------
var obj = new Object();
var obj= {};

는 엄연히 다릅니다. 똑같다고 보시는것은 무리가 있습니다.
------------------------------------------

저는 계속 이 두가지의 상반된 주장을 가지고 말하고 있다고 생각했는데, 이제와서 말꼬리군요.
인정할 건 인정하는게 자존심을 지키는 겁니다.

중간에 제가 오해할만한 표현이 있었다는 것은 인정하겠지만, 항상 제 의도는
var obj = new Object; 와 var obj = {}; 이것은 똑같은 표현이라는 것이었습니다. 두가지가 다르다는 주장을 할 게 아니라면 이쯤에서 그만 두십시오. 애쓰는 모습이 안쓰럽습니다.
   그네   07-03-24 21:42  
재밌게 읽었습니다.
전 자바스크립트에 대해 거의 모릅니다.

대충 글을 읽어보고 개인적으로 정리해보니 이런거 같습니다.


Object !== new object
Object !== {}

new object === {}

new object 도 {} 도 instance 이니까요
{} 이 수행될때 상속을 하던 어땠건 간에 new object 동작을 하니깐요..

라고요..


그리고...
언어(대화형 언어) 선정에 조금은 신경을 쓰시는게 좋을거 같습니다.
이런 토론은 정말 필요하다고 생각이 듭니다만.. 표현방법에 문제가 조금 있지 않나...여겨집니다.
   낭망백수   07-03-25 00:32  
행복한고니 //
누구나 다 똑같이 말하고 똑같은 매너로 대할 수는 없습니다.
좀 덜할 수는 있지만, 그렇다고 당신의 매너가 어떻다는 판단까지
이 자릴 통해 말씀하실 필요는 없어보입니다.
'그만두십시오, 안쓰럽습니다' 는 좀 심하셨습니다.
꾸벅~!
   간만이야   07-03-25 06:52  
내가봐도 고니님 말씀이 좀 지나치신듯...  이런 좋은 정보에 이런 말다툼이라니 고수님들 좋은 모습을 보여주세요~
   숨어지내리   07-03-25 12:01  
^^; 안남기려고 했는데.. ㅎㅎ

다시 한번 제 입장에서 이해한 내용을 말씀 드리겠습니다.

new Object() 와 {} 의 쓰임은 같겠지만, 내부적으로 다를수 있고, {} 의 쓰임이 연관배열로 많이들 표현하고, ECMA 문서에는 {} 은 new Object() 처럼 만들어진다고 있습니다.

제가 표현하려는 예제가 틀렸고, 마찬가지로 고니님의 예제도 틀린상태에서

해당부분에 대해 Object 가 {} 으로 만들어진다는내용은 없는데, 그렇게 말씀하셔서,
어느부분인지, 제가 알고 있기로는 상속의 개념에서 생각하고 있어서, 관련사항에 대해
그렇게 설명해 드렸습니다.  또한 {} 와 Object 는 같다라고 까지 하셨습니다...

"MC_BirdShim  07-03-23 20:24 
숨어지내리님 말씀은
Obejct를 Array,{}가 상속받았다는 뜻인가요?.
[]는 Array를 상속 받은 것이구요?.
내용 뜻을 잘 이해를 못 하겠어서 여쭙는 거였구요.. ^^;; 
"

그래서 MC_BirdShim 님도 이렇게 이해하셨겠지요.

헌데, 내용에 대해 계속적인 반박으로 상속을 증명해 보라해서

답글을 남기게 된거고,

Object 와 new Object() 를 이해를 잘못하고 계신게 아닌지 생각하고 있었습니다.

말씀하신 사항에 {} 가 Object의 인스턴스라고 하니,

문백을 보고 표현은 알아서 이해해야 되지 않는냐는 말씀에 다소 당황스러웠습니다. ^^;;;

그럼. "내가 JAVA 라고 얘기하는것에 대해 문맥을 보고 JAVASCRIPT 로 이해해야 되는게 아니냐? "

라는 말과 비슷한거라 보여서 입니다.

저만 Object 로 이해한건지.. 그래서 나중에는 new Object() 로 되어버린것인지..

인격을 모독하는 부분에 대해서는 따로 언급하지는 않겠습니다. 다 자신이 쌓은 덕이니깐요.

일단, 제가 생각한 내용도 올려드린것이니

제가 잘못된 판단을 하여, 이렇게 긴 토론을 하게 되었다면 죄송한 말씀 올립니다. ^^

전 올바르지 못한 내용으로 많은분들이 그게 정석이라 생각할까봐 그리 말씀드린것입니다. ^^
     
   행복한고니   07-03-25 14:10  
답글 달까 말까 고민했는데, 아무래도 다는게 좋겠네요.
제가 인격수양이 덜되서 표현을 거칠고 생각없이 했던 것은 인정하며, 사과드립니다.

그리고 이 글은 별개의 문제로,
--------------------------------------------------------------
분명, 중간에 오해할만한 표현이 있었다고 말씀드렸습니다.
제 생각에 올바르지 못한 내용은 "{}은 연관배열이고 new Object 와는 다른 표현이다" 라고 하는 것입니다. 똑같은 의도로 잘 모르시는 분들이 봤을때 정말 다른 것이라고 생각할까봐 그리 장문의 글을 썼었죠.

제 글에 오해할만한 문장이 있었던 것은 인정하지만, 오해할만한 코드가 있었다고는 생각하지 않습니다. 제 글중 Object 라고만 표현한 많은 부분은 정확하게는 "Object 타입의 인스턴스"라고 표현해야 맞는 것도 사실입니다. 배열 객체를 생성할 때 배열을 만든다라고 하지, "배열타입의 인스턴스를 만든다"라고 표현하지 않는 것과 비슷한 정도로 생각했었습니다. 그리고, 충분히 이해하셨으며 그래서 진행중이라고 생각한거죠. 코드를 충분히 이해했다면 알만한 제 글이 오해를 받고 있다고는 미처 생각하지 못했습니다.

님께서 사용하신 표현, 상속. 상속이라고 하면, 흔히 타입간의 계층을 생각하게 마련입니다. 그래서, 상속이라는 표현이 마치 {}을 하나의 타입으로 보는 것처럼 보였으며, 님께서 썼던 최초의 코멘트를 생각할 때 충분히 그렇게 주장하고 있다고 생각할만 했습니다. MC_BirdShim 님의 말은 그런 겁니다. Array 가 타입인지 알고 있는데, {}과 Array가 Object 에서 상속받았다고 표현하셨으니까요. 그런데, 나중에 보면 인스턴스가 타입을 계승한 것도 상속이라고 표현하시는 것 같더군요. Array와 같이 {}를 두고 있음으로써, 마치 {}가 타입처럼 보이게 했다고 생각합니다.

다시한번 말씀드리지만, 저는 각자의 최초의 코멘트대로 {} 과 new Object 가 다른지/같은지에 대해서 계속 토론중이라고 생각했었습니다. 저의 처음 주장을 충분히 이해하시지 않았습니까? 그런데도 어째서 제가 갑자기 "Object 타입 자체를 {}로 만들 수 있다"고 했을 때, 짚고 넘어가지 않으셨는지 모르겠습니다.

어쨌거나 상관없습니다. 길고 긴 글들이 무의미하다는 것을 알았으니, 다시 처음의 논점으로 돌아가면 되니까요. 여전히 최초의 주장은 한번도 증명하지 못하셨음도 상기해주시기 바랍니다. 많은 분들이 잘못 생각할 것이 걱정되신다면 꼭 이 글에서가 아니더라도 님의 주장이 옳은지 틀린지는 증명해주셔야 할 것 같습니다.

사실, 제가 이토록 열을 냈던 이유가 "왜 자신의 주장은 증명하지 않고, 계속 다른 소리만 하고 있는가"라고 생각하게 되었기 때문이었습니다. 엔지니어는 말보다는 코드, 기술, 실력이라고 생각합니다. 하지만, 앞으로 이런 일이 있게되면 표현에도 주의를 기울이거나 중간중간 정리하는 과정이 필요하다는 것도 덕분에 알게되었습니다.

P.S// 제 인격이 덜 된 것은 사실입니다. 그렇다고 자신의 잘못과 실수, 혹은 다른 사람이 오해할 수도 있는 부분을 단 한번도 언급하거나 인정하지 않은 분의 인격도 저에 비해서 대단히 훌륭하진 않은 것 같습니다. 제 표현이 거칠었던 점은 반성하지만, 그래도 남의 허물만 보는 것보다는 자신의 잘못을 인정하고 반성하는게 더 나은 자세라고 생각하고 있습니다.
          
   숨어지내리   07-03-25 16:34  
..^^ 끝까지 가보자는 거군요..

new Object() 와 {} 의 쓰임새를 알려드립니다.

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Creating_New_Objects:Defining_Getters_and_Setters


위의 내용을 보시고요.

new Object() 와 {} 의 쓰임새를 제대로 파악해 보시기 바랍니다.

You can define getters and setters on any predefined core object or user-defined object that supports the addition of new properties. The syntax for defining getters and setters uses the object literal syntax.

객체의 getters 와 setters 를 사용하기 위해서 literal syntax 를 사용한다고 나와있습니다.

결과가 같다고, 다 같은게 아니라고 그렇게 말을 해도 믿지 않고

책에 없다, 그런거 본적이 없다고 우기시는게 정말 재미있었습니다.

자꾸 허물 허물 하는데, 허물이 있으니 지적을 하지요.. ㅡㅡ;

솔직히 행복한 고니님이 많이 알고 해박한 지식이 있다는거 압니다만,

더 많이 알고, 더 잘하는 분들이 많고 지금도 저희의 논쟁을 보고 있을것이란 말입니다.

"엔지니어는 말보다는 코드, 기술, 실력이라고 생각합니다"

위의 내용을 말씀하시는데에 저는 그것보다 노력이라 생각합니다.

코드 , 기술 , 실력 그 딴건 노력하면 다 됩니다.

평가를 받는것에 집중하시지 말고, 시시비비를 좋아하시지 말고,

한번정도는 남의 말에 귀기울일줄 아시는것도 배우셔야 할것 같습니다.

이만, 글을 끝냈으면 하는 바램입니다. 

더 이상 행복한 고니님이 리플을 달아 불행한 고니님으로 안되시길 바랍니다.


new Object() 와 {} 는 분명 차이가 있습니다.
결과가 core Object 를 밷는다고 해서 ,
사용방법을 거스르고 사용하는것은 꽁수로 가는 지름길입니다.

큰길이 있으면, 큰길로 가시기 바랍니다.


ps. 전 숨어서 지내렵니다. ㅡㅡ; 이제 여기서 종료.!! ok? (박해미버전)

ps2. http://jjowker.egloos.com/457219 계속 이거 보고 있습니다. ㅡㅡ; 저도 많이 속하는데요 .. ㅎ
               
   행복한고니   07-03-25 17:45  
아.. 드디어 원하는게 나왔군요. 처음부터 이렇게 나왔으면 좋을 뻔 했네요. 빨리 좀 이러시지 그러셨어요? 그랬으면 이런 소모적인 대화는 필요없었을텐데요.

근데, 근거가... 근거라고 볼 수가 없네요.
영문 해석은, setter와 getter를 정의하는데 object literal 이 사용된다입니다. 그렇다고 그게 new Object 로 되지 않으며, {} 와 new Object가 서로 다른 결과라는 것을 증명하지는 못하죠. 왜냐고요? new Object 로도 getter 와 setter 를 만들어 낼 수 있거든요.

님께서 주신 바로 그 링크 아래쪽에 있습니다. 물론, 잘 보고 주신거겠죠?
var obj = new Object;
var obj = {}; 의 모양이 다른 것처럼 말이죠...

var obj = new Object;
obj.__defineGetter__("year", function(){ return 2007 });

var obj = { get year() { return 2007 } };

는 같은 거란 말입니다. 문법의 차이가 객체의 차이라고 말씀하실 건가요? 그건 아닐텐데 말이죠. 그나마도 getter, setter 는 IE에선 안되죠. 아쉽게도요. getter, setter 존재는 이미 알고 있던겁니다만, 그게 어째서 객체의 차이가 되는건지 모르겠네요.

function a() {  alert('a');  } 와  var a = function() { alert('a'); } 는 다른 거라고 말씀하실 건가요?

제발요. 저를 설득할만한 근거를 "제.대.로" 좀 가지고 오세요.
그 긴 시간을 거쳐 가지고 온게 고작 이런겁니까? ECMA에서 new Object 를 실행한 것과 같은 결과를 리턴한다는게 제 근거였고, 모든 결과가 똑같다는게 제 근거였다면 그것을 반박할만한 증거를 가지고 오셔야죠.

전 정말 님의 말에 귀기울이고 있습니다. 그런데, 그 동안은 증거도 없이 주장만 하셨고, 지금 가져온게 겨우 이런거잖습니까? 증거도 근거도 없는 다른 사람의 주장을 제가 받아들일 수는 없는 노릇이죠. 근거도 없이 주장하는건 "우기는 것" 밖에 안됩니다. 지금 누구더러 우겼다고 하시는지 모르겠군요.

아닌 걸 아니라고 해놓고서 시시비비를 가리는 걸 좋아한다는 식으로 이상하게 만드시는군요. 저는 제 지식이 틀렸기를 진심으로 바라고 있습니다. 이렇게 긴 시간을 들였는데, 겨우 "알던 것의 재확인" 만 되면 저한테 뭐가 남겠습니까? 한번 쪽팔리고 지식을 배우는게 저한테는 오히려 이득인데 말이죠. 물론, 저보다 많이 아시는 분이 없을리가 있겠습니까. 그래서 더욱 알고 싶군요. 제가 알고 있는 제 지식이 틀렸다는 것을 증명해주시기를 정말 기다리고 있습니다.

자, 제가 다시 new Object 와 {}은 똑같다고 말했습니다. 모양이 다르다고 내부적으로 달라지는 것은 아니라고 말씀드렸습니다. {}은 ECMA문서에서도 그랬습니다. new Object 로 객체 만들고 property 설정하는 것과 같은 결과라고요. 그러니 모양이 다르다고 객체 자체가 다른 것은 아니라는 말입니다. "new Object" 로 표현을 실행한 것과 같은 결과를 도출한다고 그랬으니까요.


P.S// 전 논쟁하는 것보다 배우는 것을 훨씬 좋아합니다. 또한 검증되지 않은 지식을 가지고 있는 것도 아주 싫어합니다. 그래서 제 지식의 옳고 그름을 알고 싶어하는거죠. 그래서 제 지식에는 "제가 검증해본 것"과 "남이 그렇다고 한 것"으로 나누어져 있습니다. 이 경우에는 "남이 그렇다고 한 것"이 "제가 검증해본 것"과 상충되기 때문에 논쟁이 되었죠.

P.S2// 그나저나 setter, getter 덕분에 {}이 연관배열 표현이라는 주장은 더 설득력을 잃겠는데요?
                    
   숨어지내리   07-03-25 18:13  
..^^ 끝까지 불행한 고니님으로 가실 모양입니다. 쪽지까지 주시고요..

Summary
In principle, getters and setters can be either

defined using object initializers, or
added later to any object at any time using a getter or setter adding method.


When defining getters and setters using object initializers all you need to do is to prefix a getter method with get and a setter method with set. Of course, the getter method must not expect a parameter, while the setter method expects exactly one parameter (the new value to set). For instance:

고니님 말대로 setter 와 getter 는 2가지로 만들수 있는건 사실입니다.

When defining getters and setters using object initializers all you need to do is to prefix a getter method with get and a setter method with set

허나, setter 와 getter 를 preifx 시키기 위해 object initializers 를 사용한다 되어 있습니다.

그리고 new Object() 선언할때 , setter 와 getter 는 만들수 없습니다. ㅡㅡ;
added later to any object at any time using 이죠.. ㅡㅡ;

본질은 다르다는 겁니다.. 우기시지 마시고, 영어를 차근히 해석하세요.
쇼팬하우어의 상을 두번받으셔야 겠습니다.
 http://jjowker.egloos.com/457219
 http://jjowker.egloos.com/457219



http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Literals#Object_Literals

An object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}).

위에서도 속성값과 연관값을 쌍으로 갖는 object 로 표현하고 있습니다. ㅡㅡ;
그러니 연관배열형태라고 말하게 되는것이고요..


더이상 시간 낭비 맙시다... 불행한 고니씨.

인정하셨다면, 죄송하다고 하는것도 예의입니다. ㅡㅡ;
                         
   행복한고니   07-03-25 18:41  
그런 식으로 할꺼면, getter, setter 까지 가지 않아도 이미 {propertyName:value} 역시 마찬가지입니다. new Object에서는 값을 설정하지 못하니까요.
하지만, 분명 ECMA 표준 문서에서는 같은 결과라고 얘기하고 있습니다. getter, setter 가 선언될 때 그렇게 설정이 되는 것은 {} 문법이 말 그대로 Object initializer 라서지, 그게 new Object 와 {}가 다르다는 근거는 되지 못한다는 겁니다.

Object literal 에 대해서는 이미 사용법이 다르다고 얘기하지 않았습니까? 그것을 ECMA 문서에서도 new Object 를 실행한 것과 같은 결과를 도출한다고 했고요. 지금 님께서는 "모양이 다르고 사용법이 다르니 객체가 다르다" 라고 말씀하고 계신겁니다.

영어는 매우 차근차근 읽었고요, 참고로, MDC에서 한국어 번역자로도 활동하고 있어서, MDC 문서는 적잖게 읽었습니다. 특히, JavaScript에 관한 문서는 꽤 많이 읽었거든요. 주신 링크들도 안 읽고 이런말하는게 아닙니다.

선언할 때 그렇게 설정할 수 있는 것은 "문법적인 특징일 뿐" 이라는게 제가 생각하는 바인 것입니다. 내부적으로 다르다는 근거를 아직도 못가져 오셨잖습니까? 같다는 근거라면 제가 더 들어드릴 수는 있습니다만...?

alert( ({}).__proto__ == Object.prototype );
alert( (new Object).__proto__ == Object.prototype );
alert( (new Array).__proto__ == Object.prototype );

__proto__ 에 대해서는
http://livedocs.adobe.com/flashlite/2_kr/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000731.html
이 링크 참고하세요. 어떤 객체로부터 만들어졌는지 알 수 있는 겁니다. 세번째 new Array를 예로 든 것은 {}과 new Object 는 같으나 new Array와는 다르다는 것을 보여주기 위해서입니다.

이런 토론이 시작되게 된 데에는 new Object 와 {}가 다르다는 말씀을 하셨기 때문이고, 그 아래에 {}은 연관배열이라고 하셨기 때문입니다. 그 주장이 맞으려면 new Object 와 {}은 다르며, {}이 연관배열이어야 하는데, 여전히 {}과 new Object 가 다르다는 근거를 들지 못하고 계십니다. 문법적인 차이는 이미 있다고 말씀드렸습니다만, 그게 내부적으로 다르다는 근거는 되지 못한다고도 말씀드렸습니다.

제발, 근거를 제대로 좀 가져오세요...

_________________________________________

혹시 또 오해가 있을지 모르니 입장을 한번 밝혀봅시다.

1. {}으로 생성된 인스턴스는 new Object 로 생성된 인스턴스와 같은 인스턴스입니까 아니면 다른 종류의 인스턴스입니까? (identity 가 아닌 equality 를 묻는 겁니다)
-> 제 입장은 같은 값을 가지는 인스턴스라고 봅니다.

2. {}의 모양이 다르다고, {}과 new Object는 다른 건가요?
그렇다면 []와 new Array는 같은 걸까요, 다른 걸까요?
var a  = function(){ alert('a'); } 와
var a = new Function("alert('a') "); 는 같은 걸까요, 다른 걸까요?
-> 제 입장은 예로 들었던 것들은 서로 같은 값을 가진다입니다.
_________________________________________

분명 System 상에서 구현되어져 나온다고 그러셨는데, 문법이 alias 된 것이 객체 자체가 다르다는 것을 증명해주는 것은 못됩니다.

다시 부탁드립니다. (__)

P.S// 글을 조금 수정하셨네요. 마지막 말은 저도 그대로 돌려드립니다.
   숨어지내리   07-03-25 18:45  
그냥.. 제가 졌습니다. ^^; 본질을 흐리시군요.

먼가를 답을 내주면 다른 소리 하고..

쇼팬하우어의 상 3번 받으시고, 그렇게 new Object() 와 {} 는 똑같다라고 생각하시면 될듯합니다.

 http://jjowker.egloos.com/457219
 http://jjowker.egloos.com/457219
 http://jjowker.egloos.com/457219
     
   행복한고니   07-03-25 18:47  
아뇨. 정말로 틀렸다는 것을 증명해주시기를 바라고 있습니다.
원하신다면 문서로 만들어서 대중의 심판을 받을 각오도 되어있습니다.

여태까지 주신 근거는 제가 아니라고 반박해드렸습니다.
애매한 태도로 제가 우긴 것처럼 하지 마시고요, 정확하게 논거를 들어주시기 바랍니다.

틀렸으면 깨끗이 인정을 하시던가 그렇지 않으면 "내부적으로는 다르다" 는 것에 대한 증거를 보여주셨으면 합니다. 지금과 같은 태도는 별로 바람직하지 않다고 봅니다. 본질을 흐렸다고 생각하지 않고 있는데, 본질은 무엇이며 어떻게 흐렸는지도 좀 알려주시고요. 인정하기 싫으신건지는 모르겠지만, 어쨌든 간곡히 부탁드립니다.
     
   행복한고니   07-03-25 19:09  
String literal 과 String object 는 서로 다른 거라는 근거는 찾았습니다.
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Predefined_Core_Objects:String_Object

eval 을 하면 결과가 다르다는군요.
제가 예로 들었었는데, 그 부분은 제가 틀렸습니다.
"" 과 new String 은 서로 다릅니다.

그런데, 아직도 Object literal 과 Object object 가 서로 다른 거라는 근거는 못찾겠네요. 알고 계시다면 제발 좀 알려주세요.
   숨어지내리   07-03-25 19:16  
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Creating_New_Objects:Defining_Getters_and_Setters

문서에 나와 있는데로, new Object 와 {} 의 차이점이 설명되어 있는데,
더이상 어떤걸 증명하라는건지 이해가 되질 않는군요.

제가 지치니, 해야할 일도 못하고 있군요.. 가뜩이나 휴일에 나와서 일하는데.. ㅠㅠ

아까도 말씀하신 논쟁도 아닌 소모전으로 가시지 말고, 문서에 나와 있는대로 동작하니,

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Creating_New_Objects:Using_Object_Initializers



If an object is created with an object initializer in a top-level script, JavaScript interprets the object each time it evaluates an expression containing the object literal. In addition, an initializer used in a function is created each time the function is called.

위의 내용을 해석하시면 될듯 합니다.


또한

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Literals#Object_Literals

This will lead to an error or not behave as you expect, because the { will be interpreted as the beginning of a block.

이 부분도 잘 생각해 보시기 바랍니다. 왜 에러가 나고, 원하는 대로 동작하지 않는지를..


이제 더이상 저에게 묻지 마시고, 문서를 보세요.. 머리아픕니다..

해야할일도 산더미인데.. ㅡㅡ;


보시고, 인정하시면 그동안 무례하게 한 부분 사과 해 주시면 감사하겠습니다.

사과를 안하시면 쇼팬하우어 상 100번 드립니다. ㅡㅡ;;;;;;

for( var i = 0 ; i < 100 ; ++i){ 행복한고니 = "http://jjowker.egloos.com/457219"; }

불행한 고니라고 부르고 다니겠습니다. ㅡㅡ; (반협박이죠.. ^^)

그럼 저도 사과하도록 하겠습니다.
     
   행복한고니   07-03-25 19:51  
문서에 나와있는 걸로는 "문법적인 차이" 외에는 아무리 봐도 알 수가 없네요. 구체적으로 어디에 집중해서 봐야하는건가요?

작동하는 방식은 이미 다르다고 말씀드렸고요. 그게 내부적으로 다르다는 근거는 되지 않는다고 말씀도 이미 수차례 드렸습니다. 생긴 모양이 그렇게 보일 뿐 new Object 로 객체 생성하고 프로퍼티 붙이는 것과 다를 게 없다고도 말씀드렸고요.

던져주신 문서만 보고 이해하려 해도 대체 무슨 의도로 주신건지 이해가 안됩니다. 제가 부족하다면 정확하게 찍어주시고 예제도 부탁합니다. 정확히 어디를 보면 되나요?

영문 해석을 보면 object 가 evaluate 될 때마다 literal 안에 있는 문장이 해석된다 라고 하는데요, evaluate 된다는 것은 선언될 때를 말하는 걸로 보이는군요. 그건 당연한거라고 보고요. 함수안에서 사용된 initializer 는 함수가 호출될 때마다 선언된다고 하는데, 함수안에서 사용되었으면 당연한겁니다.
또한, 그 챕터의 다른 예제에서는 function car(){} 와 같은 식으로 흔히 말하는 OOP 적인 사용을 설명하고 있고요. 챕터 자체에서 사용된 Objects라는 단어가 우리가 논하고 있는 코어 Object가 아닌 각각의 객체들을 얘기하고 있습니다.  new Object 와의 차이점이 아닌 function car() 를 정의하고 new Car() 를 사용하는 것과의 차이점을 설명하는 겁니다.

저 문장을 그냥 던져주신게 아닐텐데, 어떤 걸 보라고 주신건가요? new Object 와 {}간에는 어떤 차이가 있는 건가요? 가능하다면 예제도 하나 주시고요.

두번째에서,  에러는.. 제가 예제를 들 때 괄호로 감싸는 이유입니다. {}를 문법적으로 블럭의 시작으로 보기때문에 에러를 발생시키거든요(문서에도 그렇게 나왔죠). 이것은 {}가 객체를 생성하는 용도의 Object initializer 말고도 다른 용도(with, for, function 등을 정의할 때)로도 사용되기 때문에 인터프리터가 혼동을 일으키는 것에 불과합니다. 그래서, 제가 예제로 드릴 때 마다 항상 ({}) 과 같이 괄호로 감싸서 드렸잖습니까.

문법과 사용법이 다른게 어째서 내부적으로 다르다는 증거가 되는지를 묻는겁니다. ""과 new String 은 제가 찾은 것이긴 하지만 아주 쉽게 수긍했습니다. eval의 결과가 달랐으니, 두가지가 서로 다르다는 증거가 되는거죠. 하지만 여전히 {}과 new Object는 수긍이 안되는군요.

P.S// 제가 무례하게 한 부분은 단어 선정이 과격했던 것 말고는 없다고 생각하는군요. 그리고 그 부분은 지나쳤다고 이미 사과했습니다. 불행하다고 부르셨던 것은 그냥 넘어가드리겠습니다.
   숨어지내리   07-03-25 19:59  
아휴...ㅡㅡ; 소모전에서 제가 졌습니다.

네 .. {} 과  new Object() 는 같습니다.



ps. 덧글들의 표현들(불행, 쇼펜하우어)은 사과드리며, 이만 종료하면 좋겠습니다.
    더이상의 답글을 달지 않도록 하겠습니다.
    답글을 달지 않는다하여 욕을 하셔도 좋습니다. 이젠 힘듭니다..ㅠㅠ
   낭망백수   07-03-25 23:57  
그래도 많이 배워갑니다.
두분다 감정은 상하지 마시고, 수고하셨습니다.
공부 많이 해야겠다는 생각이 드네요.
현업으로 복귀하는데 시간이 더 많이 걸릴 것 같습니다. ㅎㅎ
꾸벅~!
   무소레즈   07-03-26 17:00  
{} 는 상수개념으로 property 를 정의한 독립적인 하나의 개체이고,
new Object 는 new 를 사용하여 새로운 instance
즉, 같은 자료구조를 가졌지만 instance 가 서로 다른 독립적인 개체를 생성합니다.

{} 은 new Object 에의해 생성된 여러 instance 중에서 어느 한 개체와
(같은 자료구조 && 같은 property 값)을 가질 수는 있지만, 분명히  instance 는 다릅니다.

제가 알고 있는 것은 이렇습니다.
     
   행복한고니   07-03-26 18:13  
저도 다시 시작하긴 싫은데, 정말로 그 "알고 계시는 것"에 대한 근거를 원합니다. 제가 바라는 건 단지 그것뿐입니다. 두 가지가 서로 다른 것이라면 다르다는 근거를 알고 싶을 뿐입니다. 또한, instance 가 다르다는 말이 어떻게 다르다는 말인지 표현이 애매합니다. 두 instance 간에 서로 identity가 다르다는 것인지 아니면 등가(equality)가 아니라는 것인지요. 참고로, ECMA 스펙에서는 new Object 를 생성한 것과 같은 결과를 리턴한다고 되어있습니다.

그에 관해서는 제가 아직도 이해하지 못한 숨어지내리님의 근거와 저 나름대로 들어놓았던 몇몇 근거가 있으니 읽어보시면 될 것 같습니다. 혹시 다른 근거가 있으시다면 다시 얘기를 나눌 의향도 있습니다.
   무소레즈   07-03-26 21:50  
function price ( a, b ) {
  this.kr=a;
  this.us=b;
}
meat1=new price(500,100);
meat2=new price(700,100);

이와 같이 정의 되어 있을때,
객체타입 price 는 Function 타입의 instance  이고,
객체변수 meat1 과 meat2 는 price 타입의 instance 이며 또한 Object 타입의 instance 입니다.

Object 타입인 meat1 과 meat2 의 instance 는 갈을지라도
서로간의 identity 나 equality 는 다릅니다.
각자 독립적인 개체이기때문입니다.

copy_m1=meat1;

alert(meat1 === meat2 );    // false
alert(meat1 == meat2 );    // false
alert(meat1 == copy_m1 ); // true

a=new Object;
b=new Object
copy_a=a;

alert (a===b);  // false
alert (a==b);    // false
alert (copy_a==a);  // true


{} 와 new Object 는  내부적으로
임의의 비어있는 객체를 생성하여  instance 만을 반환(return) 하고,
생성자로써 사용된 그 임의의 객체는 소멸된다고 판단됩니다.
Object() 함수내부에서 사용후 소멸되어
실제 생성자가 어떤 객체인지 알수가 없는 것이지요.

meat1 과  meat2 는 모두 같은 instance 를 갖지만
{} 와 new Object() 에의해 생성된 instance 는 서로 다른 instance 를 갖게 된다고 봅니다.
     
   행복한고니   07-03-26 22:41  
1. 자바스크립트에서는 생성자 함수가 객체타입의 역할도 합니다.
2. price는 Function의 인스턴스이자 meat1, meat2의 타입입니다.
3. Object 역시 Function의 인스턴스입니다. 따라서 객체타입으로서의 역할을 충분히 한다고 생각합니다.
4. 어떤 객체의 생성자는 constructor 프로퍼티를 통해 알 수 있습니다. 생성자를 체크해보면 meat1 과 meat2는 price라고 나오고, {}과 new Object는 Object 라고 나옵니다.

따라서 내부적으로 임의의 빈 객체를 생성한다는 말이나, 생성자가 소멸된다는 말은 설득력을 잃습니다. 분명 생성자는 여전히 존재합니다.

추가로,
var obj1 = new Object;
var obj2 = {};
alert(obj1.constructor === obj2.constructor);

의 결과는 true입니다. 두 객체의 생성자는 완전히 똑같은 객체이며

alert(obj1.constructor === Object);

에서 보다시피 그것은 Object 입니다.
          
   숨어지내리   07-03-27 00:53  
ㅡㅡ;; 계속 논쟁이 이어지고 있군요..

왠만하면 행복한 고니님과 논쟁을 피하고 싶으나, 논쟁이 시작되었을떄부터

아니라고 생각한 부분이 진실이 되는걸 볼수 없어, 답글을 남깁니다. ㅠㅠ


"Object 역시 Function의 인스턴스입니다."

이부분은 계속 말씀드렸듯이 core Object 즉 Object 가 최상위입니다. 


http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object

의 종합된 내용을 보면,

Core Object
Object is the primitive JavaScript object type. All JavaScript objects are descended from Object. That is, all JavaScript objects have the methods defined for Object.

모든 객체의 최상위는 core Object 라고 제가 계속적으로 말씀드린 상황입니다.

Function 이라고 보여질뿐 모든 객체는  core Object 즉 Object 를 통해서 생성된다고 되어 있습니다.

즉 최상위의 객체는 Object 입니다. ㅡㅡ;


그리고 Object 의 constructor 는 new Object() 입니다.

또한 new Object() 는 Object 의 constructor 입니다. ㅡㅡ;

Created by
The Object constructor: new Object()

처음부터 제가 주장한 결과는 같지만, new Object() 와 {} 가 다르다는게,

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Creating_New_Objects:Using_Object_Initializers



If an object is created with an object initializer in a top-level script, JavaScript interprets the object each time it evaluates an expression containing the object literal. In addition, an initializer used in a function is created each time the function is called.

를 해석해서 생각해 보시라고 한게 그런것입니다. ㅡㅡ;


core Object 의 constructor 는 new Object() 이고,
{} 는 new Object() 처럼 동작 되어지는것이고,
javascript 1.1 이하에서는 literal은 동작되지 않는다라고 되어 있습니다.

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Creating_New_Objects:Using_Object_Initializers

JavaScript 1.1 and earlier. You cannot use object initializers. You can create objects only using their constructor functions or using a function supplied by some other object for that purpose. See Using a Constructor Function.

1.1 이후 편의성에 의해서 생성된 문자(literal)이고, 그게 new Object() 처럼하는것이고요,

In addition to creating objects using a constructor function, you can create objects using an object initializer. Using object initializers is sometimes referred to as creating objects with literal notation. "Object initializer" is consistent with the terminology used by C++.

위의 내용이 뒷바침해 주고 있는것이지요.


고니님이 주장하는 new Object() 와 {} 은 동일하게 객체를 생성할때 쓰이는게 맞으나,
엄밀하게는 쓰이는 용도와 차이가 있어 똑같다고 말하는건 잘못된거 같다고 한게,
제가 처음부터 말씀드린 내용입니다.



ps. 이것에 대해 증명해보라 하지 마십시요. ^^; 기분나빠하시지도 말고요.
    정말, 그냥 여기서 멈추었으면 좋겠습니다. ㅠㅠ;
    전 단지 아닌 부분이 진실이 되어질까 하는 마음에 답글을 남깁니다.
    숨어 지낼겁니다.ㅠㅠ

ps2. http://zeldign.com/tt/38
               
   행복한고니   07-03-27 02:33  
다시 나올지 몰랐네요. 혹시나 했는데, 역시나...

Function 이 Object 을 상속한 것은 맞지만, Object 역시 Function의 인스턴스입니다. 자바스크립트 언어의 특징이라 볼 수 있는 prototype chain 에 의해서 말이죠. 님과는 달리 저는 증명이 뒤따르지 않으면 믿지 않습니다. 그래서 또 근거를 드리죠.

alert(Object.aa);
Function.prototype.aa = 'bb';
alert(Object.aa);

실행해보시고 그럼 이게 어떻게 다르게 해석될 수 있는지 다시 말씀해주세요. "내부적으로 다르다"는 근거도 없는 그런 막연한 말씀은 빼고요.

그 전부터 느끼고 있던 것인데요, 왜 문서에 없는 부분을 자꾸 첨가하시는 건지 모르겠습니다. 자바스크립트의 모든 객체들이 Object 를 상속하는 것은 맞습니다. 당연한 사실이죠. 하지만, 그게 Object가 Function의 인스턴스가 아니라는 말은 안된다는 말입니다. 거기 어디에 그런 문장이 있는지 짚어주세요.

만약, 문서에 그리 나와있었으면 제가 인정해드리겠습니다만, 문서에 없는 내용을 자꾸 첨언하고 계시잖습니까? 자의적인 해석 말고 있는 그대로 보세요. 제가 말한 것이 설령 그른 내용일지라도 저는 코드상에서 비춰지는 사실 그 자체만을 말하고 있고요, 님께서는 문서상에 없는 말을 첨언하고서 저더러 믿으라고 하시는군요.

core Object의 constructor 가 new Object 라는 말은 잘못하신거겠죠? constructor 라면 자바스크립트가 아닌 (최소한 제가 아는)다른 어떤 언어에서라도 생성자는 메소드/함수가 되어야 할텐데 Object 도 아닌 new Object 가 constructor 가 된다는 말씀인가요? 자바스크립트는 함수가 아닌 객체 자체를 생성자로 사용할 수 있다니 무척 놀라워하고 있습니다.
________________________________________________

Create by 부분에서 제대로 웃었습니다. ㅎㅎ
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Number

Array의 constructor 는 new Array 군요. Number 의 constructor 역시 new Number 구요? ㅎㅎㅎ
________________________________________________

잠깐 재밌었으니 다시, 'In addition to'... 이 부분은 사용자가 명시적으로 constructor function 을 이용해서 생성하는 방법 외에 Object initializer 라는 방법을 사용할 수 있다라는 내용입니다. 물론, 사용과 동시에 객체에 프로퍼티를 지정하는 등의 초기화가 가능하니까 initializer 라 부르는 것이고요. 이 부분에 대해서도 ECMA에도 나와있다고 제가 말했으며, "방법만 다를 뿐" 같은 결과라고도 했습니다. 이게 왜 님의 주장을 뒷받침해주는 것인지 말씀해주세요.

new Function 으로 함수를 만들 수도 있고 function 선언으로 만들 수도 있습니다. 중요한 것은 적재적소에 쓰는 게 맞습니다. 하지만, 용도가 다르다고 코드의 생김새가 다르다고 "객체가 다르다"고 주장하는 것은 논리적 비약이죠. 인스턴스 객체를 초기화하면서 생성할 때 {}가 더 유용한 것은 사실이나 "더 유용하다"라는 사실이 "서로 다르다"를 증명하지는 못한다는 말입니다. 꼼수건 정석이건 제대로 알고 쓰셔야죠.
________________________________________________

블로그에서 영문해석을 조금 잘못하신 것 같은데, 함수처럼 쓰인다는 말은 그 문장에 없고요, {}가 "함수에서 사용되었을 때"와 "함수가 호출될 때" 밖에 없습니다. 어디에 함수처럼 쓰인다고 써있나요?

an initializer used in a function is created each time the function is called.
>> 함수에서 사용된 initializer는 해당 함수가 호출될 때마다 생성된다.

그래서 당연하다고 했는데요? 당연하다고 했을 때는 듣지도 않고 안한다고 하시더니 이제 와서 또 딴소리를...
function aa() {
    var bb = {};
}

function aa() {
    var bb = new Object;
}

어떻게 하면 함수가 호출될 때마다 생성되지 않을 수 있을까요? 그 챕터가 전체적으로 의미하는 바를 잘못 짚으셨다고 위에서도 말했는데, 그 챕터는 new Object 와의 차이점이 아니라,사용자가 객체 타입을 정의했을 때와 비교하는 겁니다.

지금 논리적인 착각을 하고 계시는 듯 해서 정리해드리면요. "용도"와 "모양"은 그 사물의 "본질"을 결정짓는 절대적인 요소가 아닙니다. 오히려 "성질"이 본질을 결정짓는 중요한 요소인거죠.

P.S1// 인정하는 모습이 꽤 찝찝하긴 했어도 그냥 그러려니 했는데, 역시 이러시는군요. 그럴바엔 그런 성의없는 인정한다는 말도 안하는 편이 훨씬 좋았을텐데요. 인정했다고 하지 말던지, 기껏 블로그에서 다른 소리 하는게 님의 스타일이시군요. 잘 알겠습니다.

P.S2// 증명도 못하는 고집은 이제 그만 꺾으십시오. 차라리 코드로 나름의 논리가 있는 무소레즈님과 얘기하는 편이 훨씬 더 유익합니다. 초보자들 이제 그만 현혹시키세요.

P.S3// 영문해석을 그리 잘하시지는 못하시는 것 같습니다. ^^

P.S4// 아... 이번엔 재밌었습니다. 특히 Create by 가요. ;)
                    
   숨어지내리   07-03-27 03:07  
ㅎㅎㅎ creaed by 부분은 잠시 생각하고 잠자리에 누웠다가

바로 일어나서 확인했네요..^^;;

성급한 해석이었던듯 ..^^ 인정.!!
                    
   숨어지내리   07-03-27 05:41  
prototype chain 대한 명제이니, 아래의 예제는 참일수밖에 없습니다. ^^;

alert(Object.aa);
Function.prototype.aa = 'bb';
alert(Object.aa);


제가 고니님을 반박했던

Object.prototype.someFunc = function() { alert('hello~') };

({}).someFunc();
(new Object).someFunc();
(new Array).someFunc();

위와 같은 내용과 같은 것이니깐요. ^^;


허나 제가 보는 입장은 고니님이

---------------------------------------------------------------------------------------------------
 "용도"와 "모양"은 그 사물의 "본질"을 결정짓는 절대적인 요소가 아닙니다.
---------------------------------------------------------------------------------------------------

와 같이 말했듯이 new Object() 와 {} 은 용도는 같다는 것입니다.
따라서 본질이 같다고 까지 할수 없다라는 것이죠.


본질을 결정짓는것은 성질일수도 있지만, 특징일수도 있는것입니다.

이미 앞에서도 언급해 드린대로 setter 와 getter 의 생성에 대한 특징 부분에서

-----------------------------------------------------------------------------------
" When defining getters and setters using object initializers all you need to do is to prefix a getter method with get and a setter method with set

허나, setter 와 getter 를 preifx 시키기 위해 object initializers 를 사용한다 되어 있습니다.

그리고 new Object() 선언할때 , setter 와 getter 는 만들수 없습니다. ㅡㅡ;
added later to any object at any time using 이죠.. ㅡㅡ;  "
-----------------------------------------------------------------------------------

위와 같은 성질과 함께 특징을 가지고 있는게 {} 이기 때문에

똑같다는 표현은 아니라는 것입니다.


행복한 고니님이 말한  new Object() 와 {} 의 본질은 무엇인가요?
막연히 똑같다? 는 입니까???

객체의 constructor 와 prototype 이 같기때문에 본질도 같다?

저야말로 수긍하기 어렵습니다.

ps. 새벽 늦게 글을 보다, 고니님이 Function 이 최상위 인듯 얘기하는것 같아,
    글을 남겼는데... 또 논쟁으로 빠져버렸네요.. ㅡㅡ;

    또 자세히 보니 " Object 역시 Function의 인스턴스입니다 " 이군요.

    이제부턴 새벽에는 phpschool 에는 들어가지 말아야 할것 같네요..ㅡㅡ;

    제가 반박한 prototype chain 에 제가 걸려 넘어졌네요.. ^^;
   ε♡з   07-03-27 06:23  
기술적인 부분을 이해는 못하지만 오랫만에 보는 흥미진진한 논쟁이네효.
쇼펜하우어까지 나오구요 >_<;; 이해가 됬으면 더 재밌을텐데 아쉽습니다.

쇼펜하우어 책을 보셨으면 아실테지만 논쟁에서 객관적인 승리는 불가능하다고 써있습니다.
다만 자신에게 유리하게 몰아가는 법이 있습니다.
내 주장은 좁히며 상대방 주장은 확대해석하는 법입니다. ㄳ
(기술적인 부분을 이해했으면 누가 확대해석 하는지 알 수 있을텐데 >_<)

이부분을 달리 생각해보면..
서로 심플하게 자신의 주장을 내세운다면 어긋났던 부분은 분명 잡힌다는 겁니다..

아무쪼록 끝을 보시는게 인류발전에 도움이 될듯.. ㄳㄳ

ps) 제 리플은 무시하고 고고싱~ ㄳ
     
   숨어지내리   07-03-27 06:35  
잠 다깨고, 날 샜네요..ㅡㅡ; 덴장.

1. new Object() 와 {} 의 결과는 같다.
2. 허나 차이가 있다.
3. 따라서 똑같다고 말하는것은 어불성설이다. '고니님이 말한 각각의 본질이 있다.'
          
   행복한고니   07-03-27 11:18  
아... gettter 와 setter 를 prefix 한다는 말 말인데요, 정확하게는 get 으로 getter를 표시해주고, set 으로 setter를 명시해주기 위해서 사용한다는 말입니다. 단지 문법적이고 방법적인 특징일 뿐이라고도 말씀드렸던 것 같군요. 코드의 모양이 다르니까 달라보이겠지만, 본질은 같다는 거죠.

여태까지 방법적인 차이 말고 무엇을 증명하셨는지 모르겠군요. 했던 얘기 또 하고, 했던 얘기 또 하고... 방법의 차이는 어느 누가 봐도 존재하고(코드의 모양이 다르니까), 또 저 역시 처음부터 방법적인 차이는 있다고 말했었는데 말이죠.

왜 누구나 아는 보편적 사실을 가지고, 그게 갑자기 "본질의 차이"를 만들어내는 방법이 되는지 논리를 이해할 수가 없군요. 문법적인 편의성이 "본질"을 결정짓는 중요한 요소가 될 수 있었군요. ^^

뭐... 그냥 그렇게 생각하고 계시라는 말 밖에는 할 말이 없네요. 이미 어떤 말을 해도 인정을 안들으실 것 같으니까요. 그나마 처음에는 new Object와 {}의 결과가 같은 것도 인정안하더니 그나마 조금 낫군요. 증명도 안되는 논리에 상대해주는 것도 이젠 그만하렵니다. 열심히 사세요 :)
               
   숨어지내리   07-03-27 13:41  
prefix 를 잘 설명해 주시네요.. ^^;

get 으로 getter 를 명시해 주는거랑
getter 를 prefix 해주는거랑

set 으로 setter 를 명시해주는거랑
setter 를 prefix 해 주는거랑 무슨 차이가 있는지 모르겠네요..

목적은 getter 와 setter 를 명시해 주는것인데? ㅡㅡ;
혹시 영어해석이 틀린게 아닌지 잡아내려고? (그렇다면, 소심하시다.. ㅡㅡ)
본질은 prefix 인데요.. ㅡㅡ;


그럼 new Object() 는 선언될떄부터 명시해주나요.? 아 그래서 같은 거구나 라고

말할수 있는 근거를 말도 못하면서, 본질 얘기 하더니 참 재미있네요..^^

제 대화의 시작과 핵심은 {} 과 new Object() 는 결과는 같을지라도,
서로 차이가 있다 라는 것입니다.

code 로 들이밀면서 constructor 가 같은니 완전히 같다 라고 말하는것자제가
본질을 무시하고 결과가 같으니깐, 같다라고 말하는것과 무슨 차이가 있나요?

말하는것과 같이 생성자가 같으면 모두 같다면,

alert(Array.constructor);
alert(Object.constructor);
alert(Function.constructor);
alert(Number.constructor);

alert(Array.constructor === Object.constructor);
alert(Array.constructor === Object.constructor);
alert(Array.constructor === Function.constructor);
alert(Array.constructor === Number.constructor);

alert(Function.prototype.constructor.constructor);
alert(Array.prototype.constructor.constructor === Function.prototype.constructor.constructor);
alert(Array.prototype.constructor.constructor === Number.prototype.constructor.constructor);
alert(Array.prototype.constructor.constructor === Object.prototype.constructor.constructor);
alert(Object.prototype.constructor.constructor === Object.prototype.constructor.constructor);
alert(Array.prototype.constructor.constructor === Array.prototype.constructor.constructor);



아..

Array === Object === Function === Number 

모두가 같네.. 캬~

차이가 없네.. 결국은 모두 같은게야~~

고니님의 이론 재미있었습니다. ㅋㅋ

저게 다르다는걸 입증해 보는것도 고니님의 숙제 같네요..^^

'문서에 다르다고 되어 있어요' 라고 하면,

고니님의 주장은 설득력을 완전히 상실하겠네요.

constructor 가 같으면 다 같으니 말입니다. ㅋ

본질을 부정하시지 말아요~ 제발 .. ^^

전 잘먹고 잘살고 있으니, 제 걱정 안하셔도 될거 같네요. ㅋ


ps.
코드로 들이미는거 좋아하시나봐요? 자 저코드는 무얼의미하는지
ㅋ 제가 걸려 넘어졌던 prototype chain 인데..ㅋㅋ
고니님의 의견대로 모두가 같으니말입니다. ㅋ


ps2. 제 의견의 뜻을 모를까봐 .

var obj1 = new Object;
var obj2 = {};
alert(obj1.constructor === obj2.constructor);

new Object() 의 constructor 와 {} 의 constructor 는 같으니깐 .
Object 이다.

그럼 Object 의 constructor 와 Function 의 constructor 가 같고
다 같으니깐,

모두가 다 같으면, 의미가 없다라는것이죠? ㅡㅡ;

그러니, 너무 깊게 들어가면 어차피 prototype chain 에 걸려 자빠지니,

그냥 {} 와 new Object() 는 용도는 같다. 하지만 본질은 다르니,

{} 는 javscript 1.1 이후에 나온거고, setter 와 getter 를 prefix 해 주니

어느정도 그 목적과 본질이 있는건 아닌지 라고 생각해 보라는것입니다. ㅡㅡ;

ps3.
"왜 누구나 아는 보편적 사실을 가지고, 그게 갑자기 "본질의 차이"를 만들어내는 방법이 되는지 논리를 이해할 수가 없군요. 문법적인 편의성이 "본질"을 결정짓는 중요한 요소가 될 수 있었군요. ^^ "

편의성이라 판단하시다니, 대단합니다. ㅡㅡ; 특징을 편의성이라고 못박으시니...
그러니, 누구나 다 아는 보편적 사실을 가지고,

일관되게 주장해온 constructor 가 같다는 보편적사실을 가지고 여태 쭉 본질의 차이점에 대해 주장해온게 누군지 상상해 보시면 좋을것 같습니다. ^^

ps4. 자, 이로써 소정의 목적달성을 한 저는 이만 숨어지냅니다.
      솔직히 영어해석 딸립니다. ㅋㅋ 주관적으로 해석하지 않으려고 노력하는데도..ㅋ
      제가 질문한 코드가 저 부분이 다르다고 고니님이 입증하면,
      다시 와서 글남겨버리겠지만,
      아마도 짱구가 아니라면, 본질을 부정하지는 않을 겁니다. :)
      보시는 분들 수고 많으셨습니다.. 아마도 답글은 달리지 않을것으로 판단됩니다. :)
      http://zeldign.com/tt/38
                    
   행복한고니   07-03-27 16:34  
ㅎㅎㅎ 유머감각있으시네요.

지금 객체 타입으로서의 객체와 인스턴스로서의 객체를 혼동하고 계십니다. 으하하...
저라면 Function의 constructor가 Function으로 나올때부터 이상하다고 생각했을 텐데 그런 생각은 못하셨나봐요?

죄송하지만, 자바스크립트... 잘 모르시죠? 객체 타입이 Function의 인스턴스로 나타나는 것은 자바스크립트의 특징인 것입니다. 말하자면 class type1, class type2 를 지정하는 것과 같은 것이라는 말이죠. 그렇다고 type1과 type2 를 같은 클래스라고 하지는 않죠. 그게 바로 님께서 범한 오류입니다. 똑같이 class로 선언된다고 두개가 같은 클래스인가요? "클래스"라는 사실은 같겠죠. ㅋㅋ 객체 타입이 Function의 인스턴스로 나타나는 것은 자바스크립트의 특징, 그 중에서도 객체 타입선언의 특.수.성이라는 말입니다. 이러한 특수성을 가지고 마치 전체인양 호도하시다니 유머감각이 대단하시군요. ㅎㅎㅎ

제 말이 틀린 것이라면, 자료구조가 아닌 다른 인스턴스들을 한번 비교해보세요. ㅎㅎ 특수성이라는 말이 틀렸나요? 그러면 어떻게 Function의 생성자가 다시 Function이 될 수 있을지 한번 생각해보세요. 자료구조의 constructor를 비교해서 얘네가 다 Function이라고 말하는 것은 "얘네 모두 자료구조야"라는 말밖에 안된다는 겁니다. 아셨어요? ^^ 적어두세요. 특.수.성.

constructor 한번 비교한 것은 그나마 봐줄 만 했습니다. constructor를 여러번 하면 당연히 최상위 객체가 나오겠죠. 그런데 상위객체를 비교해놓고서 "당신이 틀렸다"라고 하고 있으니, 상속의 개념... 잘 모르세요?

기껏 가져온다는 코드가 이런거라니... 참...

자, 이제...
생성자가 같고,
타입이 같고,
성질이 같은
두 객체가 어떻게 다르다고 볼 수 있는지 다시 말씀해보세요. 힘드셔서 그랬겠지만, 자료구조가 Function 객체라는 특수성을 가지고 호도할 생각은 마시고요. :)

요약 : 비교 자체가 틀려서 논할 가치도 없다.

P.S1// 영어해석 딸리는 것은 알고있으니, 괘념치 마세요.
P.S2// 방금은 쇼펜하우어 법칙 14번이네요. 역시 마스터하셨군요!

_________________________________
혹시 또 이해를 못하셨을까봐 님께서 하셨던 비유를 제가 설명해드리죠.
var num1 = 1;
var num2 = 2;

alert(num1.constructor === num2.constructor);
이렇다고 num1과 num2의 "값"이 같은거냐고 묻고 있는겁니다. 두 객체의 indentity는 분명 다르고 값도 다르지만, "Number"의 특징을 지니고 있는 완전히 똑같은 "본질"(=숫자)의 객체임은 같은겁니다.

님께서 했던 그 코드는 말이죠.
Array가 자료구조 맞아? Object가 자료구조 맞아? 이것만 비교한 것말고는 아무런 의미도 가지지 못한다는 거죠. Array === Object는 아니죠. identity도 다르고 값도 다르니까요. 하지만 "자료구조"임에는 확실히 맞습니다. 그게 Array와 Object의 "본질"이죠.

단지 "자료구조"인지 아닌지만 비교해놓고서, 갑자기 서로의 값 혹은 identity를 묻고서 그게 마치 "본질"인 것처럼 말하고 있는거죠. 논술세대가 아니신 것 같습니다만, 그래도 이정도 논리는 갖추어야 앞으로도 이로우실 겁니다. :)

그래도, 갈수록 유머감각 있으시네요. ㅋㅋ
                         
   숨어지내리   07-03-27 17:53  
ㅋㅋㅋ 재미있군요..

특수성이란 단어도 말씀하시고, 전 그냥 prototype chain으로 밖에는 안보이는데요.
..ㅋㅋ 전 고니님이 자바스크립트를 잘한다고 생각했었는데..

------------------------------------------------------------------------------------
var obj1 = new Object;
var obj2 = {};
alert(obj1.constructor === obj2.constructor);

의 결과는 true입니다. 두 객체의 생성자는 완전히 똑같은 객체이며

alert(obj1.constructor === Object);

에서 보다시피 그것은 Object 입니다.
-------------------------------------------------------------------------------------
3. Object 역시 Function의 인스턴스입니다.
    따라서 객체타입으로서의 역할을 충분히 한다고 생각합니다
-------------------------------------------------------------------------------------
지금 객체 타입으로서의 객체와 인스턴스로서의 객체를 혼동하고 계십니다. 으하하...
-------------------------------------------------------------------------------------

와 같이 주장하고 있는것은 Object 역시 Function 의 인스턴스라고 생각하시는분의
생각은 객체와 인스턴스로서의 객체를 잘 이해하고 있는것만은 아닌거 같은데요..^^ ㅋㅋㅋㅋ

자신의 논리로 자신의 논리를 부정하는것처럼 보여지는데요..^^ 전...

constructor 로 Object 를 비교하면서 Object.constructor 로 표현하니 당연히 아니다라는 말인가?

그럼 고니님의 논리인 객체의 인스턴스로써의 constructor 로 표현하면 맞나요? ㅎㅎ

alert(new Object().constructor.constructor === Function);
alert(new Object().constructor.constructor === new Array().constructor.constructor);

돌려치나 매치나..ㅋㅋ constructor 로 비교하는것 자체가 고니님이 주장하는 게 틀린게 아닐까요?ㅎ
예제를 들어 표현한건데요..^^; 참 이상하게 받아들으시네..ㅋ

전 prototype chain 자체를 이해하지 못하는것처럼 보이는데요..^^ㅎㅎㅎ

고니님의 주장대로 하면 new Object() 의 본질은 Function 인가 봅니다. ㅎㅎ


ps . 전 주장의 근거가 계속 바뀌는 고니님이 재미있는데요.. ㅎㅎ

ps2. 개콘나가셔도 될듯하네요.. ㅎㅎㅎㅎ
                         
   행복한고니   07-03-27 19:05  
숨어지내리 //
객체지향도 모르고, 타입으로서의 객체와 인스턴스로서의 객체를 혼동하고 계시니... 안타깝습니다. 어찌 그리 자기 주장만 보고 사시는지... ㅎㅎ

Object, Array, Function, Date 등은 "객체타입"이라는 본질이 같은 겁니다. 아시겠습니까? 지금 님이 하신 행동은 말이죠. A라는 사람과 B라는 사람이 "사람"이라는 것을 증명해놓고 "둘 다 사람이라고 A와 B가 같은 사람이냐?" 라고 묻는 것과 같은 겁니다.

제가 증명하던게 그거였나요?
제가 증명하던 것은 A와 B가 둘 다 "사람"이라는 그 자체다 이겁니다. new Object와 {}의 constructor가 같아서 둘 다 같은 종류의 객체이며 값에 대한 특성은 굳이 따져보지 않아도 같음을 알지않습니까?

new Object의 본질은 "Object"라는 것이고요,
Object의 본질이 Function의 인스턴스로 표현되는 "객체타입"이라는 겁니다.

자바스크립트에는 타입의 Object 타입이 상위에 있는 것을 제외하고는 상속이 없습니다. 객체타입은 반드시 Function의 인스턴스가 되어야만 하죠.
따라서 현재 객체의 constructor는 인스턴스의 본질이 될 수 있지만, 어떠한 타입이라도 constructor를 두번 하게 되면 Function이 됩니다. 그 때는 하위객체와 상관없이 타입 객체 자체의 타입을 따지는거죠. constuctor를 두번 사용했다고 그 객체의 본질이 되는 것도 아니고, constructor를 따져보아 현재 인스턴스의 성질을 아는 겁니다.

(new Object).constructor 를 하게되면 new Object 자체의 성질을 묻는 것이고,
(new Object).constructor.constructor 를 하게되면 (new Object 타입객체라는 인스턴스)의 성질을 묻는 겁니다.

그냥 에러없이 실행되니까 헷갈리시죠? 이게 타입으로서인지 인스턴스로서인지도 모르고, 그냥 어찌어찌 봐도 말이 되는 것 같으니까 본인의 생각이 옳다고 생각하시는 모양인데, 그게 아니라 이겁니다.

function 이 함수 자체로서도 사용할 수도 있고, 타입으로서 사용될 수도 있는 자바스크립트의 특징을 잘 이해나 하고 있나 모르겠군요.

PS1// 추가로, 문법적인 차이말고 {}와 new Object가 어떻게 다른지는 근거가 없는 걸로 기억하는군요. 어설픈 우기기나 하지 마시고 본인의 주장이나 증명하세요.

PS2// 걱정마세요. 전 자바스크립트만으로도 잘 먹고 잘 살고 있습니다.
                         
   행복한고니   07-03-27 19:15  
prototype chain 이라는 단어를 잘 모르고 사용하시는 것 같아서 예제를 드리죠. 왜 constructor를 두번 이상하면 안되는지요.

Function.prototype.aa = "aa";
Object.prototype.bb = "cc";
var obj = new Object;

alert(Object.aa);
alert(obj.aa);
alert(obj.bb);

타입으로서의 객체와 인스턴스로의 객체타입을 혼동하지 마시기 바랍니다.
                         
   숨어지내리   07-03-27 20:00  
ㅋㅋㅋ 아 2번하면 성질을 나타내는군요.. 고니님이 말하신 본질!!
-----------------------------------------------------------------------------------------------------------
지금 논리적인 착각을 하고 계시는 듯 해서 정리해드리면요. "용도"와 "모양"은 그 사물의 "본질"을 결정짓는 절대적인 요소가 아닙니다. 오히려 "성질"이 본질을 결정짓는 중요한 요소인거죠.
----------------------------------------------------------------------------------------------------------

A 가 B 와 같고 B 와 C 가 같다면 A != C 다르다고 생각하는 이유가 머죠? ㅎㅎㅎ

new Object().constructor === Object 라고 본질을 주장하시는 분이
여태 본질을 물으려고 이렇게 예제를 보여주신거 아닌가요?

전 new Object().constructor.constructor == new Array().constructor.constructor

가 같으니, A = C 가 같아야 되는거 아닌가요?

constructor 만으로 비교하시는것 자체가 잘못된거라 생각안하세요?

new Object().constructor.constructor 의

1번 constructor 하는 것과 2번하는것의 차이가 있는줄 이제야 알았네요.. ㅋㅋㅋ
constructor 라 지칭하는게 서로 다르다는 얘기네요..ㅋㅋㅋㅋㅋㅋㅋㅋ

JAVASCRIPT 의 특수성이라 우기지 마세요..ㅋㅋㅋㅋㅋ

엄연히 prototype chain 이란 명이 있습니다.
전 prototype chain 의 특성이라 생각합니다.

Object.prototype.a = "a";
alert(Array.a);
alert(Function.a);
alert(Number.a);
alert(String.a);

ㅋㅋ 인스턴스가 아닌 객체자신인데, 서로 통하네요..캬~

이게 prototype chain 이 아닐까요? ㅋㅋ

prototype chain 에 대해 더 공부하세요.

성질을 묻는다고 말하지도 마세요.... 공부하세요.!!

ㅋㅋㅋㅋㅋㅋㅋ


ps. 주관적인 생각을 심어주시네요..ㅋㅋ
--------------------------------------
자바스크립트에는 타입의 Object 타입이 상위에 있는 것을 제외하고는 상속이 없습니다. 객체타입은 반드시 Function의 인스턴스가 되어야만 하죠.
--------------------------------------
위의 것은 prototype chain 이란것으로 설명할수 있습니다. ㅋㅋ

Object 가 최상위라는것은 이미 계속적으로 제가 말한 상태이고요..^^;ㅋㅋ

ps2. ㅋㅋㅋ 이미 고니님의 주장은 설득력을 상실하였습니다.

ps3. 개콘pd 분 소개시켜줘야겠다...ㅋㅋㅋㅋ
   행복한고니   07-03-27 20:06  
너무 길어졌군요. 다시 적어드리죠.

1. 일단 2차 상속이라는게 자바스크립트에는 없습니다. 설명은 위에서 밝혔으니 따로 하지 않겠습니다(코드만 봐도 충분하다 봅니다). 따라서 constructor 를 두번 비교하는 것은 위에서 제가 말했던 대로 님의 착각에서 비롯된 것입니다.

2. constructor 는 해당 인스턴스의 객체구조를 알 수 있게 합니다. 이 때 객체구조의 정의는 반드시 Function의 인스턴스여야 합니다.

3. Array, Date, Object 등은 객체구조로서 볼 때는 그저 구조를 정의한 객체타입일 뿐입니다. 그 자체가 인스턴스가 아닌 단지 타입이므로, "객체타입"이라는 본질에서 그들은 모두 같은 성질을 가지고 있습니다.

4. 자바스크립트에서는 객체타입이 곧 Function의 인스턴스이기도 하므로, 헷갈릴 수 있겠지만 Array, Date, Object 내장 객체자체의 데이터 구조는 다르지 않습니다. 다만 생성자 함수이기 때문에 이들이 정의하는 인스턴스들의 객체구조는 서로 다릅니다.

5. Array, Date, Object의 타입도 모두 같고, 이들이 서로 다른 객체구조를 정의하기 위해 사용되었을 지언정 인스턴스로서의 구조는 같습니다. 그것은 즉, Function 생성자에서 정의한 객체구조와 동일합니다.

6. new Object와 {}는 객체타입이 아니므로 인스턴스로서만 봅니다. 인스턴스로서만 봤을 때, new Object와 {}은 같은 생성자 Object에서 정의된 객체구조를 가집니다. 문법적인 차이만 있을 뿐 두가지는 서로 같습니다. 편의성을 위해 alias된 문법이 있다고 그게 본질을 결정하는 것은 아닙니다.

7. prototype 은 생성자에만 사용할 수 있으며, 생성자 함수로 생성될 인스턴스의 객체구조를 정의합니다. Object, Function 은 모두 생성자 함수이므로 prototype의 사용이 가능하지만, new Object는 prototype이라는 속성이 없습니다.

객체 타입인지, 인스턴스인지 헷갈려서 자신이 잘못이해한 것을 마치 진실인양 받아들이지 마시기 바랍니다.

P.S// 위에서 Object.prototype 을 정의할 수 있는 것은 Object 객체 자체가 아니라 Object가 생성자 함수이기 때문입니다. 7번에 적은 이유때문이죠. prototype chain 의 의미를 잘 모르고 있다는 것은 이미 알고 있으니 다시 안 밝히셔도 됩니다.
   무소레즈   07-03-27 20:08  
constructor의 객체타입이 같다고 instance 개체가 같다고 할 수는 없지 않을까 합니다.
instance 는 같아도 constructor 는 달라질 수 있습니다.

엄밀히 말하자면, instance 는 같아도 instance 개체는 다릅니다.
같은 instance 라해도  실체화된 instance 개체의 constructor 는 달라질 수 있기때문입니다.

instance 개체 생성시 실행되는 객체 함수내부에서의 초기 조건에따라
서로 다른 생성자를 가진 서로다른 instance 개체가 생성될 수 있습니다.

예를 들어, 임의 빈 함수 price 를 만들고 
new 를 통하여 meat 라는 임의 개체변수로 instance 개체를 생성하면

meat 의 constructor 는 함수타입의 price 가 되고
meat 의 instance 는 함수객체 price 타입의 instance 이기도 하며
또한 new 를 통해 생성하였기에 Object 타입 의 instance 이기도 합니다.

하지만,

function price(cond) {
    if(cond) this.constructor=(new Date).constructor;
    else this.constructor=(new Function).constructor;
    return this;
}

var meat1=price(0);
var meat2=price(1);

으로 instance 개체 두개를 생성했을때..

meat1 과 meat2  의 instance 를 보면,
price 객체타입의 instance 이며, Object 객체타입의 instance 이기도 합니다.
같은 instance 를 갖기만  instance 개체가 같다는 말은 아닙니다.

meat1 의 constructor 는 Date 함수 객체타입이지만
meat2 의 constructor 는 Function 함수 객체타입이 됩니다.


constructor 는 다르지만 instance 가 같습니다.
다시한번 얘기하지만 instance 가 같다는 것이
  instance 개체가 같다는 의미는 전혀 아닙니다.

instance 라는 것은 constructor 함수 내부의 조건별 환경과는 무관하게
instance 개체 생성시에 어떤 객체타입의 instance 인가만을 알려준다는 것입니다.

constructor 체크와 instance 체크는
단지 어떤 객체타입의 constructor 인가,
또는 어느 객체타입의 instance 를 가졌는가를 확인하기위한 것일뿐
실체로서의 instance 개체의 동질성을 판단해주지는 못합니다.

instance 는 같을 수 있을지라도 instance 개체는 분명히 다릅니다.
또한, 사용자 정의 함수 객체의 내부 제어에따라 instance 까지도 변경이 가능합니다.
     
   숨어지내리   07-03-27 20:11  
동의 합니다.!!
          
   행복한고니   07-03-27 20:17  
아래글 다 안읽고 동의하시면 후회할 겁니다. :)
               
   숨어지내리   07-03-27 20:24  
ㅋㅋㅋㅋㅋㅋ 네 :)
                    
   행복한고니   07-03-27 20:27  
아.. .윗글에 자바스크립트의 특성에 대해서 간략하게 썼으니 보고 공부하세요.
모르는 건 죄가 아니지만, 모르면서도 안다고 우기는 것은 좋지 않죠.
                         
   숨어지내리   07-03-27 20:37  
ㅋㅋㅋㅋㅋㅋㅋ 네 :)
     
   행복한고니   07-03-27 20:16  
예제가 잘못되었습니다.
내장 메소드, 객체까지 덮어씌울 수 있는 자바스크립트의 특성상 그렇게 보일 뿐입니다.

return this 하기전에, this.constructor = 1; 도 해보세요. 되나 안되나. ^^

그리고 price(0) <- 이렇게 한 것은 price가 객체의 생성자로서 사용된 것이 아닌 단순한 함수의 실행입니다. 단순한 함수의 실행은 생성자 함수로서 인정밭지 못하기 때문에 this가 가리키는 것은 함수자체가 아닌 window 객체가 됩니다.

price.prototype을 해도 그곳에 정의된 자료구조가 meat1에는 적용되지 않는 것도 물론이고요.

제 말이 맞는지 틀린지 테스트해보세요.
this.constructor 가 덮어씌워져서 그렇게 되는 것처럼 보일 뿐입니다. 무소레즈님께서 작성한 코드 아래에 다음과 같이 실행해보세요. ^^

alert(meat1.constructor);
alert(meat2.constructor);

meat1과 meat2는 독립적인 객체도 아닐 뿐더러 price에 의해 생성된 인스턴스는 더더군다나 아닙니다. 아... 그리고 덮어씌웠다고 한들 그게 생성자로서의 역할을 하는 것도 아닙니다.

var obj = new Object; alert(obj.__proto__ === Object.prototype); 이지만
위 예제에서 meat1.constructor === Date.prototype 은 아닙니다.

constructor가 그 인스턴스 객체의 성질과 자료구조를 결정짓는 겁니다.
   무소레즈   07-03-27 20:30  
글 작성시 소스를 제대로 작성치 못했군요... 수정합니다.

function price(cond) {
    if(cond) this.constructor=(new Date).constructor;
    else this.constructor=(new Function).constructor;
    return this;
}

var meat1=new price(0);
var meat2=new price(1);

이것이 맞습니다.
다시 테스트 해보시지요.
     
   행복한고니   07-03-27 20:34  
그게... 위에서도 말했지만, 프로퍼티를 재정의할 수 있는 자바스크립트의 특성때문입니다.
return this 위에 this.constructor=1 이라고 해도 된다고 말씀도 드렸는데요. ^^;;

alert(meat1 instanceof Date);
alert(meat1 instanceof price);

설령 constructor라는 속성을 재정의 한 것처럼 보일지라도 meat1은 여전히 price의 인스턴스입니다.
   무소레즈   07-03-27 21:18  
instance 와  instance 개체가 다르다는 것에대해 얘기를 했고, 그와 관련되 예문을 보여 드린것인데
instance 가 다르다느니 하는 얘기는 엉뚱하게 들립니다.
instance 가 같아도 instance 개체는 항상 같지 않다는 것에대해 얘기한것입니다.
instance 와 instance 개체를 혼동하지 않았으면 하는 의미였지요.

추측을 기반으로 참여하였지만, 재미도 있겠다 싶어 시작한 얘기들이
말하고자 하는 바에대한 얘기를 벗어나는 댓글만 나오는것 같군요.
     
   행복한고니   07-03-27 21:26  
무슨 말씀인지 이해가 안됩니다.

price 는 meat1의 생성자이고
meat1은 price의 인스턴스입니다.

이 사실은 설령 meat1의 constructor 속성이 재정의 된 것처럼 보이더라도 변하지 않습니다. 재정의 된 것처럼 보일 뿐 실제로 instanceof 등의 연산자로 체크해보면 변하지 않았음을 알 수 있습니다.

용어혼동이 와서 그러는데, 클래스/인스턴스 혹은 객체타입/인스턴스 라는 용어로 다시 정리해주시겠습니까? "instance" 와 "instance 개체"가 각각 의미하는 것이 무엇인지 애매하네요.

자바스크립트는 미리 정의된 속성도 재정의 할 수 있는 무척 유연한 언어입니다. constructor 속성을 강제로 재정의 한 것이 그게 재정의 된 것처럼 보일지라도 실제로 내부적으로는 재정의가 된 것이 아니라는 의미로 코드를 드렸습니다.

그래서 , constructor 속성을 재정의 했을지라도 여전히 meat1은 price의 인스턴스임을 증명해드렸습니다. 무엇이 벗어났다는 것인지 모르겠습니다.
   숨어지내리   07-03-27 21:32  
ㅋㅋㅋㅋㅋㅋ 재미있군요..^^; 이렇게 까지는 하기 싫었는데..

---------------------------------------------------------------------------------------------------------------------------
PS1// 추가로, 문법적인 차이말고 {}와 new Object가 어떻게 다른지는 근거가 없는 걸로 기억하는군요. 어설픈 우기기나 하지 마시고 본인의 주장이나 증명하세요.

PS2// 걱정마세요. 전 자바스크립트만으로도 잘 먹고 잘 살고 있습니다.
---------------------------------------------------------------------------------------------------------------------------

고니님은 new Object() === {} 는 같다. 라고 하셨는데.. 완전히 주관이었던게 드러났습니다.

delete Object;
alert({});               
alert(new Object());


위의 코드가 증명해 주고 있습니다.

아까도 말했듯이 constructor 로 비교하는것 자체가 무리가 있다고 하지 않았나요? ㅋㅋㅋㅋ


참 재미있는 토론입니다. !! 아니 말장난입니다. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ


아.. 고니님 먹고 살기 힘드시겠습니다... ㅋㅋㅋ

객체를 삭제하면 new Object() 는 에러가 납니다.

허나 literal 은 본연의 임무를 충실히 시행하네요. .ㅋㅋㅋㅋㅋㅋㅋㅋㅋ

아직도 자기 주관을 남에게 이관시킬 작정입니까? ㅋㅋㅋㅋ

저것도 반문해 보시지요???

저것도 JAVASCRIPT 의 특징 아니!! 특.수.성 입니까????????????????????????

또 본질은 같다? ㅋㅋㅋㅋㅋㅋㅋ

자신의 우둔함과 교만, 주장을 남에게 설파하는것밖으로는 안보이는군요. 믿어라

믿는자에게 복이 있나니..ㅋㅋㅋ


ps. 자.. 행복한 고니님을 개콘으로~

ps2. 저 JAVASCRIPT 잘못합니다. ^^; 헌데.. 고니님도 못하시는듯 합니다. ㅋㅋ


ps3. 정말 이렇게 까진 하기싫었지만, 전 고니님이 다음의 내용을 실천하시거라 생각합니다.

-----------------------------
아뇨. 정말로 틀렸다는 것을 증명해주시기를 바라고 있습니다.
원하신다면 문서로 만들어서 대중의 심판을 받을 각오도 되어있습니다.

여태까지 주신 근거는 제가 아니라고 반박해드렸습니다.
애매한 태도로 제가 우긴 것처럼 하지 마시고요, 정확하게 논거를 들어주시기 바랍니다.

틀렸으면 깨끗이 인정을 하시던가 그렇지 않으면 "내부적으로는 다르다" 는 것에 대한 증거를 보여주셨으면 합니다. 지금과 같은 태도는 별로 바람직하지 않다고 봅니다. 본질을 흐렸다고 생각하지 않고 있는데, 본질은 무엇이며 어떻게 흐렸는지도 좀 알려주시고요. 인정하기 싫으신건지는 모르겠지만, 어쨌든 간곡히 부탁드립니다
-------------------------------
     
   행복한고니   07-03-27 21:41  
브라우저를 IE만 쓰시나봐요?
여태까지는 Mozilla 에만 있는 set, get 을 특징으로 드시더니요? ^^

FF에서 해보세요. :)
아... 참고로 모질라 재단에 자바스크립트의 창시자인 Brendan Eich 씨가 있는 것은 아시죠?
게다가 IE에서 사용되는 것은 자기들도 스스로 JavaScript가 아닌 JScript 라 부른다는 사실~ 아시고 계시죠? ^^

테스트 할 때는 좀 다양하게 해보세요.
제일 처음의 코드부터, Create by도 딸랑 하나만 보고 근거로 삼질 않나, 이번에도 딸랑 IE에서만 해보고 "앗싸, 이거다"라는 마음에 테스트도 안해보고... ㅎㅎ

PS// 제가 님보다 많이 벌걸요? 제 생계는 걱정마세요. ^^
          
   숨어지내리   07-03-27 21:47  
ㅋㅋㅋㅋㅋ 아직도 인정을 안하시네..ㅋㅋ

고집하나 대단 하십니다..ㅋㅋㅋ

Brendan Eich 이분이 M$로 가면 말이 되는건가요? ㅋㅋㅋㅋㅋㅋㅋ

논리적인 부분의 비약이 드러납니다.ㅋ
               
   행복한고니   07-03-27 21:52  
Mozilla specific 은 누가 먼저 예로 들었는지 말안해도 아실텐데요? :)

게다가 우리가 서로 근거로 삼고 있는 문서또한 MDC 문서였구요.
http://en.wikipedia.org/wiki/JScript

JScript는 Microsoft에서 만든 ECMA 스크립트 언어의 하나로 "Approx. JavaScript" 라고만 나와있습니다. 자신의 근거가 힘을 받지 못하니 "제 고집"이 되는거군요. 자신이 끈질기게 근거로 들었던 부분이 얼마나 JScript와 호환되는지부터 살펴보고 그런 말씀을 해주세요.

우리 지금 javascript 에 대해서 말하고 있는 게 아니었나요?
참 재밌군요. 저 승리감에 도취된 말투라니... ㅎㅎ

아.. Eich 씨요.. 모질라의 CTO 이십니다. ^^
______________________________________________
자기가 모질라에서만 특징적인 것으로 근거를 들 때는 그게 논리적인 근거가 되고,
제가 IE는 JScript는 JavaScript가 아니다라고 하니까 고집이 되는군요.
내가 하면 로맨스, 남이 하면 불륜? ㅎㅎ

더 그럴 듯 한걸로 가져오세요. 이제 다 떨어졌나요? ^^
                    
   숨어지내리   07-03-27 21:57  
"재밌네요. 어거지도 이만하면 상줄만 합니다. " 이말이 생각납니다.
                         
   행복한고니   07-03-27 22:02  
저는 위에서 적은 말 말고도 "똥묻은 개가 겨묻은 개 나무란다"는 말이 생각나는군요.

기껏 근거로 드는 코드라는게 인스턴스와 생성자로서의 역할도 모르고, 상속도 모르고, prototype chain에 대한 이해도 없이 자신이 헷갈려놓고 마치 진실인 양 하더니,

이제는 JScript 에 있는 특징을 보고 "이게 Javascript의 진실이다"라고 하질 않나,

자신이 저~~ 위에서부터 set, get 과 같은 Mozill에 특징적인 스펙을 설명할 때는, MDC의 문서를 근거로 들 때는 생각지도 못하고 이제와서 JScript의 스펙이라고 말하는 사람에게 "고집"이라는 둥, "어거지"라는 둥,

억울하면 증명하세요.
                    
   숨어지내리   07-03-27 22:01  
전, 일관된 주장...  new Object() 와 {} 가 똑같을지 의문이 듭니다. ㅋㅋㅋ

비슷하다, 동일하다, 하는역할이 같다, 인스턴스를 반환한다. 정도이지,

똑같다라는 표현 ... 참 어색하기 그지없습니다. .ㅡㅡ;ㅋㅋ
                         
   행복한고니   07-03-27 22:06  
저도 일관된 주장.

{}는 new Object 를 편하게 사용하기 위한(특히 property를 설정할 때), 문법적인 alias일 뿐이다.

new Function 객체가 있어도 function 선언으로 함수를 만들 수 있죠. 하지만 뭘로 만들건 같은 특징과 성질을 가지는 "함수"일 뿐입니다.

용도는 달라도, 문법적인 모양은 달라도 결국은 똑같은 "함수", 똑같은 "Object".

문법적인 차이는 3살짜리 꼬맹이가 봐도 생긴게 다르니 당연히 다르죠. 하지만 "본질" 혹은 "특징"이 다르다는 근거는 아직 못봤네요. 계속 일관된 고집만 보여요.

___________________________

아... 개콘 PD 아시면 방청권 하나 부탁합니다.
아직 가본적이 없네요. :)
                         
   숨어지내리   07-03-27 22:27  
ㅋㅋ 또, 문법적인 alias 로 되어 있네요.. ^^;;

매회 바뀌는 주장들... 이젠 고만하시죠. 읽는 분들에게 뭇매 맞습니다. ㅡㅡ;


전 판단은 읽으신 분들이 하실거라 생각합니다.

전 할만큼 다했습니다. ^^;;;;;;;;;;;ㅋㅋㅋㅋㅋ

똑같다라는 표현... 이젠 자제해 주세요.

http://zeldign.com/tt/38

위의 입장이니, 보시는분들에게 판단을 돌리죠 ? 고니님..^^;



참고: http://zeldign.com/tt/39
        액션스크립트에서 {} 과 new Object() 퍼포먼스 테스트한 결과라는데,
        다들 참고하시면 좋을거 같네요. ^^.
        이건 테스트한 분의 주관이 포함된 것이니, 알아서들 판단하셔야 합니다.^^
                         
   행복한고니   07-03-27 22:32  
제 글 안 읽으시는군요.
alias는 저~~~기 위에도 있습니다. 이 페이지에서 alias로 검색해보세요.

저는 말과 행동이 다른 누군가가 아니라서요. ^^
과연 이제 정말로 안오려나... ㅋㅋ 또 두고보죠 뭐

제가 왜 자제하죠? 저도 할만큼 했는데요.
"내부적으로 다르다"라는 명제를 증명하지 못한 사람은 제가 아닌걸요? :)
그냥 그렇게 생각하고 사시라는 말, 또 합니다. 그냥 그렇게 생각하고 사세요.

결론 : {}과 new Object는 똑같은 표현입니다.


// JScript를 JavaScript로 보고 "증명해냈다"라고 하는 모습이, 참...-_-;;
                         
   숨어지내리   07-03-27 22:45  
ㅋㅋㅋㅋㅋㅋ 네 :)

고니님의 주장 적절히 판단하겠습니다. ^^

수고하셨습니다.
                         
   행복한고니   07-03-27 22:54  
아... IE에서는 증명하셨다 그랬죠?

var o = Object;
delete Object;
alert({});
alert(new o);
alert( ({}).constructor === (new o).constructor);

이것도 한번 테스트 해주세요.
사라진 Object 객체가 어떻게 생성자로서의 역할을 할 수 있을까요? ^^
과연 이게 Object 객체가 사라진 것일까요, 아니면 명시적인 선언만 안되게 해놓은 IE의 특징일까요? 판단은 다른 분들이 알아서 하시겠죠. :)

필요하시면 블로그에 퍼가도 좋습니다. ㅋㅋ

수고하셨습니다. (__)
아마도 또 답글이 달릴 것 같지만... 어쨌거나요 ㅎㅎ
                         
   숨어지내리   07-03-27 23:18  
아직도 객체,상속,생성자를 이해하고 있지 않은듯 합니다. ^^ㅋㅋㅋ

constructor 로 비교하시지 말라 그래도..ㅋㅋ

잘 생각해보세요.. ^^ㅋㅋㅋㅋ 삭제못하게 만드려고 var 를 붙였네요.ㅋㅋ

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Special_Operators:delete_Operator

x=42
var y= 43
myobj=new Number()
myobj.h=4      // create property h
delete x      // returns true (can delete if declared implicitly)
delete y      // returns false (cannot delete if declared with var)
delete Math.PI // returns false (cannot delete predefined properties)
delete myobj.h // returns true (can delete user-defined properties)
delete myobj  // returns true (can delete objects)


지금 퀴즈하자는 겁니까? ㅋㅋㅋ 재미없습니다.
사용방법도 모르고 왜그러냐니..ㅡㅡ;

한심합니다..

언능 주무세요.. 오늘 회사도 이것때문에 안나갔습니다. ^^ㅋㅋㅋ

for(var i = 0 ; i < 100 ; ++i) { 행복한고니 = "수고하셨습니다."; }

수고하세요.~~~~
                         
   행복한고니   07-03-27 23:22  
ㅋㅋ 그렇게 나올 줄 알았죠.
이번엔 또 MDC 문서로군요! var 도 빼고 한번 해보세요. ^^ 물론, 해보시고 저한테 "한심하다"고 하신거겠죠?

아... 다음 코드도 한번~ ^^
var o1 = new Object;
delete Object;
var o2 = {};
alert(o1.constructor == o2.constructor);
alert(o2 instanceof o1.constructor);

Object는 삭제되었을텐데, 두 객체의 constructor가 같다고도 하고, o2 는 o1의 생성자의 인스턴스가 맞다는데 이걸 어떻게 해석해야 할까요?

___________________________________________

이것때문에 잠도 못자고 회사도 안나가고 바쁘시네요. :)
전 잠도 잘자고 일도 많이했는데요. 아... 스터디도 진행했었군요. ^^
                         
   숨어지내리   07-03-27 23:40  
ㅋㅋㅋ

재미있습니다. ^^ 지지 않으려고.. 지푸라기 잡는거..ㅋㅋㅋ

var o1 = new Object; // 상속처리
delete Object;  // 삭제
var o2 = {};
alert(o1.constructor === o2.constructor);

Object 를 delete 하기전에 이미 상속을 받았으니
constructor 라는 값을 가지고 있는거지요..ㅋㅋㅋㅋ

상속에 대해 진정 모릅니까? ㅋㅋㅋ 헛발 디디라고 하나이까??ㅋㅋㅋ

미치겠네요.. 정말..ㅋㅋㅋ 이젠 한계에 도달합니다.


delete Object;  // 삭제
var o1 = new Object; // 상속처리 -> 에러..객체없음
var o2 = {};
alert(o1.constructor === o2.constructor);

ie 에서 이게 동작을 하지 않는데...ㅋㅋㅋ 재미있네요..ㅋㅋ
무슨 의미가 있나요? ㅋㅋㅋㅋㅋ
                         
   행복한고니   07-03-28 00:00  
역시.. 이해할 거라곤 기대하지도 않았습니다.
우선 또 오해가 있기전에 정리부터 하죠. 객관식으로 드리겠습니다.

Object를 삭제했는데, new Object가 안되고 {}가 되는 것은 fact입니다.
이것이 의미하는 바가 무엇입니까?

1. new Object는 Object객체를 사용하지만, {}는 그렇지 않다.
2. new Object는 안되고 {}는 되니까 그것만으로도 다르다는게 증명된다.
3. 기타 의견

저는 희한하게도 Object 객체를 삭제했는데도 {}가 여전히 Object의 인스턴스라는 점을 말하고 있을 뿐입니다. 그래서 희한하다고 한거죠.

Object가 constructor에 있다고 칩시다.
그러면 어떻게 {}는 다시 Object의 인스턴스가 될 수 있었을까요?
Object는 정말로 삭제된 것일까요, 남아있는데도 삭제된 것으로 취급하는 IE가 이상한 것일까요?

Object가 삭제되었는데 어째서 {}는 Object의 인스턴스가 될 수 있느냐를 묻는거였는데요. instanceof 는 왜 쏙 빼먹고 말씀안하시나요? ^^ 유리한 것만 하지 마시고, 다른 것도 말씀하셔야죠.

제 의도는 있는 것을 없다하는 IE를 얘기하고 있을 뿐입니다. 저는 님의 의도대로 IE가 동작해준게 과연 정상적인지, 버그 혹은 오동작인지에 대해서 의문을 제가하는 겁니다.
                         
   숨어지내리   07-03-28 00:31  
ㅋㅋㅋㅋㅋ 이젠 버그이군요.. 주관적인 생각을 주입시켜주셔서 감사드립니다.
캬캬캬..^^;
                         
   행복한고니   07-03-28 00:37  
아... 님에게 JScript를 지원하는 IE는 JavaScript의 완벽한 표본이군요.

그럼요. IE의 CSS, 렌더링, 메모리 릭 등을 포함한 버그들도 다 IE가 틀린게 아니죠. IE는 완벽하니 다른 브라우저가 잘못된 것이죠. 그말이 옳습니다 ㅎㅎ

그럼 그냥 그렇게 생각하세요.
개발자로서 아주 훌륭한 마인드입니다.

이해할 수 없는 현상에 대해 문제제기를 하는게 "지극히 주관적인 현상"이었군요.

아직도 intanceof 가 왜 그렇게 나오는가에 대해서는 대답도 못하고 자기 말이 옳다는 것을 증명할 수 있는 사실 하나만 붙잡고(그나마도 JavaScript 호환언어에서) 계시네요. ^^

다른 건 다 제쳐두고,
"이것봐라. 그러니까 내 말이 옳다"만 반복하고 있으시네요. ㅎㅎ

그만 주무세요.
까딱하면 오늘도 못 주무실 수 있겠어요. :)
   낭망백수   07-03-27 22:59  
이 논쟁을 이해하면 경지에 오르는 건가요? ㅎㅎ
대단들 하십니다. ^^
꾸벅~!
   무소레즈   07-03-27 23:15  
meat1 이나 meat2 나 모두 price 함수 객체타입의 instance 입니다.

instance 개체를 생성하면 constructor 로써 price의 초기환경설정이 시작합니다.
constructor 라는 것이 원래 그런 목적으로 만들어진것이니까요.
그렇게 constructor 는 개체의 초기조건과 초기 실행환경을 만들어 줍니다.

주어진 조건이 다르다면  생성된 instance 개체의 실행 행위가 달라집니다.
물론 이렇게 실행환경이 달라지더라도  instance 라는 것은 같습니다.

instance 는 어떤 객체타입의 instance 를 가졌는가를 알려줄 뿐이지만,
instance 객체라는 것은 실체화된 독립적인 개체로서
주어진 객체타입에서 설계된 구조의 제어대로 실행을 하는 실체입니다.

예문에서 보면,
instance 객체 생성시 초기 생성자 함수가 비록 price 였지만
price 내부에 들어가면, 주어진 조건에의해 다른 constructor 의 제어를 받습니다.
개체의 새로운 실행 환경이 주어지게 되는것이지요.

그 예문에서 constructor 재설정은 의미는
어떤 객체타입의 실행환경을 가졌는가를 확인하기위한 일종의 안내일뿐입니다.
생성된 instance 개체가 어떤 환경하에서 실행되는지 확인하기 위한것이라는 것이지요.

서로 다른 생성자에의해 다른 환경조건이 주어졌다면
instance 개체는 다른 실행을 하게 된다는 것이지요.



instance 객체를 생성시  초기 생성자 함수 객체타입은
위의 price 함수에서 보여진대로, 조건에따라 내부에서 다른 constructor 를 통하여
새로운 환경을 가지게 됩니다.

처음의 price  생성자가 소멸아닌 소멸이 되어 버리는 것이지요.
이 얘기 역시, 존재는 하지만 실제 실행주체를 위한 생성자가 아니니 소멸이라고 표현한것 뿐입니다.



----------------------------

반복되는 얘기일수도 있지만 행복한 고니님의 글에 답변성 글을 올립니다.
글재주가 부족해서 무슨 말을 어떻게 썼는지 흠...
아뭏든 제가 아는 바는 아래와 같습니다.

----------------------------

-->>
price 는 meat1의 생성자이고
meat1은 price의 인스턴스입니다

<<--
meat1 은 price 함수 객체타입의 인스터스를 가지고 있다... 라고 해야하지 않을까 합니다.
서로 이해하면 되니까 그건 그렇다고 하지요.

price 함수 조건별 제어에의해
meat1 의 생성자가 price 가 되지 않도록 할 수도 있습니다.
생성자란것이 초기 실행 환경설정의 주체이기때문에
constructor 의 재정의가 아닌 조건별 constructor 의 선택에의해 실행환경을 바꿀수 있습니다.

-->>
이 사실은 설령 meat1의 constructor가 재정의 된 것처럼 보이더라도 변하지 않습니다. 재정의 된 것처럼 보일 뿐이죠.

<<--
재정의된것처럼 보이는것도 맞습니다.. 그렇게 요청시에 안내만 해준것 뿐입니다.
(개체.constructor) 의 확인 목적은 instance 개체가 생성자(객체타입)의 어떤 초기 실행 환경을 가졌는지를 알기 위함이라고 알고 있습니다.


<<--
function price (){}
meat = new price;


  객체타입

price 는 함수 객체타입인 생성자 입니다. 실행환경과 실행구조를 정의합니다.
price 함수객체 내부에는 조건별 생성자와 그에따른 실제 행위를 할 method 의 구조를 정의할수도 있습니다.

    인스턴스

instance 는 어떤 객체타입인가를 얘기합니다.
meat 의 instance 는  "function price (){}" 입니다.
즉, meta 는 함수객체 price 타입의 instance 를 가졌다고 말할 수 있습니다.
또한, new 를 통해 instance 개체를 생성하면 새로 생성된 instance 개체의 instance는 자동으로 함수객체 Object 타입을 갖게 됩니다.


    인스턴스 개체

meat 는 instance 개체입니다. instance 가 아닌 해당 객체타입의 instance 를 가진 개체입니다.
instance 개체는  해당 생성자에서 주어진 환경설정과 실행명령에의해
직접 실행을 하게 되는 실행주체입니다.
     
   행복한고니   07-03-27 23:29  
여태껏 제가 했던 주장을 instanceof 연산자를 사용해서 한다해도 다 똑같은 결과가 나옵니다.

유연함으로 인해 재설정이 가능한 것과 실제 성질이 그러한 것을 혼동하시는 것 같습니다. 최초에 만들어진 meat1은 분명 price라는 contructor를 가지고 있었으나 price 내부에서 유연함을 이용해 재설정 해버린 것입니다.

제가 요구하는게 재설정이 가능한지를 묻는 것이었던 것은 아닌걸 아실텐데요.
constructor가 재설정이 가능하기 때문에 신뢰성이 없다면, instanceof 연산자를 가지고 바꾸어 생각하셔도 좋습니다.

언어의 유연함을 이용해 constructor를 강제로 바꾸고서 "constructor속성이 달라졌으니 생성자가 다르다"라고 말할 수 있을지 의문입니다.

아... 그리고.. constructor가 바뀐다고 님의 표현대로인 "실행환경" 혹은 제 표현인 "타입/성질"이 바뀌는 것은 아닙니다.

function class1(){ this.aa = "b"; }
function class2(){ this.aa = "c"; }

var a = new class1();
alert(a.constructor);
alert(a.aa);

a.constructor = class2;
alert(a.constructor);
alert(a.aa);

이렇게 하면 답변이 될까요?
          
   무소레즈   07-03-28 10:43  
설명이 필요하여 보여드린 소스에 달랑 (객체.constructor) 만 구현되어 있어서
constructor 에대한 언급시 constructor 함수객체와 혼동이 있으신것 같군요.
생성자가 다르게 구현되는 좀 더 구체적인 예제 소스를 작성해 보지요.
   무소레즈   07-03-27 23:40  
글의 의도된 의미를 거듭 얘기했어도 의미전달이 제대로 되어지고 있지 않군요.
앨리스가 된 기분...
가능하다면 내가 작성한 글을 모두 삭제해 버리고 싶네요..
운영자님이 보시면.. 삭제좀 해줬으면 좋겠어요.
     
   행복한고니   07-03-27 23:52  
인스턴스 부분에서 이해를 잘못하신 것 같네요.

어떤 클래스가 있을 때, 그것은 그냥 구조로만 존재합니다(물론, 자바스크립트에서는 함수 개체로 존재하지만).
그 클래스를 실제로 구현했을 때를 인스턴스라고 합니다.
http://www.terms.co.kr/instance.htm

따라서 meat1의 클래스는 price이고, price의 인스턴스가 meat1 입니다. 이 부분을 오해하신 것 같네요. 님께서 인스턴스 객체라고 말한 것이 제 용어에서 인스턴스이고, 인스턴스라는 개념이 클래스라는 뜻으로 사용된 것 같네요.

자바스크립트에서는 생성자가 곧 객체 타입도 됩니다. 이 부분을 간과하신 것 같네요.
함수 내부에서만 구조가 정의된다고 생각하시겠지만...
price.prototype.someProp = '111';
price.prototype.someFunc = function(){};
과 같이도 정의할 수 있습니다. 따라서, price와 객체의 "실행환경"이라는 것과 별개로 생각하시는 것은 잘못 이해하고 계신겁니다.

대체 인스턴스와 인스턴스 객체가 어떻게 다른지 용어가 다른 문제인데요. 인스턴스 객체를 다른 의미로 사용하는 건 진짜로 첨봤습니다. -_-;;
          
   무소레즈   07-03-28 00:19  
제가 올린 글을 제대로 읽어본 후 표현한 글인지 의심이 가는 답변이로군요.
정말 엉뚱한 답변의 연속입니다.
               
   행복한고니   07-03-28 00:26  
에효... 그냥 그렇다고 해두죠.
무슨 말인지 이해해보려고 해도 이것도 아닌가보군요. 뭔가 다른 소리를 각자 하고 있는 것 같으니 그만두죠 뭐.
   무소레즈   07-03-28 01:10  
행복한 고니님, 숨어지내리님 수고들 하셨습니다.
다음에 이런 공간이 다시 주어지면 보다 덜 소모적인 대화가 진행되었으면 하는 아쉬움이 있습니다만.
그래도 나름 즐거운 시간이었습니다.  ^^

------------------


올린 글을 다시 보니... 인스턴스 부분 설명이 잘못되었네요.

    meat 의 instance 는  "function price (){}" 입니다. 

는 잘못된 글입니다.

    [인스턴스]
    instance 는 어떤 객체타입인가를 얘기합니다.
    meat 의 constructor 는 "function price (){}" 입니다.
    ( meat instanceof price ) 는 true 입니다.
    즉, meat는 함수객체 price 타입의 instance 를 가졌다고 말할 수 있습니다.
    또한, new 를 통해 instance 개체를 생성하면
    새로 생성된 instance 개체의 instance는 자동으로 함수객체 Object 타입을 갖게 됩니다.

로 정정합니다.
   무소레즈   07-03-28 11:16  
function arirang (flag){
    if(flag == 1) {
        a =new Function;
        a.constructor=(new Object).constructor;
        a.run=new Function("return ('arirang - 꽃');");
        return a;
    }
    else {
        b=new Function;
        b.constructor=(new Date).constructor;
        b.run=new Function("return ('arirang - 요일');");
        b.getDayKr=function () {
            return  ['일','월','화','수','목','금','토'][(new Date).getDay()];
        }
        return b;
    }
}

flower= new arirang(1);
week = new arirang(0);

//-----------------------------

function echo (str) {
    if(echo.arguments.length==0) str='';
    if( (s_arr=str.split('::')).length>1 ) str=s_arr[0].bold()+' :: ' + s_arr[1];
    document.write(str+'<br>'); }

echo ('flower.run() :: ' + flower.run() );
echo ('week.run()  :: ' + week.run() );
echo ('week.getDayKr() :: ' + week.getDayKr().concat('요일') );
echo ()
echo ('flower instanceof arirang :: ' +  (flower instanceof arirang ) )
echo ('week instanceof arirang :: ' +  (week instanceof arirang ) );
echo ()
echo ('(flower.constructor == week.constructor) :: ' +  (flower.constructor == week.constructor) )
echo ('flower.constructor :: ' +  (flower.constructor) )
echo ('week.constructor :: ' +  (week.constructor) )
echo ()
echo ('week.constructor === Date.prototype.constructor :: ' + (week.constructor === Date.prototype.constructor ) );
     
   행복한고니   07-03-28 11:29  
아무리봐도 제가 이해하기에는 했던 말을 반복할 수 밖에 없습니다.
어떻게 constructor하고 instance하고 따로 생각할 수 있는지 이해가 안됩니다.

flower가 arirang의 인스턴스라고 이미 instanceof 에서 나왔는데 재정의된 constructor를 비교해봐야 무슨 소용이 있는 줄 모르겠군요. 재정의된 상태에서 constructor를 비교하는 것은 정말 단순한 객체의 비교밖에 안됩니다.

var b = new Function;
b.constructor = Date; // (new Date).constructor는 Date

var d = new Date;

Date.prototype.aa = "aa";

alert(b.aa);
alert(d.aa);

b의 constructor를 강제로 바꿔봤자 b 라는 객체에 영향을 끼치는 것은 최초의 생성자이지, 그 뒤에 constructor라는 속성을 재설정해봐야 소용없다는 말입니다. Date는 b 객체에 대해 아무런 영향도 끼치지 못합니다. 도대체 코드가 의미하는 바를 알 수가 없군요.

제가 드리는 이 명제를 동의하지 못한다면 자바스크립트의 특성을 잘못이해하고 계시는 것이니, 그냥 이쯤에서 그만두는게 좋을 것 같습니다. 자꾸 반복만 할 것 같습니다.

"자바스크립트에서는 생성자가 곧 객체타입입니다."
          
   무소레즈   07-03-28 11:32  
flower가 arirang의 인스턴스라고  나온 부분과 소스를  다시 잘 보시기 바랍니다.
               
   무소레즈   07-03-28 11:39  
상대가 무슨 얘길 하는지 확인하고 답변을 다는것이 좋지 않을까요?
소스를 구현해주고, 보기 편하라고 실행결과까지 구현해주었는데도 ...
그 마저 대충 보고 얘길하면 대화가 되겠습니까?

또한 생성자란 함수 객체여야만 생성이 되는 것이고, 객체타입을 갖는 것이 당연한것을
대단한 것처럼 동의를 구하려 하시는군요.
               
   행복한고니   07-03-28 11:40  
거기까지는 이해했는데, 왜 재설정된 contructor를 비교하는건지 의도파악이 안되서 그런겁니다. 재설정되버린 것은 객체에 아무런 의미도 없는데 왜 비교를 하신건가요?
                    
   무소레즈   07-03-28 11:47  
밥 지어 주니까...밥까지 먹여 달라는 격이로군요..
행복한 고니님이 반론 펴신 내용의 대한 답으로 실행문을 예로 보여준것입니다.
다시 잘 보시고...  무슨 의미인지 나름 판단해보시기 바랍니다.
뭐 어찌되었건 대화이니 대화 그 자체로 지나쳐 버려도 될 일입니다.
오늘따라 날이 찌뿌둥 하군요.
                         
   행복한고니   07-03-28 12:06  
제 의도를 정리해드리죠.

"인스턴스를 만들고 난 이후에 constructor를 재설정해도 그것은 이미 생성자로서의 의미를 가지지 못하며, 재설정되는 것은 단순히 자바스크립트의 유연성에서 비롯되는 것일 뿐이다. 따라서, "강제로 재설정한" constructor를 비교하는 것은 아무런 의미가 없다."

입니다.

유연함으로 인해 constructor 속성이 아무 값이라도 상관없이 재설정 할 수 있다는 것은 meat1.constructor = 1 이라는 예제를 통해서 이미 충분히 입증되었다고 생각합니다. 함수객체가 아닌 것도 constructor 속성에 설정될 수 있으니까요.

"강제 재설정" 자체가 의미가 없다는 겁니다.
"생성자가 곧 객체타입"이라 했습니다. 그렇다면, constructor를 재설정해서 객체타입이 변하느냐... 그게 아니라는 겁니다. 그래서 그렇게 바꾼 constructor는 아무런 의미도 없다는 것을 바로 위에서 말씀드렸습니다. 오히려 constructor를 바꿔도 최초의 생성자가 여전히 해당 인스턴스에 영향을 미치고 있음을 알 수 있습니다.

이제 다시 물어보겠습니다.
왜 강제로 재설정한 constructor를 비교하신건가요?
그 constructor가 해당 인스턴스의 자료구조에 영향을 끼치나요?

잘 판단해보시기 바랍니다.

"강제로 재설정한 constructor 속성은 아무런 의미가 없습니다"
                         
   무소레즈   07-03-28 12:14  
(객체.constructor) 이나  (A instanceof B) 등이 어디에 어떤 상황에서 사용될 수 있는지 생각해보세요..
스스로 생각하는 시간을 가져야 하지 않겠습니까?
자신이 사용해보거나 직접 프로그램에 적용시켜 본적이 없다고
의미가 없다고 얘기하는것은  바람직하지 않겠지요.
뭣에 쓰는 물건인고... 내지는 뭣에 쓸꼬...를 생각해보세요.
의미가 없다는 말은 그 다음에 해도 늦지 않을까 합니다.
                         
   행복한고니   07-03-28 12:19  
전 하루종일 자바스크립트만 생각하는 사람이니까 저한테 생각해보라고 하지마시고요,

대화를 하시려면, 뭐가 자신의 의도인지 밝히시던지 제가 오해하고 있다면 어느 부분이 오해인지 말씀을 하셔야죠.

대화를 하실 생각이 아니라면 그만 두셔도 상관없습니다.
                         
   무소레즈   07-03-28 12:27  
대화할 생각이 없다기 보다는 더 이상의 대화는 필요하지 않을 것 같습니다.
어떤 목적으로 소스를 보여드린것이지 미리 얘기해 주었고,
몇줄 되지도 않는 소스의 의미 파악도 안되는 상황인듯 싶은데..
더 진행이 되겠습니까?
                         
   행복한고니   07-03-28 13:33  
글쎄요... 저 위에 보면 생성자라는 개념을 혼동하고 있으신 것 같아서 말이죠.

constructor를 강제로 재설정했다고 constructor 속성에 있는 값이 생성자인 것은 아니라고 말씀드렸는데, 그게 생성자라고 말하고 계시는 것 같거든요. 그 전에는 인스턴스와 인스턴스 객체라는 용어를 다른 개념으로 사용하셨는데, 이것 역시 개념을 혼동하고 계시는 것 같다라는 말씀밖에는 더 드릴게 없습니다.

어쨌건 제가 보기에는 개념 자체를 혼동하시는 것 같으니 더 이상 얘기를 나눠봤자 진전이 없을 것 같습니다.

대화를 더 나눠봐야 진행이 안될 것 같다는 데는 동의합니다.
                         
   무소레즈   07-03-28 15:05  
생성자 개념을 혼동하는 부분이 어느 부분인지 구체적으로 말씀해보세요.
(객체.constructor) 에의해 다른 객체타입의 construtor 속성값이 재할당 되도록 소스에 구현되어 있으나
그것이 생성자인것으로 생각하고 있는 것은  행복한 고니님입니다.

제공해 준 소스에서 생성자는 무엇이고, 인스턴스는 무엇이고, 어떤 객체 타입을 가졌고
그 결과가 제대로 나온것인지, 아니면 결과에 무엇이 잘못되었는지
설명 할 수 있다면 해보시기 바랍니다.


인스턴스와 인스턴스 개체라는 용어의 정의도 그렇습니다.
용어의 표현이 서로 다르다 할지라도 그 본질적인 의미가 같지 않다면 누군가 잘못 알고 있는 것이겠지요.
막연하게 잘못되었다느니... 개념을 혼동한다느니...라는 표현보다
님은 어떻게 생각하고 있는지를 밝힌다음에 어느 부분이 어떻게 다르고, 님은 어떻게 생각한다....라고
표현해야 하지 않겠습니까?

막연한 말로 말씨름 하기엔 어린 나이가 아닐텐데 말입니다.


그리고... 님의 반론에대한 반론으로 소스를 보여주었고...
윗쪽 많은 답변성 글들중에는 님이 소스의 검증을 해보고 난 후 문제점을 테스트용 소스로 간략하게나마 제시하던데..
제가 제시한 소스에서는 어떤 문제로 인해 어떤 결과가 잘못 출력되었나요?
소스를 제공했으면,  로직이 잘못되었다던가? 결과가 바르게 출력되지 않는다던가...
기타 여러가지 문제점을 제시해야 하지 않는가요?

말로 다 채우려하지 말고, 제공한 소스로 직접 로직을 구현해보고, 점검해 본후
문제점을 지적해줄 님의 소스를 제시해 보시기 바랍니다.

또한, 님이 언급한..

    "강제로 재설정한" constructor를 비교하는 것은 아무런 의미가 없다"

라는 말처럼  의미가 없으면 그 부분도 지우고 테스트를 해본후 함께 소견을 밝혀보시기 바랍니다.

  "왜 강제로 재설정한 constructor를 비교하신건가요?
  그 constructor가 해당 인스턴스의 자료구조에 영향을 끼치나요?

  잘 판단해보시기 바랍니다."

라는 억지성 의견은 말고 말입니다.
뺄 부분은 빼고 테스트를 해보고, 빼거나 그대로 두거나 결과가 같다면
그냥 빼면 됩니다. 만약 결과가 다르다면 그것이 의미하는 바가 있겠지요.
                         
   행복한고니   07-03-28 16:47  
용어에 대한 제 생각은 저 위에 적었습니다. 텀즈 링크까지 드렸습니다.
상대방의 글을 제대로 읽으라면서요... -_-;;;

제가 생각하는 코드도 드렸습니다.
그랬더니 빗나간다고 하시던데요.

강제로 재설정한 constructor가 자료구조에 영향을 미치는 지에 대해서도 "그렇지않다"라고 증명하는 코드도 역시 드렸습니다. 그 뒤에 저한테 무슨 답글을 다셨는지 잘 보세요. 님이 말씀하시는 모든 것들을 이미 코드로도, 말로도 설명했습니다.

님의 글에 대한 제 글들을 잘 보세요.
어째서 강제로 설정한 constructor가 의미가 없는지에 대해서 남겼습니다. 그게 아니라면 저~~기 아래에 숨어지내리 님도 똑같은 착각을 하고 계시길래 근거를 남겨드렸습니다.

어떤 코드를 만들어드릴까요? 어떤 코드가 필요하신대요?
본인이 작성한 것을 이해못하면 제가 답답한 것이고 밥까지 먹여달라고 하는 격이고 글을 제대로 안 읽었다 하면, 제가 작성한 코드와 이미 했던 말을 이해못하거나 했는지도 모르고 계시는 님을 저는 어떻게 표현해야할까요.

인스턴스나 인스턴스 객체나 저에게 같은 말이고 인스턴스의 객체구조를 정의하는 것을 타입, 객체타입, 클래스 등으로 부릅니다. 클래스, 객체타입 등등은 추상적인 의미고요, 인스턴스는 실제로 사용할 수 있는 형태를 의미합니다.

"생성자가 곧 객체타입"
"consturctor 속성은 강제로 재정의 될 수 있으나 그게 진짜 생성자는 아니며, 따라서 강제로 설정된 값은 실제 객체구조에 아무런 영향도 미치지 못한다."

생성자가 곧 객체타입이 되는 것은 prototype 에 의해서입니다.
function type1() {}

var obj1 = new type1();
obj1.constructor = Date;

이렇게 바꿨을 때 obj1의 생성자가 Date이라면, Date의 prototype을 통해 속성을 지정했을 때, obj1에도 적용이 되어야 하지만 그렇지 않습니다.

Date.prototype.cc = "c";
alert(obj1.cc);

하지만, type1에 지정하게 되면 obj1 에 적용이 됩니다.

type1.prototype.bb = "b";
alert(obj1.bb);

왜 의미가 없느냐면, constructor  속성에 있는 것은 어떻게든 강제적으로 조작이 가능합니다. 지우는 것도 아무런 의미가 없는 값을 넣는 것도 가능합니다. 하지만, 이상한 값을 넣어도 constructor 속성을 삭제해도 여전히 obj1이 type1이라는 객체구조를 가지는 인스턴스 임에는 틀림이 없다는 말입니다.

delete obj1.constructor;
alert(obj1.constructor);
type1.prototype.dd = "d";
alert(obj1.dd);

혹은

obj1.constructor = 1;
alert(obj1.constructor);
type1.prototype.ee = "e";
alert(obj1.ee);

constructor 속성은 말 그대로 인스턴스 객체에 있는 속성일 뿐입니다. 그것을 강제로 지정하려면 할 수도 있습니다. 하지만 그렇다고 그게 객체의 성질을 규정하는 건 아니라는 거죠.
                         
   무소레즈   07-03-28 17:53  
'강제로 재설정한 constructor가 자료구조에 영향을 미치는 지에 대해서도 "그렇지않다"라고 증명하는 코드도 역시 드렸습니다.'

라고 하셨는데...그것때문에 제가 제시한 소스코드에 어떤 문제점이 있는것인가요?
제 소스와 실행결과가 잘못된것이 있는데 그 이유가
강제로 재설정한 constructor 가 자료구조에 영향을 미치지 않기때문이라는 것인가요?

어떻게 결과가 나와야 제대로 나오는것인지에 대한 얘기는 없군요.
constructor 속성의 강제 설정이 의미가 없다고 하면서
제시한 소스와 관련하여 그렇게 의미없는 얘기를 중점적으로 하는 이유라도 있어야 하지 않을까요?

유연성 얘기를 많이 꺼내시는데... 그 유연성을 활용하여 실행 처리하면 무엇이 잘못됩니까?
주어진 유연성을 활용하여 나름대로의 의미를 부여하며 처리하여 올바른 결과물을 가져와도
잘못된 것이라는 듯한 뉘앙스를 주는군요.

constructor 속성의 값에 수나 문자열을 할당시키던, 객체를 할당 시키던
그것이 프로그램 처리에 있어서 무슨 문제를 일으킨다는 것인가요?

행복한고니님의 그런 저런 증명이나 길고 긴 부연설명들이 모두 그러..그러하다는 얘기들일뿐
반론으로써 제시한 소스에 대해서는  도대체 무슨 문제 있고,
실행 결과 값이 어떻게 틀린지등에대한  실질적인 언급이 없다는 것입니다.

의미 없는 constructor 재설정 얘기로 끝내지 말고, 
그런 의미 없는 것으로 인해  소스코드의 실행에 어떤 문제가 있는것인지를
얘기할 수 있어야 하지 않을까 합니다.

정의가 어떻고 어떠하다....라는 말로 끝내고는 무슨 얘기가 진행이 됩니까?
스스로 의미없다고 하는 것들에대해 너무 집착하고 있는 것은 아닌가요?
아니면... 그 의미 없다고 얘기한 것이 없어져 줘야만..
님이 주장하고 싶은 것들을 다시 피력할 수 있기 때문인가요?

윗쪽 답변글들중에서는  constructor 속성과 instanceof 연산자를 이용하여
여러가지 체크와 문제점을 제기했었는데...
제가 제시한 소스의 실행결과에서는 그것만으로 문제점을 찾을 수가 없던가요?

님의 답변글에는 제 소스의 로직과 실행의 문제점에 대한 실질적인 얘기가
어디에 표현되어 있는지 찾을 길이 없습니다.
대부분 정의와 관련 테스트 예들 뿐입니다.
어찌 엉뚱한 대답이 아닐 수 있겠습니까?
   TP™ 아쿠아   07-03-28 12:07  
음..............
이거 다 이해하면 고수대열에 끼이는건가요 -_-;
장장 40분에 걸쳐서 읽었네요 -ㅅ-;
     
   숨어지내리   07-03-28 13:53  
^^ 고생하셨습니다.
   낭망백수   07-03-28 13:35  
무소레즈 // (쪽지가 안되서 여기다 씁니다)
커멘트중에 자신의 커멘트는 삭제했으면 좋겠다고 의견을 피력하셨는데요.
괜찮으시다면, 삭제하지 않았으면 좋겠습니다.
혹시나 삭제될까봐 심히 염려가 되는군요. ^^;;;
     
   TP™ 아쿠아   07-03-28 13:52  
저두요....
삭제되면 아까워요
   숨어지내리   07-03-28 14:42  
왠만하면 안달려고 했습니다. ^^

이미 어느정도 제가 주장하고 있는 내용을 보여드렸으니깐요.

헌데, 고니님이 수긍하시지 않는 모습이 정말 이렇게 글을 남기게 되는군요.

자 이 모든건 제가 처음부터 말씀드렸던 prototype chain 으로 설명이 가능합니다.

----------------------------------------------------------------------------------
1. 일단 2차 상속이라는게 자바스크립트에는 없습니다. 설명은 위에서 밝혔으니 따로 하지 않겠습니다(코드만 봐도 충분하다 봅니다). 따라서 constructor 를 두번 비교하는 것은 위에서 제가 말했던 대로 님의 착각에서 비롯된 것입니다.

2. constructor 는 해당 인스턴스의 객체구조를 알 수 있게 합니다. 이 때 객체구조의 정의는 반드시 Function의 인스턴스여야 합니다.
----------------------------------------------------------------------------------

위의 내용은 고니님이 직접 정리한 내용입니다.

Object 는 최상위라는것만 증명이 되면 고니님이 '주관적으로' 생각하는
아래의 내용 'Function 의 instance 여야만 합니다.' 라는게 거짓이 되는것입니다.
Constructor 로 비교하는것 자체가 무리다 라는것이 입증되면, 고니님은 인정을 하실수밖에 없습니다.

즉, 제가 말한 'constructor 로 객체를 비교하는것 자체가 무리가 있다'라는 것입니다.

아래의 코드를 봐주십시요.

alert(delete Function.prototype.constructor);
alert(new Function().constructor.constructor);
alert(new Object().constructor.constructor);
alert(new Array().constructor.constructor);
alert(new Number().constructor.constructor);
alert(new String().constructor.constructor);

alert(String.constructor);
alert(Function.constructor);
alert(Object.constructor);
alert(Array.constructor);
alert(Number.constructor);

ㅋㅋㅋ 위의 코드는 IE , Firefox 모두 동작합니다. 고니님.!!!! ㅋㅋ

위의 코드는 prototype chain 을 일부러 끊어 보았습니다.

그랬더니, 각각의 객체는 Object 라는 constructor 를 보여주기 시작합니다.

따라서, 최상위 객체는 Object 라는 것이 입증된 샘이며,
Function 은 단지 prototype chain 을 구성하는것 입니다.

Object 가 Function 의 instance 가 아니라는 것입니다.

그건 즉 , constructor 는 말그대로 생성자입니다. 생성한 근본이 누구인지를 말입니다.


Object
|
Array - Number - String - Function ...

으로 되어 있고 각각의 Function 이라는 chain 으로 감싸서 서로 연결되도록 구성되어 있는것입니다.

그래서 constructor 로 객체를 비교하는것은 무리가 있다라는 것입니다.

constructor 를 2번 비교하는것이랑 1번비교하는것이랑의 차이는 없습니다. ^^

단지, 생성한 근본 객체를 보여주는것이니깐 그런거구나하고 참조만 하면 된다라는 것입니다.

 

고로, 고니님이 주장하는 1,2 의 항목이 거짓입니다.

그러면, 여태 주장한 모든 것은 '주관,고집' 으로 보이는 것입니다.

---------------------------------------------------------------------------------
 검증되지 않은 지식을 가지고 있는 것도 아주 싫어합니다.
---------------------------------------------------------------------------------

따라서, 고니님은 고니님을 아주 싫어하는 것입니다. ㅡㅡ;;;;

이런게 논리고 , 응용입니다. 고니님..


이제 고니님이 인정할것이라 생각하며,

-----------------------------
아뇨. 정말로 틀렸다는 것을 증명해주시기를 바라고 있습니다.
원하신다면 문서로 만들어서 대중의 심판을 받을 각오도 되어있습니다.

여태까지 주신 근거는 제가 아니라고 반박해드렸습니다.
애매한 태도로 제가 우긴 것처럼 하지 마시고요, 정확하게 논거를 들어주시기 바랍니다.

틀렸으면 깨끗이 인정을 하시던가 그렇지 않으면 "내부적으로는 다르다" 는 것에 대한 증거를 보여주셨으면 합니다. 지금과 같은 태도는 별로 바람직하지 않다고 봅니다. 본질을 흐렸다고 생각하지 않고 있는데, 본질은 무엇이며 어떻게 흐렸는지도 좀 알려주시고요. 인정하기 싫으신건지는 모르겠지만, 어쨌든 간곡히 부탁드립니다
-------------------------------

위의 내용을 토대로 실행하여, 이제껏 말한 내용을 정의 하여 주실거라 생각합니다.



ps. 전 고니님과 친하게 지내고 싶습니다.
    토론으로 서로 감정을 나쁘게 하지 않았으면 하는 바램입니다.

ps2. http://zeldign.com/tt/38  과 같이 생각하고 있고,
      동의하시는분들은 똑같다라는 표현은 다소 무리가 있다라고 생각해 주시면 감사하겠습니다.
     
   행복한고니   07-03-28 16:04  
에휴... 안타깝습니다. 진짜... 자바스크립트를 제대로 좀 이해하세요.
테스트 할 때는 본인 주장에 맞는 것만 하고서 "맞다"라고 하지말고, 제가 반론할 수 있는 여지까지 테스트해주시기 바랍니다. -_-;; 제발...

번호 붙여 순서대로 증명할테니, 여기부터 이상하다 싶은 명제가 있으면 번호를 알려주세요.

1. 어떤 객체의 constructor는 생성후 자유롭게 조작가능합니다. 그건 위에서 무소레즈님과 대화할 때 말씀드렸으니 따로 더 말 안하겠습니다. (new Object).constructor = 1; 처럼 성질에 관계없이 값을 넣는 것도 가능합니다.

2. Function.prototype 은 함수의 인스턴스입니다. 물론, 확인하셨겠죠? FF에서는 그냥 함수 객체처럼, IE에서는 prototype이라는 이름을 가진 함수로 나타납니다.

3. 1번에 의해서 함수인스턴스의 constructor 속성은 또한 삭제할 수 있습니다. 하지만, 삭제가 되지는 않고 대신 Object 가 설정됩니다. 이 부분은 특이한 동작임이 확실합니다. 하지만 단지 재설정되었을 뿐입니다. 다른 객체에서는 constructor 속성이 삭제가능함을 굳이 증명하지 않겠습니다.

4. Object, Array, String... 등의 함수 인스턴스의 생성자인 Function에 prototype에 있는 속성값이 변경되었습니다. 따라서 Object... 등에 적용이 됩니다. 자 이제, Object, Array, String... 등은 constructor 속성으로 Object를 가지게 되었습니다.

5. 그렇다면 또 증명할 게 남았죠. constructor 속성이 Object라고 해서 Object는 더이상 Function의 인스턴스가 아닐까? 하는거죠.
delete Function.prototype.constructor;
alert(Object instanceof Function);

이걸로는 좀 부족하신가요? ^^
하나더. 객체에는 constructor 뿐만 아니라, 생성자의 prototype을 알 수 있는 __proto__ 라는 속성도 있습니다. 아... JScript에는 없더군요.

alert(Object.__proto__ === Function.prototype);
alert(Object.__proto__ === Object.prototype);
alert(Array.__proto__ === Function.prototype);
alert(Array.__proto__ === Object.prototype);

이런... 이제 어쩔까요? ^^ 여전히 Function이 생성자인 것처럼 되어있군요.

6. 아직도 부족하시다면 그 끊었다던 prototype chain을 한번 이용해볼까요?
Function.prototype.fool = "you";
alert(Object.fool);
alert(Array.fool);

어라? 여전히 적용이 되네요? 님의 주장대로라면 Function은 생성자가 아니어야 할텐데 말이죠. ^^

7. 결론. 님이 하신 것은 단순히 Function.prototype 이라는 함수 인스턴스에 있는 constructor 속성값을 지웠을 뿐입니다. 분명 지워진 자리가 undefined가 아닌 Object로 다시 복구되는 것은 특이한 일입니다(사용자 정의 객체에서는 undefined가 되죠). 하지만 그렇다해도 그것은 단지 constructor  속성이 재정의된 것에 불과할 뿐, 그게 constructor 속성에 있는 것이 생성자라는 뜻은 아닙니다. 여전히 내장객체들의 생성자는 Function 입니다.

보너스.
Function.prototype.constructor = 1;
alert(Object.constructor);

Object의 상위객체는  숫자 1일까요? ^^
자바스크립트의 유연성 덕분에 가능한 코드를 테스트도 안해보고 이렇게 들이밀어서야 되겠습니까. ^^

아.. 그리고, 저는 별로 안 친해지고 싶어요. :)
          
   숨어지내리   07-03-28 17:10  
ㅋㅋㅋㅋㅋㅋ 재미있습니다.

또 자기주관을 설파하시네요..

__proto__ 와 prototype 이 같다고 생각하시나 보다.. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ


그럼 상속된 객체에서는 왜 다른지 알려줘보시겠어요?

alert(new Object().__proto__ === new Object().prototype);


이렇게 비교하는것이랑

alert(Object.constructor === Array.constructor);


무슨차이가 있나요? ㅡㅡ; 참어이가 없을 따름입니다.


__proto__: which class
prototype: define lower class and class methods.
__proto__ is a reference to the prototype property.
The __proto__ property determines the prototype chain used to return property values
the value of the prototype property of the constructor function

고니님처럼 한다면,

alert(delete Function.prototype.__proto__);

객체에 which class 처음 값을 그대로 유지하고 있습니다. 

그러니 체인을 끊은것을 보여주는게 아니라 체인을 그대로 보여주고 있는 것입니다.


Object 가 최상위라는걸 증명하는건 다음과 같이 증명됩니다.

alert(Function.__proto__.__proto__.__proto__); // null
alert(Function.__proto__.__proto__);        // Object
alert(Object.prototype.__proto__); // null
alert(Object.prototype);    // Object

alert(Array.prototype.__proto__.__proto__); // null
alert(Array.prototype.__proto__); // Object

alert(String.prototype.__proto__.__proto__); // null
alert(String.prototype.__proto__); // Object
        
alert(Object.prototype);    // Object


참고로 Firefox 에서 실행한 겁니다. 고니님.. ㅋㅋ ㅡㅡ;;;


따라서

alert(Function.__proto__.__proto__ === Object.prototype);
alert(Array.__proto__.__proto__ === Object.prototype);

즉. Object 가 최상위라는 말입니다. ㅡㅡ;

무슨 상속을 받습니까?.. Function 은 prototype chain 만 구성한다니깐요.. ㅡㅡ;




친해지고 싶지 않다니, 에휴...^^; 소심하셔서 그런지...ㅋ



그럼 그렇게 하시지 않으셔도 됩니다. ^^


ps. 이 글을 보고 계시는 분들이 많을 거라 생각합니다. 허나, 제가 말씀드리고 싶은것은

행복한 고니님과 저는 싸우려고 이렇게 장문을 쓰는게 아닙니다.

행복한 고니님이 틀렸다고 반박하는게 아니라,

글을 쓰다보니, 감정이 이입되어 서로 기분이 상한게 사실입니다.

고니님이 주장하는부분은 일리가 있습니다.

허나 또 제가 생각하는게 달라서 댓글을 달아 나가는 것이니깐요....

생각이 달라 이어지는 글이니, 그렇게만 생각해 주시면 감사하겠습니다. ^^
               
   행복한고니   07-03-28 18:32  
우선 제가 __proto__ 를 어떻게 사용했는지 좀 보세요. 이거야 원...
Function을 Object의 생성자로 보고 증명하기 위해 사용한겁니다.

어떤객체.__proto__ === 어떤객체의생성자.prototype 이거든요? 그건 저~~기 위에도 썼던 얘깁니다. 제발 제 글 좀 읽으세요!

나참 코드를 이해못하고, 글도 안 읽고... 대체 뭘하자는 건지... -_-;;
___________________________________________________________

일단은 나머지 예도 반박해주세요.
항상 일부만 반박하는 버릇이 있으시더군요.

아.. 아닙니다. 그냥 맞다고 혼자 생각하시고 답글 달지 마세요.
블로그에서 제 말이 틀렸다고 하시든지, 스쿨 팁텍에 정리해서 올리든지는 알아서 하시고요... 제 글 모니터링이 되서 답글달면 어쨌거나 제가 그 글을 봐야하니까 이 글에 답글달지 말고 자신의 세계를 계속 설파하세요.

팁으로 올리면 글쓴이 이름보고 자체필터링 할 수 있으니까요. 그렇게 해주세요.
___________________________________________________________

그나저나 이 코드 어이가 없습니다.
prototype은 왜 비교하는데요? 아... 진짜...

Function.__proto__.__proto__ 값이 Object라고 이미 써놓고서는
Object.prototype 이랑 같다고 한건 또 뭔지...

prototype chain을 가지고 거슬러 올라가면서 상속증명하려는 사람은 또 첨봤구요.

Function.__proto__ 는 Function이라는객체의생성자의prototype입니다.
여기에 또 prototype을 쓰면서부터 말도 안되는 증명이 시작됩니다. prototype이라는 속성의 생성자를 비교해서 어쩌자고요? 제가 왜 한단계밖에 이해못하신거 같군요.

제가 __proto__를 사용했던 것은 __proto__가 위에서 제가 말한 것과 같기 때문에,
"이 객체의 생성자가 무엇인지 확인해보기 위해 썼던 것"입니다.

(new Object).__proto__ === Object.prototype;

이게 가능하다면 new Object는 Object라는 생성자로부터 만들어진게 맞다는 말이됩니다. ㅋㅋ 근데 왜 prototype 속성 자체의 타입을 비교하고 계시나요? ㅎㅎ 그게 여러번 사용되면 상속을 증명할 수 있게 되는건가요? ㅋㅋ

Function.__proto__ <- 이거요? Function의생성자의prototype이죠. Function의 생성자가 뭔지 그것의 prototype이 뭔지 체크해보세요.

(Function.__proto__) 여기부터는 function(){} 인스턴스를 가지고 또 다루겠네요.

님께서 하신 행동이요? 바로 그런겁니다. Function과 관계있는게 아니라 prototype 자체를 비교하고 있는 것이죠. 으하하하하~~  Array.prototype, Function.prototype 이런거 한번씩 찍어보셨죠? ㅎㅎ  prototype 속성의 생성자, 또  prototype의 속성 이런걸 따져서 어쩌자고요? ㅋㅋ

IE에서도 할 수 있어요.
__proto__ 대신에 constructor.prototype 을 치환하시면 됩니다. prototype 속성 자체를 거슬러 올라가서 어쩌자는 것인지 원...

prototype chain에 대해서 잘 모르시는거 이미 알고 있으니 다시 상기시켜주지 않으셔도 됩니다.
___________________________________________________________

아... 이해를 하셨건 못하셨건 또 저보고 우긴다고 할테니, 이젠 그만 혼자 노세요.
___________________________________________________________

소심하기도 한데, 말귀도 못알아먹는 사람과는 어머니께서 친하게 지내지 말라더라군요.
                    
   숨어지내리   07-03-28 19:12  
어떻게... 진짜.. 모르고 계셨네... ㅠㅠ;

__proto__ 와 prototype 을 사용하는 방법을요.. ㅡㅡ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

그러면서 JAVASCIRPT 를 모른다고 운운하셨습니까 ??????


아...일을 어쩐다냐...ㅡㅡ;  한심하기 그지 없습니다... ㅠㅠ

오늘로써 고니님의 대한 나의 생각을 다시 정리해야할것 같습니다... ㅡㅡ;

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Property_Inheritance_Revisited:Determining_Instance_Relationships

일단 , 위의 내용 보시고요 __proto__ 의 제대로된 내용을 공부하세요.!!!


//========================================
---------------------------------------------------

alert(Function.__proto__.__proto__.__proto__); // null
alert(Function.__proto__.__proto__);        // Object
alert(Object.prototype.__proto__); // null
alert(Object.prototype);    // Object

alert(Array.prototype.__proto__.__proto__); // null
alert(Array.prototype.__proto__); // Object

alert(String.prototype.__proto__.__proto__); // null
alert(String.prototype.__proto__); // Object
       
alert(Object.prototype);    // Object


참고로 Firefox 에서 실행한 겁니다. 고니님.. ㅋㅋ ㅡㅡ;;;


따라서

alert(Function.__proto__.__proto__ === Object.prototype);
alert(Array.__proto__.__proto__ === Object.prototype);
---------------------------------------------------

//========================================


위의 코드를 이해를 못하시고 계시니 원... ㅡㅡ;; 이러니 말이 안통하죠..


---------------------------------------------------
Function.__proto__.__proto__ 값이 Object라고 이미 써놓고서는
Object.prototype 이랑 같다고 한건 또 뭔지...
prototype chain을 가지고 거슬러 올라가면서 상속증명하려는 사람은 또 첨봤구요.
---------------------------------------------------

처음 보셨으니, 이제부터 계속 보실것입니다. ..


자 그럼 아래의 코드를 보세요.


alert(Object.prototype.__proto__); // null -> function 의 상속이 아니다. 라는 증명
alert(Function.prototype.__proto__.__proto__); //null
alert(Array.prototype.__proto__.__proto__); // null
alert(String.prototype.__proto__.__proto__); // null

따라서 이렇게 되는 겁니다.

alert(Object.prototype); // object
alert(Function.prototype.__proto__); // object
alert(Array.prototype.__proto__); // object
alert(String.prototype.__proto__); // object

아직도 모르겠습니까?
function(){} 은 chain 을 구성하는것 이라니깐요.. ㅡㅡ;


그래서 이렇게 증명된거고요..  Object 가 최상위이다..
1. Object 는 Function 의 instance 가 아니다라고요..!!!!
2. Function 은 단지 prototype chain 만을 구성한다고 말하는것이고,
3. constructor로 비교하는것 자체가 무리이고요..

자꾸만 왜 이상한 변명과 고집을 피는지 모르겠습니다. ㅡㅡ;;;;



--------------------------------------------------------------------------------------
말귀도 못알아먹는 사람과는 어머니께서 친하게 지내지 말라더라군요.
--------------------------------------------------------------------------------------

이젠 어머님의 말씀을 따라야 할것 같습니다. ㅠㅠ



따라서, 고니님의 주장은 모두 '주관,고집' 이라고 말하는것이고요.. ㅡㅡ;

제가 말한 아래의 내용이 되는것입니다.

//=======================================

고로, 고니님이 주장하는 1,2 의 항목이 거짓입니다.

그러면, 여태 주장한 모든 것은 '주관,고집' 으로 보이는 것입니다.

---------------------------------------------------------------------------------
 검증되지 않은 지식을 가지고 있는 것도 아주 싫어합니다.
---------------------------------------------------------------------------------

따라서, 고니님은 고니님을 아주 싫어하는 것입니다. ㅡㅡ;;;;

이런게 논리고 , 응용입니다. 고니님..

//=======================================


아.. 깝깝스럽습니다.. ㅠㅠ

왜 진실을 왜곡하면서 자신의 주관을 설파하는지...

고니님의 특징을 잘 보면

0. 자신의 주관을 사실인 양 말한다.

1. 하나 검증하면 , 또다른 숙제를 낸다.

2. 또 검증하면, 반박하며,  또다른 숙제를 낸다.
2.2 살짝 약올린다.

3. 막판까지 오면, 자신의 주장을 살짝 바꾼다. (브라우저문제, 버그 등등)

4. 아닌거 같으니, 이젠 답글을 그만 달라한다.




ps. 그냥 진실이 왜곡되지 않았다면, 이런 긴 댓글은 없었을것입니다.
                         
   행복한고니   07-03-29 02:08  
인용하신 MDC 문서에서 사용된 코드를 그대로 가져다 드리죠.
________________________________________
chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");
chris.__proto__ == Engineer.prototype;
________________________________________
위에서 보시면 아시겠지만 chirs가 Engineer의 인스턴스이기 때문에 chris.__proto__ 는 생성자인Engineer의 prototype이 됩니다.

아... 그리고  // Object 라고 표시한게 Object의 인스턴스더군요. 그렇다면,
alert(Function.__proto__.__proto__ === Object.prototype);

이렇게 비교하는 것은 옳습니다. 이 부분은 제 실수가 맞네요. 하지만 제가 코드를 착각한 것이지 성질 자체를 착각한 것은 아닙니다. 주욱 위에서부터 읽어보세요. 계속 똑같은 얘기만 하고 있으니까요.

어쨌거나 위의 부분에서는 제가 실수했습니다.

하지만 왜 계속 __proto__ 를 물고 들어가는게 옳지 않은지는 뭐... 생각해보면 아시겠지만, 모르셔도 상관없습니다.

________________________________________

자, 이제 또 제가 증명할 시간이 왔습니다.

이것저것 증명하다가 그래봐야 어차피 듣지도 않을 것이고 해서 싹 지우고 그냥 애초 생각대로 javascript 엔진을 까봤습니다. -_-;; 귀차니즘이 강한 저를 이렇게 하게까지 한 점은 정말 높이삽니다. 다운로드는 아래 주소에서 하세요.

ftp://ftp.mozilla.org/pub/mozilla.org/js/rhino1_6R5.zip

뭐... 제가 한 소스 분석이 마음에 안들면 직접 다 분석해보셔도 됩니다. :)

차근차근 따라가보면 알겠지만, 스크립트를 실행할 때 object literal 을 만드는 부분이 있습니다. ScriptRuntime.java의 3094 라인을 보세요.

잘 보시면 리턴하는 객체가 cx.newObject 라는 것에 의해 만들어지는 것을 알 수 있고, cx는 Context 타입임을 알 수 있습니다.

자.. 이제 Context.java 열어보시고요, 1404 라인 보세요. 주석에 떡하니 써있습니다. new Object를 실행하는 것과 equivalent 하다고 말이죠. ^^ equivalent의 뜻을 혹시 또 오해할까봐 밑에 있는 오버로딩 메소드들도 꼭! 같이 보라고 말씀드립니다.

다시 ScriptRuntime.java의 3098라인 보세요. 객체 만들고 나서 프로퍼티 할당하고 있는게 보이실 겁니다. 그리고 나서는 바로 객체를 리턴하는 것으로 보이네요. 

이렇게 소스를 열어놓고 보니 둘이 왜 다르다고 하는지 더더욱 모르겠네요. :)
또한, 객체 만들고 프로퍼티를 설정하는 것을 더 편하게 해준거라는 제 주장에 더 힘이 실릴 것 같구요. ^^
________________________________________

이 글에 답글 안 달아도 되니까 애초에 생각하셨던 바와 그 근거를 팁으로 정리하셔서 부디 널리 퍼트리세요. :)

여러분의 판단을 위해서 해당 부분 소스를 첨부합니다.
###################################
## ScriptRuntime.java의 3094 라인부터
###################################
public static Scriptable newObjectLiteral(Object[] propertyIds,
                                          Object[] propertyValues,
                                          Context cx, Scriptable scope)
{
    Scriptable object = cx.newObject(scope);
    for (int i = 0, end = propertyIds.length; i != end; ++i) {
        Object id = propertyIds[i];
        Object value = propertyValues[i];
        if (id instanceof String) {
            ScriptableObject.putProperty(object, (String)id, value);
        } else {
            int index = ((Integer)id).intValue();
            ScriptableObject.putProperty(object, index, value);
        }
    }
    return object;
}

##############################
## Context.java 의 1396 라인부터
##############################
/**
 * Create a new JavaScript object.
 *
 * Equivalent to evaluating "new Object()".
 * @param scope the scope to search for the constructor and to evaluate
 *              against
 * @return the new object
 */
public final Scriptable newObject(Scriptable scope)
{
    return newObject(scope, "Object", ScriptRuntime.emptyArgs);
}

/**
 * Create a new JavaScript object by executing the named constructor.
 *
 * The call <code>newObject(scope, "Foo")</code> is equivalent to
 * evaluating "new Foo()".
 *
 * @param scope the scope to search for the constructor and to evaluate against
 * @param constructorName the name of the constructor to call
 * @return the new object
 */
public final Scriptable newObject(Scriptable scope, String constructorName)
{
    return newObject(scope, constructorName, ScriptRuntime.emptyArgs);
}

/**
 * Creates a new JavaScript object by executing the named constructor.
 *
 * Searches <code>scope</code> for the named constructor, calls it with
 * the given arguments, and returns the result.<p>
 *
 * The code
 * <pre>
 * Object[] args = { "a", "b" };
 * newObject(scope, "Foo", args)</pre>
 * is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo
 * constructor has been defined in <code>scope</code>.
 *
 * @param scope The scope to search for the constructor and to evaluate
 *              against
 * @param constructorName the name of the constructor to call
 * @param args the array of arguments for the constructor
 * @return the new object
 */
public final Scriptable newObject(Scriptable scope, String constructorName,
                                  Object[] args)
{
    scope = ScriptableObject.getTopLevelScope(scope);
    Function ctor = ScriptRuntime.getExistingCtor(this, scope,
                                                  constructorName);
    if (args == null) { args = ScriptRuntime.emptyArgs; }
    return ctor.construct(this, scope, args);
}
                    
   kisstoto   07-03-29 01:13  
// 행복한고니

자바스크립만 잘하면 뭐해여.

사람들이 왜 다구리하나 아직도 모르시겠나요...
                         
   행복한고니   07-03-29 02:09  
님의 의견은 고맙지만, 희한하게도 저는 kisstoto 님과 숨어지내리님의 아이피가 상당히 유사한 것에 눈길이 가네요. ^^
                         
   숨어지내리   07-03-29 12:10  
kisstoto 는 제 친구예요..ㅋㅋ ^^;

제가 그러지 말라고, 중간에 개입하지 말라고 충고 했습니다. ^^

개의치 않아도 됩니다. ㅋ
   똥파리   07-03-28 16:44  
이런 역사적인 자리에 참석을 해보고 싶은 마음이 들어서 이렇게 용감하게 댓글답니다.
왠지 댓글다는 부분을 시간순으로 특정인을 중심으로 플레이를 해보면 감동적이겠다는 생각이 들었습니다.

아~ 만들어보고 싶네요 ^^

모두 감동주셔서 고맙습니다.  예술같아요.
   Java™엔시   07-03-29 00:01  
스쿨최대의 토론이군요.ㄳ
   Nal㏇™날나리코더   07-03-29 00:15  
자 일단 휴식게이지 올리고 다시 만납시다. +,.+
   송월동김모양   07-03-29 01:28  
어이쿠....고생하셨습니다.
좋은 내용 보고 갑니다...
두분다 릴렉스 하시거 ^^
   불친절한코더씨   07-03-29 01:56  
지나치고 말았는데 어느새 논쟁이... ;;

관심있게 관전? 하시는분들께 이해를 돕기위해 추천하고 싶은 문서가 있습니다.
 
http://www.crockford.com/javascript/

보면 시작하는 첫번째 주제에 달린 링크중에 한글로 번역된 글도 있으니 살펴봐주세요.

그리고 "in javascript"에서 일어나는 상속에 대한 여러가지 이야기도 포함하고 다른문서도 있으니 도움이 되리라 봅니다.

또 참여 하시는 분들은 먼저 사용하는 용어 일치, 표준에 좀더 가깝게 지원하는 모질라 계열의 파이어폭스를 기준으로 예제를 첨부하는건 어떨까요?
     
   행복한고니   07-03-29 02:24  
제 예제는 언제나 FF 기준이었습니다. ^^
사실, 맥 사용자라 IE 쓰는게 더 번거로워요. ( -_-)a
          
   Nal㏇™날나리코더   07-03-29 02:32  
나도 맥에서 개발하고 싶음 ㅠㅠ;;
               
   행복한고니   07-03-29 02:34  
자바하신다고 하지 않으셨어요?
다른건 몰라도 J2EE 5 맥용이 없어서... 우리도 jsp쪽 연동작업할 때는 어쩔 수 없이 윈도우 쓰고 있어요. =_=
                    
   Nal㏇™날나리코더   07-03-29 02:40  
훔..맥에 기본적으로 설치된게 jdk 1.5.x 라.. j2ee5 개발엔 문제가 없을듯한데여....
요새 1.6.x java 6 플랫폼땜시 ㅎㅎ..근데 대부분 SI는 아직 1.4 플랫폼에서 개발되요 ㅎㅎ... 문제는 솔직히 java 단이 아니라 jsp 및 html단이죠.. 맥에서의 비주얼과 ie에서의 비주얼이 많이 차이가나니 ...
이쪽 고객들은 1픽셀로시비걸고 글씨체도 자신들 눈에 익지않은 글씨체 나오믄 바로 이슈발생이라서 ㅠㅠ
                         
   행복한고니   07-03-29 02:50  
그게 J2SE 예요. 덕분에 J2EE 기반으로 만들어진 프레임웍이 안돌아서 서비스 개발팀하고 같이 일하는데 지장이 많습니다.

1.4는 있다고 들었던 것 같아요. ^^;
                         
   Nal㏇™날나리코더   07-03-29 02:54  
요새 새로 해보고싶은게 cocoa인데...하하..
틈틈히 공부하려구요 ㅎㅎ..
                         
   행복한고니   07-03-29 02:58  
저도 코코아 조금씩 공부하고 있습니다.
이제 겨우 화면 조금 만들어봤지만...

Objective-C 이게 개념이 꽤 재밌어요. ^^
IDE 만들고 객체에 메소드 붙이고... 재밌더라구요.

예전에 애코에서 배포했던 Learnig Cocoa 한글판 PDF 있는데 드릴까요?
                         
   Nal㏇™날나리코더   07-03-29 03:01  
네 주세요 +,.+ valenny@naver.com
                         
   행복한고니   07-03-29 03:46  
보내드렸습니다. ^^
          
   불친절한코더씨   07-03-29 02:37  
유명하다던 textmate 사용자인가요?
부럽...
               
   행복한고니   07-03-29 02:52  
텍스트메이트가 상용이라서... T^T

그리고 요새는 모르겠는데 예전에 썼을때는 한글 문제가 있었던 것으로 기억합니다.
IDE는 오직 Aptana! 취미 생활을 위해 Eclipse도 가끔 사용합니다.
간단한 텍스트 편집기는 Smultron 이용하고 있습니다.
   곰아야옹해봐   07-03-29 09:43  
와우 대단하다;;ㄷㄷ
   숨어지내리   07-03-29 11:45  
ㅋㅋㅋ 역시 제가 보는 고니님의 본질을 맞는것 같습니다. ^^

0. 자신의 주관을 사실인양 말한다.

제가 곧 증명할게 될것이니, 쭉 읽어 보십시요. 고니님 과 그외 추종자 분들 ^^ㅋㅋㅋ



일단 잠깐동안의 휴식기동안, 댓글을 많이들 다셨네요..^^

많은 개발자분들이 보실꺼란 생각에 중간정도에 그만두려고 했는데,
누굴 가르치기 보단, 처음부터 끝까지 진실이 거짓에 가려지는건 용납할수 없습니다.


이글을 보시는분들의 유형은 전 이렇게 생각합니다. (제 주관입니다.)


65% : 고니님의 추종자분들
30% : 정말 그럴까? 라고 생각하시는 분들
5% : 아니다.라고 생각하시는분들..

ㅋㅋ

rhino 소스까지 보니 제 생각이 일치한다는게 맞았던거 같습니다.


---------------------------------------------------------------------------

public static Scriptable newObjectLiteral(Object[] propertyIds,
                                          Object[] propertyValues,
                                          Context cx, Scriptable scope)
{
    Scriptable object = cx.newObject(scope);
    for (int i = 0, end = propertyIds.length; i != end; ++i) {
        Object id = propertyIds[i];
        Object value = propertyValues[i];
        if (id instanceof String) {
            ScriptableObject.putProperty(object, (String)id, value);
        } else {
            int index = ((Integer)id).intValue();
            ScriptableObject.putProperty(object, index, value);
        }
    }
    return object;
}


public final Scriptable newObject(Scriptable scope, String constructorName,
                                  Object[] args)
{
    scope = ScriptableObject.getTopLevelScope(scope);
    Function ctor = ScriptRuntime.getExistingCtor(this, scope,
                                                  constructorName);
    if (args == null) { args = ScriptRuntime.emptyArgs; }
    Object a = ctor.construct(this , scope, args);
    return ctor.construct(this, scope, args);
}

---------------------------------------------------------------------------



이게 똑같다라고 보십니까? ㅋㅋ





코드가 다르다..ㅋㅋ 95%
5% 는 제 생각과 일치하시는 분들이라 생각합니다.








제가 철학자도 아니고, 본질까지 말할줄은 몰랐습니다. ㅋㅋ


서론이 길었습니다.






얼마전의 개콘의 개그 두뇌트레이닝을 보고 너무 재미있었습니다. 신선하고요..ㅋㅋㅋ( 따라해봤습니다.ㅋ)



















결론부터 말하자면, new Object() !=== {} 라는 것입니다.

!=== 왜 === 세개를 했는지는 본질을 말하기 위해서 그렇게 표현합니다.


1. 아직도 고니님의 주장이 그렇습니까?
아니오라고 하는 분들은 개발자의 길에 '최상급'을 달리고 계십니다.ㅋㅋ




















2. 저 코드는 {} 는 본질의 instance()를 재가공한다.
new Object() 는 본질의 instance() 를 반환한다.

아직도 고니님의 생각에 동의하십니까? ㅋㅋ
아니오 라고 대답하시는 분들은 개발자의 '고급'을 달리고 계십니다. ㅋㅋ
































3. rhino 의 newObject 메서드 중

ctor.construct(this, scope, args); 보시고,

Object a = ctor.construct(this , scope, args);
return a;

아직도 고니님의 생각에 동의하십니까? ㅋㅋ
아니오 라고 대답하시는 분들은 개발자의 초급을 달리고 계십니다. ㅋㅋ































4. 그럼 javascript 로 표현하겠습니다.


object = new Object();
function a() {
    var object = new Object();

    var tmp;
    for(var i = 0; i < arguments[i] ; ++i){
        tmp = arguments[i].split(':');
        object[tmp[0]] = tmp[1];
    }

    return object;
};

var xx  = a();
alert(xx.__proto__.__proto__);        // null
alert(object.__proto__.__proto__);  // null
alert(object.__proto__ === xx.__proto__);    // Object 는 같다.
alert(object === xx);    // false

아직도 고니님의 생각에 동의하십니까?


아니오 라고 생각하시는 분들은 개발자의 길을 걸으셔도 됩니다.

예 라고 하시는분들은 다른 직업을 찾아 보시기 바랍니다. ^^










결론 : rhino 소스에서도 나와있듯이 constuctor 를 실행하는 것이 new Object() 의 본질이고, {} 은 그 실행되어진 본질을 재가공하는것이 본질입니다.
따라서 new Object() !=== {} 는 성립된다고 할수 있습니다.





제가 결론부터 말한 고니님의 본질

'0. 자신의 주관을 사실인양 말한다.'

도 증명된거 같군요.


사전적인 의미에서 왜 rhino 에서도 equivalent 으로 되어 있는지 설명이 되어집니다.

e·quiv·a·lent〔〕〔L 「같은 가치의」의 뜻에서〕 a.
1 동등한, 같은 가치[양]의;<말·표현이> 같은 뜻의
                            ^

양과 질은 엄연히 다른것입니다.

new Object().constructor === Object 를 비교하는것이 어불성설이라는 말이 그것과 같습니다.


만약 Object 라는 본질이 같은것이라면,

  본질(本質) true[intrinsic] nature;essence;substance

으로 표기하여, 다른분들에게 혼돈이 없게 하였을것으로 생각됩니다.

{} 은 이미 constructor 가 실행되어진 객체를 재가공하는 역할을 하고 있는것입니다.


이로써 제가 증명해야 할게 더 남았나요?

아~ Object 는 Function 의 instance 이다. ㅋ


불친절한 코더님이 제공한 주소 보시고,

http://javascript.crockford.com/prototypal.html

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

다시 잘 생각하시고 보세요.!!! 고니님 ^^

전 한번은 읽어 봤으니깐요. (다 해석은 못해지만 말입니다. 주관이 섞여서..ㅋㅋㅋ)






고로 논쟁거리

1. new Object() === {} 가 같다?
2. Object 가 {} 으로 만들어진다?
3. constructor 의 비교로 객체가 똑같다고 말할수 있다?
4. Object 는 Function 의 instance 이다?

모두가 고니님의 틀린 주관으로 사실인양 말하는 전제 0 이  밝혀지게 된것입니다. ㅡㅡ;;;;;



//=======================================

고로, 고니님이 주장하는 1,2 의 항목이 거짓입니다.

그러면, 여태 주장한 모든 것은 '주관,고집' 으로 보이는 것입니다.

---------------------------------------------------------------------------------
 검증되지 않은 지식을 가지고 있는 것도 아주 싫어합니다.
---------------------------------------------------------------------------------

따라서, 고니님은 고니님을 아주 싫어하는 것입니다. ㅡㅡ;;;;

이런게 논리고 , 응용입니다. 고니님..

//=======================================



이렇게 되는것이고..


//=======================================

--------------------------------------------------------------------------------------
말귀도 못알아먹는 사람과는 어머니께서 친하게 지내지 말라더라군요.
--------------------------------------------------------------------------------------

이젠 어머님의 말씀을 따라야 할것 같습니다. ㅠㅠ

//=======================================


이렇게 된것이니.. 누굴 탓하겠습니까?

이기기 좋아하고, 진다고 생각하면,
이상한 논리와 원소스까지 들이대면서
추종자분들과 바락바락 우기는 고니님... 참 까탈스럽습니다..


ps. 고니님 책은 쓰시지 마세요.!! 부탁드립니다. 다른분들에게 주관을 설파하시지는 마세요. ^^
     
   행복한고니   07-03-29 12:27  
자신의 논리가 바껴있다는 것을 이제 인정하실 때도 됐는데... ^^
________________________________________________
제가 보는 관점은 Object - {}
                                  - Array

와 같이 상속처럼 구현되어져 있고 , {} 은 연관배열(배열의 형태는 필드명에 의한 문자열 인덱스 배열(associative array; 혹은 연상배열) 로 구성된다는 겁니다.
________________________________________________
{} 는 분명 Object 를 implements 했을뿐이고, 그렇게 보이는것입니다.
________________________________________________
물론 Array 또한 Object 를 implements 한것이고요..
________________________________________________

이렇다면서요? ^^ 계속 주장해보세요. ㅎㅎ

아... 자신의 주장에 동의하는 사람은 "진짜 개발자"이고, 제 주장에 동의하는 사람은 "추종자"이군요.

아... 그리고 왜 생성자가 같으면 같은 객체타입인지를 밝히는데는 고등학교 정규과정만 밟았어도 나옵니다. 이른바, 3단 논법이죠.

생성자가 객체타입을 결정한다.
A와 B의 생성자는 같다.
따라서, A와 B의 객체타입은 같다.

하지만 위 명제를 통해 다음과 같은 논리는 절대 나올 수가 없습니다.

A와 B의 생성자가 같다.
따라서, A와 B는 같다.(identity)

또한 다음과 같은 논리도 결코 나올 수가 없죠.

A와 B의 생성자의 생성자가 같다.
따라서, A와 B는 같다.

저 같은 하수의 말이라 아직도 인정을 못하시겠다면 님께서 인정하실만한 고수분께 부탁드려서 중재를 부탁드려볼까요? ^^

ㅎㅎ 그래도 시간을 들였으니 확실히 아시고 가셔야죠?


P.S// 프로그래밍 언어의 용어를 해석하면서 equivalent 를 등량(等量)이라고 해석하는 사람은 처음 봤습니다. 등가(等價)로 볼텐데 말이죠.
          
   comefeel   07-03-29 13:33  
논쟁은 끝났으니깐

이글 이외에 달지마세여 .
   발광머리앤   07-03-29 12:13  
너무 길어서 "전혀" 읽지 않고 답글 올립니다 ㅋㅋ
new Object() 와 {} 가 같냐 틀리냐 문제인가요?;;

두개는 다릅니다~ 끝 ㅋㅋ
new Object() 했을때랑 {} 했을때랑 다른점을 같은 구현 코드로 한쪽만 에러내는 방법이 있는데 위에 그 예가 나왔나 모르겠네요; 찾기도 귀찮고 오래전에 본거라;

C에서 링크드 리스트 하나로 큐, 스택, 힙 등을 구현하듯이..
http://en.wikipedia.org/wiki/Prototype-based_programming
JS는 prototype based 객체지향 언어입니다. 물론 객체의 모든 성질을 충족하지 못하고 부족한 부분이 있습니다만;
위로 올라가면 두놈은 같은 형질의 놈입니다만 상속된 실제 구현체에서는 좀 다릅니다..
JS의 Object가 named array of properties and methods 라는 견해도 있는데 음.. 전 반반입니다;

논리적으로 new Object() 와 {}가 같은 개념일진 몰라도 실제 사용해보면 약간 차이가 나고..
{} 는 Object literals 가 맞고요

여튼 헛소리만 찍 하고 이만;;
   Lanky   07-03-29 13:22  
어느것이 진실이죠...
   무소레즈   07-03-29 22:38  
숨어지내리님의 글중에... 논쟁거리라는 아래 내용이 첨부되어 있기에
그에 대한 제 답변도 올려 봅니다.

---------------------------------------
1. new Object() === {} 가 같다?
2. Object 가 {} 으로 만들어진다?
3. constructor 의 비교로 객체가 똑같다고 말할수 있다?
4. Object 는 Function 의 instance 이다?
---------------------------------------

1. new Object() === {} 가 같다?
답변 1. 엄밀하게 다릅니다.

    ( new Object() === {} )  의 결과는 false 입니다.
    하지만 함수 객체타입은 같기에  instance 를 비교하면 true 입니다.
    왜냐하면 같은 Object 함수의 객체타입으로 생성되기 때문입니다.
    어떤 함수든 new 통하여 새로운 instance 개체를 생성하면
    어떤 instance 개체든 Object 함수 객체타입의 instance 를 갖습니다.

    예를 들어

        today = new Date();

        today 라는 instance 개체는
        Date 함수객체타입의 instance 이기도 하지만
        Object 함수 객체타입의 instance 이기도 합니다.

    또한 사용자 정의 함수를 통하여 새로운 instance 개체를 생성해도 마찬가지입니다.

        function funcName() {
        }
        fn = new funcName();

        fn 이라는 instance 개체는
        funcName 함수객체타입의 instance 이기도 하지만
        Object 함수 객체타입의 instance 이기도 합니다.

        fn 은 독립적인 instance 개체로서
        funcName 이라는 함수객체에서 정의된 구조(초기환경설정)의 instance 을 가졌다는 것이지요.

        만약 funcName 함수로 또다른 instance 개체를 생성한다면

        fn2 = new funcName();

        fn2 은 fn 과는 서로다른  instance 개체이지만
        funcName 이라는 함수명으로 정의된 구조를 가진 같은 instance 를 가집니다.
        fn1 과 fn2 는 같은 instance 를 가지고 있지만 서로 다른 개체입니다.


    (new Object) 와  {} 에의해 생성된 각각의 instance 객체변수로 비교하자면

        x1=new Object
        x2=new Object
        y1={};
        y2={};

        (x1 === x2);
        (y1 === y2)
        (x1 === y1);
        (x2 === y2);

    모두 false 입니다.  생성된 instance 개체가 서로 독립적이기 때문이지요.
    하지만  instanceof 연산자를 이용하여 비교해보면 모두 같은 instance 를 가지고 있습니다.

    Object 함수객체 타입은  ( Object.prototype.constructor ) 로 알아낼수 있습니다.
      결과는 :  function Object() { [native code] }
    funcName 함수객체 타입은  ( funcName.prototype.constructor ) 로 알아낼수 있습니다.
      결과는 : function funcName() { }

    (new Object ) 와 {} 는 미리 정의된 Object 함수 객체를 통하여
    서로다른 새로운 instance 개체들을 생성합니다.
    사용자 정의 함수에서 처럼  funcName 이 없기때문에
    Object 함수 객체타입의 instance 만을 갖게 되는 것입니다.

    ★ 그렇다고 (new Object) 와 {} 가 Object 함수객체 내부에서 주어진 정의가 완전히 같은가?
    그렇지 않습니다.
    {} 는 Object initializer (개체 초기화 지정자) 라고 불리우며,
    Object initializer 라 불리우는 {} 를 다른 함수의 내부에서 사용시
    Object initializer 를 호출할때 마다, {} 에의 정의된  속성과 그에 할당된 표현식이나 값을
    매번 다시 해석(interpret) 한다는 것이 (new Object) 와 다릅니다.

    함수내부에서 개체 초기화 지정자인 {} 를 정의하고
    그 함수를  호출하면 {} 에의해 정의된 속성과 그 값을 다시 해석하여
    매번 초기화 시킨다는것입니다.

        function funcName (cond) {
                A=3;
                B={ A:5 };
                C=new Object;
                Object.prototype.A=7;

                if(cond==1) return B.A;
                else if( cond==2) return C.A;
                else  return A;
        }

        A1=funcName(0);
        B1=funcName(1);
        C1=funcName(2);

        A2=funcName(0);
        B2=funcName(1);
        C2=funcName(2);


        A1 과 A2 는 메모리에 이미 저장된 "3" 이란 값을 반환 받습니다.
        C1 과 C2 도 메모리에 이미 저장된 "7" 이란 값을 반환 받습니다.
        B1 과 B2 는 각각 호출시 초기화 지정자를 재 해석하여 메모리에 다시 올려 놓고,
        그 후에 "5" 라는 값을 반환합니다.

        B 는  초기화 지정자 {}로 할당 받았기 때문에
        매번 함수를 호출 할때마다  B 의 속성과 값을 재 해석하여 메모리에 재 저장합니다.
        즉, 함수를 호출할때마다 매번 다시 초기화 시킨다는 말입니다.


        만약 함수 외부에서 초기화 지정자를 사용했다면
        var G={ A: 9 };
        G.A 를 호출할때 이미 초기화되어 메모리에 저장되어 있는 "9" 라는 값을 불러오게 됩니다.
        다른 곳에서 G.A 를 호출해도 역시 이미 저장되어 있는 값 "9"를 반환합니다.
        함수 내부에서 처럼 재 해석하여 재 초기화 시키는 것이 아닙니다.

        C1 과 C2 를 호출하면 이미 메모리에 저정되어 있는  "7" 이라는 값을 반환합니다.
        B1 과 B2 처럼 호출할때마다 재 초기화 시키는 것이 아닙니다.

        그렇게 (new Object ) 와 {} 는 다릅니다.


2. Object 가 {} 으로 만들어진다?
답변 2.
    {} 를 호출하면 내부에서 새로운 (new Object) 를 생성하여 instance 개체를 반환한다고 알고 있습니다.


3. constructor 의 비교로 객체가 똑같다고 말할수 있다?
답변 3.
    (객체.constructor) 의 사용은 생성자가 어떤 객체타입을 가지고 있는지 참조할수 있도록
    미리 정의되어 있는 Object 의 prototype 일뿐입니다.
    프로그램의 처리 로직에따라 객체의 속성으로써 prototype 정의는 언제든 변경 가능하며
    변경된 결과를 처리 조건에따라 필요할때 마다 활용할 수 있습니다.

    (개체.constructor) 는 
    개체를 새로 생성했을때 그 개체가
    어떤 객체 타입을 가진 생성자 함수로부터 생성된 개체인지를 참조할 수 있도록
    Javascript 에서 미리 정의해둔 하나의 속성 일뿐입니다.
    변경 불가한 상수가 아니란 것이지요.
    프로그램 처리의 상황에따라 그 값을 변경하며, 참조하여 활용할 수 있습니다.

    "constructor 의 비교로 객체가 똑같다고 말할수 있습니다."
    에대해서는 그럴수도 있고 아닐수도 있겠지요.
    프로그램의 처리 상황에따라 그 속성을 주어진대로 활용하거나, 변경하여 사용하거나
    아니면 사용하지 않거나..
    엿을 파는 엿장수 맘 아니겠습니까?

    엿장수 맘대로 사용했을때 문제가 발생할 여지가 있다면야 그렇게 사용해서는 안되겠지요.
    어느 분이든...  어떤 경우에 문제가 생기는지 알려주시면
    저도 다음부터는 유의하여 사용해 보겠습니다.


4. Object 는 Function 의 instance 이다?
답변 4.
    이미 정의되어 있는 Object 는 Function 함수 객체로부터 생성된 함수 객체이기때문에
        Function 함수 객체타입의 instance 를 갖습니다.
        또한 동시에 new 를 통하여 생성되기때문에 Object 객체타입의 instance  를 갖기도 합니다.
     
   nmccm   07-03-30 09:38  
잘보고갑니다.. 고맙습니다.
     
   낭망백수   07-03-30 19:33  
무소레즈 //
님 이거 스크랩해가도 되겠습니까?
혹은 님 블로그에 올려두시면, 트랙백이라도 걸죠.
블로그 주소 보내주시면 감사~~ mulriver@gmail.com
꾸벅~!
          
   무소레즈   07-03-30 21:49  
네..
어떤 방법으로든  가져 가셔서 해당 부분에대해 잘못된 점은 수정하시고,
추가할 부분은 추가하시고, 지울 부분은 지우시면서
부분적으로나마, 보다 완성된 지식으로 재가공 되어지길 바랄뿐 입니다.
아..참..용어의 표현에 있어서도 마찬가지입니다.


출처 - PHP SCHOOL

by 뭔일이여 2007. 3. 23. 19:00

역시 기술이 발전하면 배울것도 많고 해줘야 하는것도 많으네요.
그냥 예전의 상태로 계속 있으면 좋겠지만, 데이터는 계속 쌓여만 가고 관리는 힘들어지니 어떻하겠습니까

아래의 내용은 이곳저곳 떠돌다가 발췌한 내용도 있고, 제의 경험상 알아두면 좋은것들도 있습니다.
불펌을 하고 싶어서 한것은 아니지만, 당췌 원문이 어디인지 알수가 있어야 적죠... ^^;

1. MyISAM
 1) 예전의 MySQL 의 Storage Engines 으로 MyISAM 을 사용했었습니다.
    예를 들자면 블로그라던지, 게시판 처럼 한사람이 글을 쓰면 다른 많은 사람들이 글을 읽는 방식에
    최적의 성능을 발휘를 하지요. 지금도 많이 사용하고 있는 방식입니다.

 2) 제공하는 웹서비스다 그닥 크지 않다면 이것을 사용해도 괜찮다고 생각을 합니다.


2. InnoDB

 1) 트랜잭션-세이프 스토리지 엔진입니다.

 2) MyISAM 과 비슷하지만 ORACLE 처럼 많은 기능을 지원을 합니다.
   (* commit, rollback, 장애복구, row-level locking, 외래키 등)

 3) 다수의 사용자 동시접속과 퍼포먼스가 증가하여 대용량 데이터를 처리할 때 최대의 퍼포먼스를 내도록 설계되었습니다.
   CPU효율은 어느 디스크 기반의 데이터 베이스와 비교해도 손색이 없고
   자체적으로 메인 메모리 안에 데이터 캐싱과 인덱싱을 위한 버퍼 풀(pool)을 관리합니다.

 4) 테이블과 인덱스를 테이블 스페이스에 저장을 하고 테이블 스페이스는 몇개의 서버파일이나 디스크 파티션으로
   구성되어있습니다. 이것은 MyISAM 과 다른 점인데, MyISAM은 테이블과 인덱스를 각각 분리된 파일로 관리합니다.
   여기서 중요한것이 이제 InnoDB 를 제대로 사용을 하기 위해서는 테이블 스페이스 라는 개념을 파악을 하셔야합니다.
   이것에 대해서는 밑에서 따로 언급을 하겠습니다.

 5) InnoDB 테이블은 OS의 파일 사이즈 한계가 2GB이더라도 상관없이 어느 크기나 가질 수 있습니다.

 6) InnoDB는 높은 퍼포먼스가 필요한 대용량 사이트에 적합합니다.


3. InnoDB 사용하기

 1) InnoDB 는 MyISAM 과 공유하는 메모리도 있지만 별도의 Buffer pool을 가지고 있으니까
   InnoDB 전용 DB를 구성한다면 MyISAM 이 사용하는 record_boffer 과 key_buffer 에 너무 많은 메모리를 할당하지 마세요

 2) InnoDB 설정
   ㄱ) M
ySql 을 설치한 폴더 아래에 ibdata 와 iblogs 폴더를 생성합니다.
   ㄴ) my.ini 파일 설정을 변경
      * innodb_buffer_pool_size
        - 현재 자신의 시스템 메모리의 50~80% 사이로 만듭니다.
           x86 시스템에서는 2G 이상 설정을 할 수 없습니다.
      * innodb_additional_mem_pool_size
        - 데이터 사전정보 나 내부의 데이터 구조 정보를 담는 메모리 입니다.
           보통 2M 정도 잡아주면 아주 많은 테이블을 사용한다면 좀 늘려주시면 됩니다.
           만약 메모리공장이 부족하면 error log 에 warning 메서지를 남기니 그때 늘려주세요
      * innodb_flush_log_at_trx_commit
        - insert, update 등 데이터 삽입과 관계가 있습니다.
           commit 을 하였을때 그 즉시 commit 된 데이터를 log file 에 기록할지 안할지를 설정합니다.
           로그파일을 기록할 경우 갑작스러운 경우 데이터 손실을 막을 수 있지만 매번 로그를 기록하므로 속도가 저하됩니다.
           1 일경우 기록을 하는것이고, 0일 경우 기록을 안하는것입니다.
      * innodb_log_file_size
        - 트랜잭션을 기록하는 로그 파일의 크기를 결정하는 옵션입니다.
           inno_buffer_pool_size 옵션은 성능을 위한것이지만 시스템이 다운되었을 경우 데이터가 손실이 되므로
           이것을 방지하기 위해 log file 을 만들어서 commit 될때마다 로그에 기억을 하고 자동복구를 합니다.
           로그파일은 무한정 계속 커지는 것이 아니라 일정한 크기와 갯수를 가지고 순환식으로 처리되므로 크기는
           inno_buffer_pool_size 의 15% 정도로 설정을 합니다.
           만약 메모리가 1기가이면 inno_buffer_pool_size = 512M 이고, innodb_log_file_size = 80M 가 됩니다.
      * innodb_log_buffer_size
        - 로그 파일을 기록하기 위한 버퍼 사이즈입니다.
          트랜잭션이 작거나 거의 없다면 크게 잡는것은 낭비이므로 보통 1M~8M 사이로 설정을 합니다.

      [
mysqld]
      innodb_data_home_dir="C:/MySQL/MySQL Server 5.0/ibdata/"
      innodb_log_group_home_dir="C:/MySQL/MySQL Server 5.0/iblogs"
      innodb_data_file_path=ibdata1:10M:autoextend:max:1000M
      innodb_additional_mem_pool_size=3469K
      innodb_flush_log_at_trx_commit=1
      innodb_log_buffer_size=2M
      innodb_buffer_pool_size=256M
      innodb_log_file_size=40M
      innodb_thread_concurrency=8
      innodb_log_archive=0

   ㄷ) my.ini 을 수정했으면 mysql 서버를 재시작합니다.

 3) InnoDB 테이블 만들기
   create table test_inno (
   ~
   )type=innodb;
   으로 맨 마지막에 type=innodb; 라고 명시해주시면 됩니다.

 4) InnoDB 트랜잭션 사용
  ㄱ) 트랜잭션을 사용하기 위해서는 처음에 set autocommit=0; 이나 begin; 을 선언해야 합니다.
      선언 후 데이터 변경이 있을 때, 이상이 없을 경우는 commit를 하고, 이상이 있을 경우 rollback을 실행합니다.
      오라클이랑 비슷하다고 보시면 되요

     
mysql>set autocommit=0; //begin; 같음
     
mysql>insert into test_inno values (1,'aaa');
     
mysql>select * from test_inno; //현재창에서는 입력한 내용이 보이지만 다른창에서는 보이지않음
     
mysql>commit; //다른창에서 select를 할경우 입력한 값이 보임


4. InnoDB 테이블 스페이스
 좀전에 MyISAM 과 차이점이 InnoDB 는 테이블과 인덱스를 테이블 스페이스 라는곳에 저장을 한다고 하였습니다.
 그런데 사용을 하다보니 점차 DB가 늘어나서 테이블 스페이스가 FULL 이 발생하는 경우가 생깁니다.

 4.0.x 버전부터는 일일이 할 필요가 없다는 글이 있는데 그래도 FULL이 발생하였을 때 대처방법을 알면 좋겠죠

 my.ini 에서 아래와 같이 추가를 해주면 안됩니다.
 innodb_data_file_path = /ibdata/ibdata1:1000M:autoextend 라고 할 경우
 innodb_data_file_path = /ibdata/ibdata1:1000M;/ibdata/ibdata2:1000M:autoextend 라고 ibdata2를 추가하면 안됩니다.

 아래와 같은 과정대로 하세요
 1. Use mysqldump to dump all your InnoDB tables.
 2. Stop the server.
 3. Remove all the existing tablespace files.
 4. Configure a new tablespace.
 5. Restart the server.
 6. Import the dump files.

 즉, 일단 mysqldump 로 InnoDB 테이블의 전체 덤프뜬 다음 MySQL 서버를 중지시킵니다.
 그다음 테이블스페이스 파일을 모두 지우고 테이블스페이스를 아래와 같이 추가를 합니다.
 innodb_data_file_path = /ibdata/ibdata1:1000M;/ibdata/ibdata2:1000M:autoextend
 그다음 MySQL 서버를 구동시킨다음 처음에 덤프뜬 파일을 import 하시면 됩니다.


5. 마지막으로
 위의 단계처럼 참 어렵게 설정을 하였지만, mysql.com 사이트에 들러보시면 MySQL GUI Tools 라는 프로그램이 있습니다.
 물론 무료로 다운로드 가능하고요, 이 프로그램을 설치를 하면 MySQL Administrator 라는 것이 있는데 이것을 통해서
 아주 쉽게 MySQL 의 설정을 변경하실 수 있습니다.

by 뭔일이여 2007. 3. 20. 15:09

자바스크립트로 이미지 롤링시키는 스크립트 - 미리보기

출처 - http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=51860&page=1
제작자 홈페이지 - http://comefeel.com/

by 뭔일이여 2007. 2. 9. 10:43

Ctrl + F 를 이용하시오~-_-

Mysql - ErrCode

Error code 1: 명령이 허용되지 않음
Error code 2: 그런 파일이나 디렉토리가 없음
Error code 3: 그런 프로세스가 없음
Error code 4: 중단된 시스템 호출
Error code 5: 입력/출력 오류
Error code 6: 장치가 설정되지 않았음
Error code 7: 인수 명단이 너무 깁니다
Error code 8: Exec 형식 오류
Error code 9: 잘못된 파일 기술자
Error code 10: 자식 프로세스가 없음
Error code 11: 자원이 일시적으로 사용 불가능함
Error code 12: 메모리를 할당할 수 없습니다
Error code 13: 허가 거부됨
Error code 14: 잘못된 주소
Error code 15: 블럭 장치가 필요함
Error code 16: 장치나 자원이 동작 중
Error code 17: 파일이 존재합니다
Error code 18: 부적절한 장치간 연결
Error code 19: 그런 장치가 없음
Error code 20: 디렉토리가 아닙니다
Error code 21: 디렉토리입니다
Error code 22: 부적절한 인수
Error code 23: 시스템에 열린 파일이 너무 많음
Error code 24: 열린 파일이 너무 많음
Error code 25: 장치에 대해 부적절한 ioctl
Error code 26: 실행 파일 사용 중
Error code 27: 파일이 너무 큽니다
Error code 28: 장치에 남은 공간이 없음
Error code 29: 잘못된 탐색
Error code 30: 읽기전용 파일 시스템
Error code 31: 연결이 너무 많음
Error code 32: 파이프가 깨어짐
Error code 33: 영역을 벗어난 수치 인수
Error code 34: 범위를 벗어난 수치 결과
Error code 35: 자원 교착상태를 피했습니다
Error code 36: 파일 이름이 너무 깁니다
Error code 37: 사용가능한 잠금장치가 없음
Error code 38: 함수가 구현되지 않았음
Error code 39: 디렉토리가 비어있지 않음
Error code 40: 기호 연결의 단계가 너무 많음
Error code 41: 알 수 없는 오류41
Error code 42: 적당한 형을 가진 메시지가 없음
Error code 43: 식별자 제거됨
Error code 44: 범위를 벗어난 채널 번호
Error code 45: 등급 2가 동기화되지 않음
Error code 46: 등급 3 멎었음
Error code 47: 등급 3 리셋
Error code 48: 범위를 벗어난 링크 번호
Error code 49: 규약 구동기에 연결되지 않음
Error code 50: 사용 가능한 CSI 구조가 없음
Error code 51: 등급 2 멎었음
Error code 52: 부적절한 교환
Error code 53: 잘못된 요청 기술자
Error code 54: 교환이 가득참
Error code 55: anode가 없음
Error code 56: 부적절한 요청 코드
Error code 57: 부적절한 슬롯
Error code 58: 알 수 없는 오류58
Error code 59: 잘못된 폰트 파일 형식
Error code 60: 장치가 스트림이 아님
Error code 61: 사용 가능한 자료가 없음
Error code 62: 타이머 시간 초과됨
Error code 63: 스트림 자원 부족
Error code 64: 기계가 네트워크 상에 있지 않습니다
Error code 65: 패키지가 설치되지 않음
Error code 66: 원격 개체입니다
Error code 67: 링크가 손상되었습니다
Error code 68: 광고 오류
Error code 69: Srmount 오류
Error code 70: 전송 중 통신 오류
Error code 71: 규약 오류
Error code 72: 여러개의 hop이 시도됨
Error code 73: RFS에 국한된 오류
Error code 74: 잘못된 메시지
Error code 75: 정의된 자료형으로 쓰기엔 너무 큰 값
Error code 76: 이름이 네트워크 상에서 단일하지 않음
Error code 77: 파일 기술자가 잘못된 상태에 있음
Error code 78: 원격 주소가 바뀌었음
Error code 79: 필요한 공유 라이브러리에 접근할 수 없습니다
Error code 80: 손상된 공유 라이브러리에 접근함
Error code 81: a.out의 .lib 절이 손상되었음
Error code 82: 너무 많은 동적 라이브러리와 링크하려고 시도하였음
Error code 83: 공유 라이브러리를 직접 실행할 수 없습니다
Error code 84: 부적절하거나 불완전한 다중바이트 또는 광역 문자
Error code 85: 중단된 시스템 호출은 재시작되어야 합니다
Error code 86: 스트림 파이프 오류
Error code 87: 사용자가 너무 많음
Error code 88: 비소켓상의 소켓 동작
Error code 89: 목적지 주소가 필요함
Error code 90: 메시지가 너무 깁니다
Error code 91: 소켓에 대한 규약이 잘못됨
Error code 92: 규약 사용 불가능
Error code 93: 규약이 지원되지 않음
Error code 94: 소켓 타입이 지원되지 않습니다
Error code 95: 명령이 지원되지 않음
Error code 96: 규약군이 지원되지 않음
Error code 97: 주소군이 규약에서 지원되지 않음
Error code 98: 주소가 이미 사용 중입니다
Error code 99: 요청된 주소를 배정할 수 없습니다
Error code 100: 네트워크가 죽었습니다
Error code 101: 네트워크가 접근 불가능합니다
Error code 102: 네트웍이 reset때문에 연결을 끊었습니다
Error code 103: 소프트웨어가 연결 중단을 초래했습니다
Error code 104: 연결이 상대편에 의해 끊어짐
Error code 105: 사용 가능한 버퍼 공간이 없음
Error code 106: 전송 종료지점이 이미 연결되어 있습니다
Error code 107: 전송 종료지점이 연결되어 있지 않습니다
Error code 108: 전송 종료지점이 지난 후에 보낼 수 없습니다
Error code 109: 참조가 너무 많음: 연결할 수 없습니다
Error code 110: 연결 시간 초과
Error code 111: 연결이 거부됨
Error code 112: 호스트가 죽었습니다
Error code 113: 호스트로 갈 루트가 없음
Error code 114: 이미 진행 중인 명령
Error code 115: 지금 진행 중인 명령
Error code 116: 끊어진 NFS 파일 핸들
Error code 117: 구조에 청소가 필요합니다
Error code 118: XENIX named 타입 파일이 아님
Error code 119: 사용 가능한 XENIX 세마포어가 없음
Error code 120 = Didn\t find key on read or update
Error code 121 = Duplicate key on write or update
Error code 122: Disk quota exceeded
Error code 123 = Someone has changed the row since it was read; Update with is recoverable
Error code 124 = Wrong index given to function
Error code 125: 알 수 없는 오류125
Error code 126 = Index file is crashed / Wrong file format
Error code 127 = Record-file is crashed
Error code 131 = Command not supported by database
Error code 132 = Old database file
Error code 133 = No record read before update
Error code 134 = Record was already deleted (or record file crashed)
Error code 135 = No more room in record file
Error code 136 = No more room in index file
Error code 137 = No more records (read after end of file)
Error code 138 = Unsupported extension used for table
Error code 139 = Too big row (>= 16 M)
Error code 140 = Wrong create options
Error code 141 = Duplicate unique key or constraint on write or update
Error code 142 = Unknown character set used
Error code 143 = Conflicting table definition between MERGE and mapped table
Error code 144 = Table is crashed and last repair failed
Error code 145 = Table was marked as crashed and should be repaired
Error code 146 = Lock timed out; Retry transaction
Error code 147 = Lock table is full; Restart program with a larger locktable
Error code 148 = Updates are not allowed under a read only transactions
Error code 149 = Lock deadlock; Retry transaction


Mysql - ErrNo
 
1000\hashchk\,
1001\isamchk\,
1002\NO\,
1003\YES\,
1004\Can\t create file \%-.64s\ (errno: %d)\,
1005\Can\t create table \%-.64s\ (errno: %d)\,
1006\Can\t create database \%-.64s\. (errno: %d)\,
1007\Can\t create database \%-.64s\. Database exists\,
1008\Can\t drop database \%-.64s\. Database doesn\t exist\,
1009\Error dropping database (can\t delete \%-.64s\, errno: %d)\,
1010\Error dropping database (can\t rmdir \%-.64s\, errno: %d)\,
1011\Error on delete of \%-.64s\ (errno: %d)\,
1012\Can\t read record in system table\,
1013\Can\t get status of \%-.64s\ (errno: %d)\,
1014\Can\t get working directory (errno: %d)\,
1015\Can\t lock file (errno: %d)\,
1016\Can\t open file: \%-.64s\. (errno: %d)\,
1017\Can\t find file: \%-.64s\ (errno: %d)\,
1018\Can\t read dir of \%-.64s\ (errno: %d)\,
1019\Can\t change dir to \%-.64s\ (errno: %d)\,
1020\Record has changed since last read in table \%-.64s\,
1021\Disk full (%s). Waiting for someone to free some space....\,
1022\Can\t write, duplicate key in table \%-.64s\,
1023\Error on close of \%-.64s\ (errno: %d)\,
1024\Error reading file \%-.64s\ (errno: %d)\,
1025\Error on rename of \%-.64s\ to \%-.64s\ (errno: %d)\,
1026\Error writing file \%-.64s\ (errno: %d)\,
1027\%-.64s\ is locked against change\,
1028\Sort aborted\,
1029\View \%-.64s\ doesn\t exist for \%-.64s\,
1030\Got error %d from table handler\,
1031\Table handler for \%-.64s\ doesn\t have this option\,
1032\Can\t find record in \%-.64s\,
1033\Incorrect information in file: \%-.64s\,
1034\Incorrect key file for table: \%-.64s\. Try to repair it\,
1035\Old key file for table \%-.64s\; Repair it!\,
1036\Table \%-.64s\ is read only\,
1037\Out of memory. Restart daemon and try again (needed %d bytes)\,
1038\Out of sort memory. Increase daemon sort buffer size\,
1039\Unexpected eof found when reading file \%-.64s\ (errno: %d)\,
1040\Too many connections\,
1041\Out of memory; Check if mysqld or some other process uses all available memory. If not you may have to use \ulimit\ to allow mysqld to use more memory or you can add more swap space\,
1042\Can\t get hostname for your address\,
1043\Bad handshake\,
1044\Access denied for user: \%-.32s@%-.64s\ to database \%-.64s\,
1045\Access denied for user: \%-.32s@%-.64s\ (Using password: %s)\,
1046\No Database Selected\,
1047\Unknown command\,
1048\Column \%-.64s\ cannot be null\,
1049\Unknown database \%-.64s\,
1050\Table \%-.64s\ already exists\,
1051\Unknown table \%-.64s\,
1052\Column: \%-.64s\ in %-.64s is ambiguous\,
1053\Server shutdown in progress\,
1054\Unknown column \%-.64s\ in \%-.64s\,
1055\%-.64s\ isn\t in GROUP BY\,
1056\Can\t group on \%-.64s\,
1057\Statement has sum functions and columns in same statement\,
1058\Column count doesn\t match value count\,
1059\Identifier name \%-.100s\ is too long\,
1060\Duplicate column name \%-.64s\,
1061\Duplicate key name \%-.64s\,
1062\Duplicate entry \%-.64s\ for key %d\,
1063\Incorrect column specifier for column \%-.64s\,
1064\%s near \%-.80s\ at line %d\,
1065\Query was empty\,
1066\Not unique table/alias: \%-.64s\,
1067\Invalid default value for \%-.64s\,
1068\Multiple primary key defined\,
1069\Too many keys specified. Max %d keys allowed\,
1070\Too many key parts specified. Max %d parts allowed\,
1071\Specified key was too long. Max key length is %d\,
1072\Key column \%-.64s\ doesn\t exist in table\,
1073\BLOB column \%-.64s\ can\t be used in key specification with the used table type\,
1074\Too big column length for column \%-.64s\ (max = %d). Use BLOB instead\,
1075\Incorrect table definition; There can only be one auto column and it must be defined as a key\,
1076\%s: ready for connections\n\,
1077\%s: Normal shutdown\n\,
1078\%s: Got signal %d. Aborting!\n\,
1079\%s: Shutdown Complete\n\,
1080\%s: Forcing close of thread %ld user: \%-.32s\n\,
1081\Can\t create IP socket\,
1082\Table \%-.64s\ has no index like the one used in CREATE INDEX. Recreate the table\,
1083\Field separator argument is not what is expected. Check the manual\,
1084\You can\t use fixed rowlength with BLOBs. Please use \fields terminated by\.\,
1085\The file \%-.64s\ must be in the database directory or be readable by all\,
1086\File \%-.80s\ already exists\,
1087\Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld\,
1088\Records: %ld Duplicates: %ld\,
1089\Incorrect sub part key. The used key part isn\t a string, the used length is longer than the key part or the table handler doesn\t support unique sub keys\,
1090\You can\t delete all columns with ALTER TABLE. Use DROP TABLE instead\,
1091\Can\t DROP \%-.64s\. Check that column/key exists\,
1092\Records: %ld Duplicates: %ld Warnings: %ld\,
1093\INSERT TABLE \%-.64s\ isn\t allowed in FROM table list\,
1094\Unknown thread id: %lu\,
1095\You are not owner of thread %lu\,
1096\No tables used\,
1097\Too many strings for column %-.64s and SET\,
1098\Can\t generate a unique log-filename %-.64s.(1-999)\n\,
1099\Table \%-.64s\ was locked with a READ lock and can\t be updated\,
1100\Table \%-.64s\ was not locked with LOCK TABLES\,
1101\BLOB column \%-.64s\ can\t have a default value\,
1102\Incorrect database name \%-.100s\,
1103\Incorrect table name \%-.100s\,
1104\The SELECT would examine too many records and probably take a very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok\,
1105\Unknown error\,
1106\Unknown procedure \%-.64s\,
1107\Incorrect parameter count to procedure \%-.64s\,
1108\Incorrect parameters to procedure \%-.64s\,
1109\Unknown table \%-.64s\ in %-.32s\,
1110\Column \%-.64s\ specified twice\,
1111\Invalid use of group function\,
1112\Table \%-.64s\ uses an extension that doesn\t exist in this MySQL version\,
1113\A table must have at least 1 column\,
1114\The table \%-.64s\ is full\,
1115\Unknown character set: \%-.64s\,
1116\Too many tables. MySQL can only use %d tables in a join\,
1117\Too many columns\,
1118\Too big row size. The maximum row size, not counting BLOBs, is %d. You have to change some fields to BLOBs\,
1119\Thread stack overrun: Used: %ld of a %ld stack. Use \mysqld -O thread_stack=#\ to specify a bigger stack if needed\,
1120\Cross dependency found in OUTER JOIN. Examine your ON conditions\,
1121\Column \%-.64s\ is used with UNIQUE or INDEX but is not defined as NOT NULL\,
1122\Can\t load function \%-.64s\,
1123\Can\t initialize function \%-.64s\; %-.80s\,
1124\No paths allowed for shared library\,
1125\Function \%-.64s\ already exist\,
1126\Can\t open shared library \%-.64s\ (errno: %d %-.64s)\,
1127\Can\t find function \%-.64s\ in library\,
1128\Function \%-.64s\ is not defined\,
1129\Host \%-.64s\ is blocked because of many connection errors. Unblock with \mysqladmin flush-hosts\,
1130\Host \%-.64s\ is not allowed to connect to this MySQL server\,
1131\You are using MySQL as an anonymous users and anonymous users are not allowed to change passwords\,
1132\You must have privileges to update tables in the mysql database to be able to change passwords for others\,
1133\Can\t find any matching row in the user table\,
1134\Rows matched: %ld Changed: %ld Warnings: %ld\,
1135\Can\t create a new thread (errno %d). If you are not out of available memory, you can consult the manual for a possible OS-dependent bug\,
1136\Column count doesn\t match value count at row %ld\,
1137\Can\t reopen table: \%-.64s\,
1138\Invalid use of NULL value\,
1139\Got error \%-.64s\ from regexp\,
1140\Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause\,
1141\There is no such grant defined for user \%-.32s\ on host \%-.64s\,
1142\%-.16s command denied to user: \%-.32s@%-.64s\ for table \%-.64s\,
1143\%-.16s command denied to user: \%-.32s@%-.64s\ for column \%-.64s\ in table \%-.64s\,
1144\Illegal GRANT/REVOKE command. Please consult the manual which privileges can be used.\,
1145\The host or user argument to GRANT is too long\,
1146\Table \%-.64s.%-.64s\ doesn\t exist\,
1147\There is no such grant defined for user \%-.32s\ on host \%-.64s\ on table \%-.64s\,
1148\The used command is not allowed with this MySQL version\,
1149\You have an error in your SQL syntax\,
1150\Delayed insert thread couldn\t get requested lock for table %-.64s\,
1151\Too many delayed threads in use\,
1152\Aborted connection %ld to db: \%-.64s\ user: \%-.32s\ (%-.64s)\,
1153\Got a packet bigger than \max_allowed_packet\,
1154\Got a read error from the connection pipe\,
1155\Got an error from fcntl()\,
1156\Got packets out of order\,
1157\Couldn\t uncompress communication packet\,
1158\Got an error reading communication packets\,
1159\Got timeout reading communication packets\,
1160\Got an error writing communication packets\,
1161\Got timeout writing communication packets\,
1162\Result string is longer than max_allowed_packet\,
1163\The used table type doesn\t support BLOB/TEXT columns\,
1164\The used table type doesn\t support AUTO_INCREMENT columns\,
1165\INSERT DELAYED can\t be used with table \%-.64s\, because it is locked with LOCK TABLES\,
1166\Incorrect column name \%-.100s\,
1167\The used table handler can\t index column \%-.64s\,
1168\All tables in the MERGE table are not identically defined\,
1169\Can\t write, because of unique constraint, to table \%-.64s\,
1170\BLOB column \%-.64s\ used in key specification without a key length\,
1171\All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead\,
1172\Result consisted of more than one row\,
1173\This table type requires a primary key\,
1174\This version of MySQL is not compiled with RAID support\,
1175\You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column\,
1176\Key \%-.64s\ doesn\t exist in table \%-.64s\,
1177\Can\t open table\,
1178\The handler for the table doesn\t support check/repair\,
1179\You are not allowed to execute this command in a transaction\,
1180\Got error %d during COMMIT\,
1181\Got error %d during ROLLBACK\,
1182\Got error %d during FLUSH_LOGS\,
1183\Got error %d during CHECKPOINT\,
1184\Aborted connection %ld to db: \%-.64s\ user: \%-.32s\ host: `%-.64s\ (%-.64s)\,
1185\The handler for the table does not support binary table dump\,
1186\Binlog closed, cannot RESET MASTER\,
1187\Failed rebuilding the index of dumped table \%-.64s\,
1188\Error from master: \%-.64s\,
1189\Net error reading from master\,
1190\Net error writing to master\,
1191\Can\t find FULLTEXT index matching the column list\,
1192\Can\t execute the given command because you have active locked tables or an active transaction\,
1193\Unknown system variable \%-.64\,
1194\Table \%-.64s\ is marked as crashed and should be repaired\,
1195\Table \%-.64s\ is marked as crashed and last (automatic?) repair failed\,
1196\Warning: Some non-transactional changed tables couldn\t be rolled back\,
1197\Multi-statement transaction required more than \max_binlog_cache_size\ bytes of storage. Increase this mysqld variable and try again\,
1198\This operation cannot be performed with a running slave, run SLAVE STOP first\,
1199\This operation requires a running slave, configure slave and do SLAVE START\,
1200\The server is not configured as slave, fix in config file or with CHANGE MASTER TO\,
1201\Could not initialize master info structure, check permisions on master.info\,
1202\Could not create slave thread, check system resources\,
1203\User %-.64s has already more than \max_user_connections\ active connections\,
1204\You may only use constant expressions with SET\,
1205\Lock wait timeout exceeded; Try restarting transaction\,
1206\The total number of locks exceeds the lock table size\,
1207\Update locks cannot be acquired during a READ UNCOMMITTED transaction\,
1208\DROP DATABASE not allowed while thread is holding global read lock\,
1209\CREATE DATABASE not allowed while thread is holding global read lock\,
1210\Wrong arguments to %s\,
1211\%-.32s@%-.64s is not allowed to create new users\,
1212\Incorrect table definition; All MERGE tables must be in the same database\,
1213\Deadlock found when trying to get lock; Try restarting transaction\,
1214\The used table type doesn\t support FULLTEXT indexes\,
1215\Cannot add foreign key constraint\,
1216\Cannot add a child row: a foreign key constraint fails\,
1217\Cannot delete a parent row: a foreign key constraint fails\,

출처 - 네이버 블로그

by 뭔일이여 2007. 2. 5. 16:53

HTTP 1.1 status codes [TOP]

100 : Continue
101 : Switching protocols
200 : OK, 에러없이 전송 성공
201 : Created, POST 명령 실행 및 성공
202 : Accepted, 서버가 클라이언트 명령을 받음
203 : Non-authoritative information, 서버가 클라이언트 요구 중 일부만 전송
204 : No content, 클라언트 요구을 처리했으나 전송할 데이터가 없음
205 : Reset content
206 : Partial content
300 : Multiple choices, 최근에 옮겨진 데이터를 요청
301 : Moved permanently, 요구한 데이터를 변경된 임시 URL에서 찾았음
302 : Moved temporarily, 요구한 데이터가 변경된 URL에 있음을 명시
303 : See other, 요구한 데이터를 변경하지 않았기 때문에 문제가 있음
304 : Not modified
305 : Use proxy
400 : Bad request, 클라이언트의 잘못된 요청으로 처리할 수 없음
401 : Unauthorized, 클라이언트의 인증 실패
402 : Payment required, 예약됨
403 : Forbidden, 접근이 거부된 문서를 요청함
404 : Not found, 문서를 찾을 수 없음
405 : Method not allowed, 리소스를 허용안함
406 : Not acceptable, 허용할 수 없음
407 : Proxy authentication required, 프록시 인증 필요
408 : Request timeout, 요청시간이 지남
409 : Conflict
410 : Gone, 영구적으로 사용할 수 없음
411 : Length required
412 : Precondition failed, 전체조건 실패
413 : Request entity too large,
414 : Request-URI too long, URL이 너무 김
415 : Unsupported media type
500 : Internal server error, 내부서버 오류(잘못된 스크립트 실행시)
501 : Not implemented, 클라이언트에서 서버가 수행할 수 없는 행동을 요구함
502 : Bad gateway, 서버의 과부하 상태
503 : Service unavailable, 외부 서비스가 죽었거나 현재 멈춤 상태
504 : Gateway timeout
505 : HTTP version not supported

100: Continue
101: Switching Protocols
200: OK, 에러없이 전송 성공
202: Accepted, 서버가 클라이언트의 명령을 받음.
203: Non-authoritavive Information, 서버가 클라이언트 요구중 일부만 정송
204: Non Content, 클라이언트 요구를 처리했으나 전송할 데이터가 없음.
205: Reset Content
206: Partial Content
300: Multiple Choisces, 최근에 옮겨진 데이터를 요청
301: Moved Permanently, 요구한 데이터를 변경된 임시 URL에서 찾았음.
302: Moved Permanently, 요구한 데이터가 변경된 URL에 있음을 명시.
303: See Other, 요구한 데이터를 변경하지 않았기 때문에 문제가 있음.
304: Not modified
305: Use Proxy
400: Bad Request, 요청실패문법상 오류가 있어, 서버가 요청사항을 이해하지 못함, 클라이언트는 수정없이 요청사항을 반복하지 않을 것이다.
401.1: Unauthorized, 권한 없음 (접속실패)이 에러는 서버에 로그온 하려는 요청사항이 서버에 들어있는 권한과 비교했을 때 맞지 않을 경우 발생한다. 이 경우, 여러분이 요청한 자원에 접근할 수 있는 권한을 부여받기 위해 서버 운영자에게 요청해야 할 것이다.
401.2: Unauthorized, 권한 없음(서버설정으로 인한 접속 실패)이 에러는 서버에 로그온 하려는 요청사항이 서버에 들어있는 권한과 비교했을 때 맞지않을 경우 발생한다. 이것은 일반적을 으로 적절한 www-authenticate head field를 전송하지 않아서 발생한다.
401.3: Unauthorized, 권한 없음(자원에 대한 ACL에 기인한 권한 없음)이 에러는 클라이언트가 특정 자원에 접근할 수 없을 때 발생한다. 이 자원은 페이지가 될 수도 있고 , 클라이언트의 주소 입력란에 명기된 파일일 수도 있다. 아니면 클라이언트가 행당 주소로 들어갈 때 이용되는 또 다른 파일일 수도 있다. 여러분이 접근할 전체 주소를 다시 확인해 보고 웹 서버 운영자에게 여러분이 자원에 접근할 권한이 있는지를 확인해 본다.
401.4: Unauthorized, 권한 없음(필터에 의한 권한 부여 실패)이 에러는 웹 서버가 서버에 접속하는 사용자들을 확인하기 위해 설치한 필터 프로그램이 있음을 의미한다. 서버에 접속한는 데 이용되는 인증 과정이 이런 필터 프로그램에 의해 거부되었다.
401.5: Unauthorized, 권한 없음(ISA PI/CGI 애플리케이션에 의한 권한부여 실패)이 에러는 여러분이 이용하려는 웹 서버의 어드레스에 ISA PI나 CGI프로그램이 설치되어 있어 사용자의 권한을 검증하고 있음을 의미한다. 서버에 접속하는 데 이용되는 인증 과정이 이 프로그램에 의해 거부되었다.
402: Payment Required, 예약됨.
403.1: Forbidden, 금지(수행접근 금지)이 오류는 CGI나 ISAPI,혹은 수행시키지 못하도록 되어있는 디렉토리 내의 실행 파일을 수행시키려고 했을 때 발생한다.
403.2: Forbidden,  금지(읽기 접근 금지)이 에러는 브라우저가 접근한 디렉토리에 가용한 디폴트 페이지가 없을 경우에 발생한다. 아니면 Eecute나 Script로 분한이 부여된 디렉토리에 들어있는 HTML페이지를 보려했을 때 발생한다.
403.4: Forbidden,  금지(SSL 필요함)이 에러는 여러분이 접근하려는 페이지가 SSL로 보안유지 되고 있는 것일 때 발생한다. 이것을 보기 위해서 여러분은 주소를 입력하기 전에 먼저 SSL을 이용할 수 있어야 한다.
403.5: Forbidden,  금지 (SSL 128필요함)이 에러는 접근하려는 페이지가 SSL로 보안유지 되고 있는 것일 때 발생한다. 이 자원을 보기 위해서는 여러분의 브라우저가 SSL의 행당 레벌을 지원해야 한다. 여러분의 브라우저가 128비트의 SSL을 지원하는 지를 확인해 본다.
403.6: Forbidden,  금지(IP 주소 거부됨)이 에러는 서버가 사이트에 접근이 허용되지 않은 IP주소를 갖고 있는데, 사용자가 이 주소로 접근하려 했을 때 발생한다.
403.7: Forbidden,  금지(클라이언트 확인 필요)이 에러는 여러분이 접근하려는 자원이 서버가 인식하기 위해 여러분의 브라우저에게 클라이언트 SSL을 요청하는 경우 발생한다. 이것은 여러분이 자원을 이용할 수 있는 상용자임을 입증하는데 사용된다.
403.8: Forbidden,  금지 (사이트 접근 거부됨)이 에러는 웹 서버가 요청사항을 수행하고 있지 않거나, 해당 사이트에 접근하는 것이 허락되지 않았을 경우 발생한다.
403.9: Forbidden, 접근 금지(연결된 사용자수 과다)이 에러는 웹서버 BUSY 상태에 있어서 여러분의 요청을 수행할수 없을 경우에 발생한다. 잠시 후에 다시 접근해 보도록 한다.
403.10: Forbidden,  접근금지(설정이 확실 하지 않음)이 순간 웹 서버의 설정쪽에 문제가 있다.
403.11: Forbidden,  접근금지(패스워드 변경됨)이 에러는 사용자 확인단계에서 잘못된 패스워드를 입력했을 경우 발생한다. 페이지를 갱신한 후 다시 시도해 본다.
403.12: Forbidden,  접근금지(Mapper 접근 금지됨)여러분의 클이언트 인증용 맵이 해당 웹 사이트에 접근하는 것이 거부되었다. 사이트 운영자에게 클라이언트 인증 허가를 요청한다. 또한 여러분은 여러분의 클라이언트 인증을 바꿀 수도 있다.
404: Not Found, 문서를 찾을 수 없음.웹 서버가 요청한 파일이나 스크립트를 찾지 못했다. URL을 다시 잘 보고 주소가 올바로 입력되었는지 확인해본다.- 해결방법: a.도구 ▶ 인터넷옵션 ▶ 일반 ▶ 쿠키삭제, 파일삭제, 목록지우기                  b.도구 ▶ 인터넷옵션 ▶ 고급 ▶ [URL을 항상 UTF-8FH로 보냄] 체크 해제.
405: Method not allowed, 메쏘드 허용안됨Request 라인에 명시된 메쏘드를 수행하기 위해 해당 자원의 이용이 허용되지 않았다. 여러분이 요청한 자원에 적절한 MIME 타입을 갖고 있는지 확인해 본다.
406: Not Acceptable, 받아들일 수 없음요청 사항에 필요한 자원은 요청 사항으로 전달된 Acceptheader에 따라 "Not Acceptable"인 내용을 가진 Response 개체만을 만들 수 있다.
407: Proxy Authentication Required, 대리(Proxy) 인증이 필요함해당 요청이 수행되도록 proxy 서버에게 인증을 받아야 한다. proxy서버로 로그온 한 후에 다기 시도해 본다.
408: Request timeout, 요청시간이 지남
409: Conflict
410: Gone, 영구적으로 사용할 수 없음.
411: Length Required
412: Precondition Failed, 선결조건 실패Request-header field에 하나 이상에 선결조건에 대한 값이 서버에서 테스트 결과 FALSE로 나왔을 경우에 발생한다. 현재 자원의 메타-정보가 하나 이상의 자원에 적용되는 것을 막기 위한 클라이언트 선결조건이 의도되어졌다.
413: Request entity too large
414: Request-URI too long, 요청한 URI가 너무 길다요청한 URI가 너무 길어서 서버가 요청 사항의 이행을 거부했다. 이렇게 희귀한 상황은 아래와 같은 경우에만 발생한다. 클라이언트가 긴 탐색용 정보를 가지고 POST 요청을 GET으로 부적절하게 전환했다. 클라이언트가 Redirection문제를 접하게 되었다. 서버가, 몇몇 서버가 사용하고 있는 요청한 URI 를 읽고 처리하는 고정된 길이의 메로리 버퍼를 이용해 보안체계에 들어가려는 , 클라이언트에 의한 공격을 받고 있다.
415: Unsupported media type
500: Internal Server Error, 서버 내부 오류웹 서버가 요청사항을 수행할 수 없다. 다시 한 번 요청해 본다.
501: Not Implemented, 적용안됨웹 서버가 요청사항을 수행하는 데 필요한 기능을 지원하지 않는다. 에러가 발생한 URL을 확인한 후에, 문제가 지속될 경우에는 웹 서버 운영자에게 연락한다.
502: Bad gateway, 게이트웨이 상태 나쁨/서버의 과부하 상태Gateway나 proxy로 활동하고 있는 서버가 요구 사항을 접수한 upstream 서버로부터 불명확한 답변을 접수 했을 때 발생한다. 만약 문제가 지속된다면 웹 서버 운영자와 상의해 본다.
503: Service Unavailable, 외부 서비스가 죽었거나 현재 멈춘 상태 또는 이용할 수 없는 서비스서버는 현재 일시적인 과부하 또는 관리(유지,보수) 때문에 요청을 처리할 수 없다.이것은 약간의 지연후 덜게될 일시적인 상태를 말한다.Retry-After 헤더에 지연의 길이가 표시하게 될지도 모른다.만약 Retry-After를 받지 못했다면 클라이언트는 500 응답을 위해 하고자 했는것처럼 응답을 처리해야 한다. 상태코드의 존재는 서버가 과부하가 걸릴때 그것을 사용해야한다는 것을 말하는 것이 아니다. 몇몇 서버는 접속을 거부하는 것을 바랄지도 모른다.
504: Gateway timeout
505: HTTP Version Not Supported

by 뭔일이여 2007. 1. 21. 23:17

1. Apache
1) Version 1.3.X
http://www.apache.org/dist/httpd/CHANGES_1.3
2006년 11월 15일자 최신버전은 1.3.37

2) Version 2.0.X
http://www.apache.org/dist/httpd/CHANGES_2.0
2006년 11월 15일자 최신버전은 2.0.59

3) Version 2.2.X
http://www.apache.org/dist/httpd/CHANGES_2.2
2006년 11월 15일자 최신버전은 2.2.3

2. Php
1) Version 4.X
http://www.php.net/ChangeLog-4.php
2006년 11월 15일자 최신버전은 4.4.4

2) Version 5.X
http://www.php.net/ChangeLog-5.php
2006년 11월 15일자 최신버전은 5.2.0

3. Mysql
1) Version 4.1.X
http://dev.mysql.com/doc/refman/4.1/en/news.html
2006년 11월 15일자 최신버전은 4.1.21

2) Version 5.0.X
http://dev.mysql.com/doc/refman/5.0/en/news.html
2006년 11월 15일자 최신버전은 5.0.26

3) Version 5.1.X
http://dev.mysql.com/doc/refman/5.1/en/news.html
2006년 11월 15일자 최신버전은 5.1.12

출처 - phpschool

by 뭔일이여 2007. 1. 16. 17:44



저자:
Brad Neuberg, 한동훈 역

여기서는 AJAX 응용 프로그램에 즐겨찾기와 뒤로 이동을 지원하는 오픈 소스 자바스크립트 라이브러리를 소개할 것이다. 이 글을 마지막까지 보게된다면 구글맵스지메일과 같은 곳들조차 제대로 지원하지 못했던 웹 사이트에서의 즐겨찾기, 앞으로 이동, 뒤로 이동과 같은 AJAX의 문제들을 해결할 수 있게 될 것이다.

"AJAX: 즐겨찾기와 뒤로 이동을 다루는 방법"에서는 [1]에이잭스(AJAX) 응용 프로그램들이 현재 당면하고 있는 즐겨찾기, 뒤로 이동과 같은 중요한 문제들을 설명하고, 이 문제를 해결하기 위한 오픈 소스 프레임워크인 RSH(Really Simple History) 라이브러리를 소개하고, 실제 예제들을 몇 가지 소개할 것이다.

([1]역주: 영어사전에서 AJAX는 에이잭스로 소개되며, 그리스의 신화의 아이아스나 오딧세이의 아이아스를 의미한다. sys-con의 AJAX & Rich Internet Applications 프레젠테이션에서도 그 발음을 확인할 수 있다. 네덜란드 축구팀의 이름을 딴 아약스, 또는 아작스 등으로 불리기도 한다. 한편, 세제 제조회사인 Ajax Industries는 "에이잭스社"로 옮긴다.)

여기서 소개할 프레임워크의 주요 부분은 두 개로 나뉘어진다. 첫째는 클라이언트의 정보를 갖고 있는 임시 세션 캐시를 사용하기 위해 숨겨진 HTML 폼을 사용한다. 이 캐시는 어떤 지점으로 이동하거나 페이지를 떠나는 경우에도 사용할 수 있다. 둘째는 A 태그와 숨겨진 iframe을 사용해서 브라우저 히스토리를 가로챈 다음 브라우저 히스토리 이벤트를 기록하고, 뒤로 이동과 앞으로 이동 버튼에 연결한다. 이 두 가지 기능은 모두 개발시에 쉽게 이용할 수 있도록 간단한 자바스크립트 라이브러리로 되어있다.

문제

즐겨찾기와 뒤로 이동은 여러 페이지로 구성된 전형적인 웹 응용 프로그램에서 매우 유용하다. 사용자가 웹 사이트를 항해할 때, 브라우저의 주소 창은 새로운 URL로 업데이트되며, 나중에 이 주소를 다시 방문하기 위해 이메일에 붙여넣거나 즐겨찾기에 추가할 수 있다. 뒤로 이동, 앞으로 이동 버튼들도 올바르게 동작하며, 사용자는 방문했던 페이지들을 자유로이 이동할 수 있다.

그러나, 에이잭스 응용 프로그램은 웹 페이지 하나에서 동작하는 복잡한 프로그램이기 때문에 예외적인 응용 프로그램이다. 브라우저는 이런 기능을 위해 만들어지지 않았다. 웹 응용 프로그램들이 마우스 클릭을 할 때마다 완전히 새로운 페이지를 가져올 수 있게 되었어도 브라우저는 과거에 사로잡혀 있다.

지메일과 같은 AJAX 소프트웨어에서 사용자가 기능을 선택하고, 응용 프로그램의 상태를 바꾸어도 브라우저의 주소창은 항상 같은 위치만 갖고 있기 때문에 응용 프로그램의 특정 화면에 대해 즐겨찾기를 축가하는 것은 불가능하다. 뿐만 아니라, 사용자가 이전 작업을 원상태로 되돌리기위해 뒤로 이동 버튼을 클릭하면 브라우저가 응용 프로그램의 웹 페이지를 떠나기 때문에 사용자들은 놀라게 된다.

해결책

오픈소스 RSH(Really Simple History) 프레임워크는 이러한 문제를 해결하고, 에이잭스 응용 프로그램에서 즐겨찾기, 뒤로 이동, 앞으로 이동을 제어할 수 있게 해준다. RSH는 현재 베타 버전이며, 파이어폭스 1.0, 넷스케이프 7 이상, 인터넷 익스플로러 6 이상의 버전에서 동작하며, 사파리는 현재 지원되지 않는다.(이에 대한 설명은 나의 웹 로그에서 Coding in Paradise: Safari: No DHTML History Possible를 참고하기 바란다.)

몇몇 에이잭스 프레임워크는 현재 즐겨찾기와 히스토리 문제를 해결하려 하고 있지만 이들 프레임워크는 구현 방식 때문에 몇가지 중요한 버그들을 해결하지 못하고 있다.(보다 자세한 사항은 "Coding in Paradise: AJAX History Libraries"를 참고한다) 게다가, 많은 에이잭스 [2]히스토리 프레임워크는 BackbaseDojo 같은 보다 큰 라이브러리안에 통합된 형태로 되어 있다. 이들 프레임워크는 AJAX 응용 프로그램에 대해서 완전히 다른 프로그래밍 모델을 제공하고 있으며, 개발자가 히스토리 기능을 사용하기 위해서는 완전히 새로운 접근방법을 사용할 것을 강요받게 된다.

([2]역주: 히스토리(History)는 "기록" 또는 "방문기록"으로 옮기지만 대부분이 히스토리에 익숙하기 때문에 번역하지 않았다)

반면에, RSH는 기존 AJAX 시스템에 포함시킬 수 있는 간단한 모듈로 되어 있다. 뿐만 아니라, RSH 라이브러리는 다른 히스토리 프레임워크들이 갖고 있는 버그들을 피하기 위한 기술들을 사용하고 있다.

RSH 히스토리 프레임워크는 자바스크립트 클래스 DhtmlHistory, HistoryStorage로 구성되어있다.

DhtmlHistory 클래스는 에이잭스 응용 프로그램을 위한 히스토리 추상화를 제공한다. 즉, 에이잭스 페이지는 브라우저에 새 위치와 그에 대한 히스토리 데이터를 지정한 히스토리 이벤트를 추가하는 add()를 호출한다. DhtmlHistory 클래스는 A 태그에 #new-location과 같은 해쉬를 사용해서 브라우저의 현재 URL을 업데이트하고, 히스토리 데이터와 새 URL을 연결한다. 에이잭스 응용 프로그램 자체를 히스토리 리스너(listener)로 등록하고, 사용자가 뒤로 이동, 앞으로 이동 버튼을 사용해서 이동할 때 마다 히스토리 이벤트는 add() 호출로 저장했던 히스토리 데이터와 브라우저의 위치를 제공한다.

개발자는 HistoryStorage 클래스를 사용해서 어떤 크기의 히스토리 데이터라도 저장할 수 있다. 일반 페이지에서 사용자가 새로운 웹 사이트로 이동할 때 브라우저는 이전 웹 페이지의 모든 응용 프로그램을 제거하고, 응용 프로그램과 자바스크립트의 상태를 정리한다. 따라서, 사용자가 뒤로 이동 버튼을 사용하여 이전 페이지로 돌아가면 모든 데이터가 사라진다. HistoryStorage 클래스는 put(), get(), hasKey()와 같은 간단한 해쉬 테이블 메서드를 제공하는 API를 통해서 이 문제를 해결한다. 사용자가 웹 페이지를 떠난 다음에도 개발자는 이들 메서드를 사용해서 데이터를 저장할 수 있다. 사용자가 뒤로 이동 버튼을 사용해서 돌아오면 HistoryStorage 클래스를 사용해서 데이터에 접근할 수 있다. 이 기능은 사용자가 웹 페이지를 떠난 후에도 브라우저가 폼 양식에 있는 값들을 자동으로 저장한다는 사실을 이용한 것으로, 숨겨진 폼 필드를 사용해서 구현됐다.

예제

이제 바로 간단한 예제로 살펴보자.

먼저, RSH 프레임워크를 사용할 페이지는 dhtmlHistory.js 스크립트를 반드시 인클루드해야 한다.

<!-- Load the Really Simple
       History framework -->
<script type="text/javascript"
            src="../../framework/dhtmlHistory.js">
</script>

DHTML 히스토리 응용 프로그램은 에이잭스 웹 페이지가 있는 디렉터리에 blank.html 파일을 포함시켜야 한다. 이 파일은 RSH 프레임워크에 함께 들어있으며, 인터넷 익스플로러에서 사용한다. 여담이지만, 인터넷 익스플로러는 히스토리 변경 사항을 추적하고 추가하기 위해 "숨겨진 iframe"을 사용한다. 히스토리 기능이 제대로 동작하기 위해서는 실제 위치를 가리키는 것이 필요한데, 이를 위해 비어있는 iframe을 사용한다. 그래서 이름도 blank.html이다.

RSH 프레임워크는 브라우저 히스토리를 조작하기 위한 진입점으로 dhtmlHistory라는 전역 객체를 생성한다. dhtmlHistory로 작업하는 첫번째 단계는 페이지 로딩이 끝난 후에 이 객체를 초기화하는 것이다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();

다음으로, 개발자는 히스토리 변경 이벤트를 [3]구독하기 위해 dhtmlHistory.addListener()를 사용해야 한다. 이 메서드는 DHTML 히스토리가 변경될 때, 페이지의 새로운 위치, 히스토리 변경 이벤트와 관련된 히스토리 데이터를 인자로 받는 콜백 함수를 인자로 받는다.

([3]역주: 이벤트 구독보다는 이벤트 감시가 더 적절한 표현이지만 원문이 subscribe이므로 구독으로 옮김)

window.onload = initialize;
     
function initialize() {
// DHTML 히스토리 프레임워크를 초기화한다
   dhtmlHistory.initialize();
   
// HTML 히스토리 변경 이벤트를 구독한다
   dhtmlHistory.addListener(historyChange);

historyChange() 메서드는 사용자가 새 위치로 이동한 후의 newLocation과 히스토리 변경 이벤트와 관계된 historyData를 인자로 받는 함수로 이해하기 쉽다.

/** 히스토리 변경 이벤트를 받기 위한 콜백 */
function historyChange(newLocation,
                                  historyData) {
   debug("A history change has occurred: "
            + "newLocation="+newLocation
            + ", historyData="+historyData,
            true);
}

위에서 사용한 debug() 메서드는 예제 소스 파일에 정의된 유틸리티 함수로 전체 예제 안에 포함되어 있다. debug()는 웹 페이지안에 메시지를 출력한다. 두번째 인자는 불리언(boolean) 타입으로 위 인자에서는 true를 사용했다. true를 사용하면 앞의 메시지를 모두 정리한 다음에 새로운 디버그 메시지를 출력한다.

개발자는 add() 메서드를 사용해서 히스토리 이벤트를 추가한다. 히스토리 이벤트를 추가하는 것은 edit:SomePage와 같이 히스토리 변경 이벤트와 함께 저장할 historyData 값을 제공하기 위한 새 위치를 지정하는 것이다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();
   
   // subscribe to DHTML history change
   // events
   dhtmlHistory.addListener(historyChange);
         
   // if this is the first time we have
   // loaded the page...
   if (dhtmlHistory.isFirstLoad()) {
      debug("Adding values to browser "
               + "history", false);
      // start adding history
      dhtmlHistory.add("helloworld",
                               "Hello World Data");
      dhtmlHistory.add("foobar", 33);
      dhtmlHistory.add("boobah", true);
         
      var complexObject = new Object();
      complexObject.value1 =
                           "This is the first value";
      complexObject.value2 =
                           "This is the second data";
      complexObject.value3 = new Array();
      complexObject.value3[0] = "array 1";
      complexObject.value3[1] = "array 2";
         
      dhtmlHistory.add("complexObject",
                               complexObject);

add()를 호출하는 즉시 사용자 브라우저의 URL 툴바에 새로운 위치가 표시된다. 예를 들어, http://codinginparadise.org/my_ajax_app 주소의 에이잭스 웹 페이지에서 dhtmlHistory.add( "helloworld", "Hello World Data" )를 호출하면 사용자는 브라우저의 URL 툴바에서 다음 주소를 보게 된다.

http://codinginparadise.org/my_ajax_app#helloworld

사용자는 이 페이지를 북마크할 수 있다. 사용자가 이 북마크를 이용하면 에이잭스 응용 프로그램은 #helloworld 값을 읽어서 웹 페이지를 초기화할 수 있다. 해시 # 다음의 위치 정보는 RSH 프레임워크에 의해 투명하게 인코딩과 디코딩이 수행된다.

historyData는 URL을 사용하는 것 보다 쉽게 에이잭스 위치 변화에 따른 복잡한 상태들을 저장할 수 있게 해준다. historyData는 숫자, 문자열, 객체와 같은 자바스크립트 타입으로 사용할 수 있는 값이다. 이를 사용하는 예로는 사용자가 DHTML 텍스트 에디터에서 다른 페이지로 이동하는 경우에 에디터의 내용을 모두 저장하는 것이다. 사용자가 뒤로 이동 버튼을 클릭해서 다시 DHTML 페이지로 돌아오면 브라우저는 히스토리 변경 리스너에게 객체를 돌려주게 된다.

개발자는 중첩된 객체나 복잡한 상태를 표현하는 배열과 같은 자바스크립트 객체 전체를 historyData에 사용할 수 있다. 히스토리 데이터에는 간단한 데이터 타입이나 NULL 타입 뿐만 아니라 JSON(자바스크립트 객체 표기법)으로 표현할 수 있는 무엇이든 될 수 있다. 그러나, DOM 객체에 대한 참조나 XMLHttpRequest와 같은 스크립트 가능한 브라우저 객체는 저장되지 않는다. historyData는 북마크와 함께 보존되는 데이터가 아니며, 브라우저를 종료하거나, 브라우저 캐시를 제거하거나, 사용자가 히스토리를 정리하면 사라지는 데이터이다.

dhtmlHistory를 사용하는 마지막 단계는 isFirstLoad() 메서드이다. 어떤 브라우저에서는 웹 페이지를 항해할 때 다른 페이지로 이동했다가 뒤로 이동 버튼을 눌러서 처음 사이트로 돌아오면 첫번째 페이지가 완전히 재로딩되고 onload 이벤트가 발생한다. 페이지를 반복적으로 재로딩하는 경우가 아니라 처음 로드될 때만 특별한 방법으로 초기화하길 원하는 코드를 망쳐버릴 수 있다. isFirstLoad() 메서드는 웹 페이지를 처음 로드한 경우와 사용자가 브라우저 히스토리에 저장된 웹 페이지에서 뒤로 이동한 경우를 구별해준다.

예제 코드에서는 페이지가 처음 로드되었을 때 히스토리 이벤트를 추가하길 원한다. 페이지가 로드된 다음에 사용자가 페이지로 돌아가기 위해 뒤로 이동 버튼을 누른 경우에는 히스토리 이벤트를 추가하지 않는다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();
   
   // subscribe to DHTML history change
   // events
   dhtmlHistory.addListener(historyChange);
         
   // if this is the first time we have
   // loaded the page...
   if (dhtmlHistory.isFirstLoad()) {
      debug("Adding values to browser "
               + "history", false);
      // start adding history
      dhtmlHistory.add("helloworld",
                               "Hello World Data");
      dhtmlHistory.add("foobar", 33);
      dhtmlHistory.add("boobah", true);
         
      var complexObject = new Object();
      complexObject.value1 =
                           "This is the first value";
      complexObject.value2 =
                           "This is the second data";
      complexObject.value3 = new Array();
      complexObject.value3[0] = "array 1";
      complexObject.value3[1] = "array 2";
         
      dhtmlHistory.add("complexObject",
                               complexObject);

이제 historyStorage 클래스를 살펴보자. dhtmlHistory, historyStorage와 마찬가지로 historyStorage라는 전역 객체 하나를 통해서 모든 기능을 제공한다. 이 객체는 해시 테이블을 시뮬레이션 하기 위해 put(keyName, keyValue0, get(keyName), hasKey(keyName)과 같은 메서드를 제공한다. 키 이름은 반드시 문자열이어야하며, 키 값은 XML로 된 문자열이나 자바스크립트 객체와 같이 복잡한 것도 사용할 수 있다. 예제에서는 페이지가 처음 로드될 때 historyStorage안에 간단한 XML을 저장하기 위해 put()을 사용하고 있다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();
   
   // subscribe to DHTML history change
   // events
   dhtmlHistory.addListener(historyChange);
         
   // if this is the first time we have
   // loaded the page...
   if (dhtmlHistory.isFirstLoad()) {
      debug("Adding values to browser "
               + "history", false);
      // start adding history
      dhtmlHistory.add("helloworld",
                               "Hello World Data");
      dhtmlHistory.add("foobar", 33);
      dhtmlHistory.add("boobah", true);
         
      var complexObject = new Object();
      complexObject.value1 =
                           "This is the first value";
      complexObject.value2 =
                           "This is the second data";
      complexObject.value3 = new Array();
      complexObject.value3[0] = "array 1";
      complexObject.value3[1] = "array 2";
         
      dhtmlHistory.add("complexObject",
                               complexObject);
                              
      // cache some values in the history
      // storage
      debug("Storing key 'fakeXML' into "
               + "history storage", false);
      var fakeXML =
         '<?xml version="1.0" '
         +         'encoding="ISO-8859-1"?>'
         +         '<foobar>'
         +             '<foo-entry/>'
         +         '</foobar>';
      historyStorage.put("fakeXML", fakeXML);
   }

다음으로, 사용자가 다른 페이지로 이동한 다음에 뒤로 이동 버튼을 통해 돌아온 경우에 get() 메서드를 사용해서 저장된 값을 가져올 수 있고, hasKey()를 사용해서 키가 있는지 확인할 수 있다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();
   
   // subscribe to DHTML history change
   // events
   dhtmlHistory.addListener(historyChange);
         
   // if this is the first time we have
   // loaded the page...
   if (dhtmlHistory.isFirstLoad()) {
      debug("Adding values to browser "
               + "history", false);
      // start adding history
      dhtmlHistory.add("helloworld",
                               "Hello World Data");
      dhtmlHistory.add("foobar", 33);
      dhtmlHistory.add("boobah", true);
         
      var complexObject = new Object();
      complexObject.value1 =
                           "This is the first value";
      complexObject.value2 =
                           "This is the second data";
      complexObject.value3 = new Array();
      complexObject.value3[0] = "array 1";
      complexObject.value3[1] = "array 2";
         
      dhtmlHistory.add("complexObject",
                               complexObject);
                              
      // cache some values in the history
      // storage
      debug("Storing key 'fakeXML' into "
               + "history storage", false);
      var fakeXML =
         '<?xml version="1.0" '
         +         'encoding="ISO-8859-1"?>'
         +         '<foobar>'
         +             '<foo-entry/>'
         +         '</foobar>';
      historyStorage.put("fakeXML", fakeXML);
   }
   
   // retrieve our values from the history
   // storage
   var savedXML =
                     historyStorage.get("fakeXML");
   savedXML = prettyPrintXml(savedXML);
   var hasKey =
                historyStorage.hasKey("fakeXML");
   var message =
      "historyStorage.hasKey('fakeXML')="
      + hasKey + "<br>"
      + "historyStorage.get('fakeXML')=<br>"
      + savedXML;
   debug(message, false);
}

preetyPrintXml()은 전체 예제에 포함된 유틸리티 메서드로 디버깅을 위해 웹 페이지에 XML을 출력한다.

데이터는 오직 현재 페이지의 히스토리에서만 유지된다는 점에 주의해야 한다. 즉, 브라우저를 종료하거나 사용자가 새로운 창을 열고 에이잭스 응용프로그램의 주소를 다시 입력하는 경우에 히스토리 데이터는 이용할 수 없다. 히스토리 데이터는 오직 뒤로, 앞으로 이동 버튼에 한해서만 유지된다. 사용자가 브라우저를 종료하거나 캐시를 정리하면 사라진다. 실제로, 오랜시간 유지할 수 있는 방법을 원한다면 에이잭스 대용량 저장 시스템(AMAXX, Ajax Massive Storage System)을 보기 바란다.

예제는 이것으로 끝났으며, 데모를 체험해보거나 전체 소스 코드를 다운로드하기 바란다.

예제2: 오라일리 메일

두번째 예제는 Gmail과 유사한 오라일리 메일이라는 가짜 AJAX 이메일 응용프로그램이다. 오라일리 메일을 통해 dhtmlHistory 클래스를 사용해서 브라우저 히스토리를 제어하는 방법, historyStorage 객체를 사용해서 히스토리 데이터를 캐시하는 방법에 대해 설명할 것이다.

오라일리 메일 사용자 인터페이스는 두 부분으로 구성되어 있다. 페이지의 왼쪽 사이즈는 받은 편지(Inbox), 임시 보관(Draft) 같은 다양한 이메일 폴더와 옵션으로 구성된 메뉴다. 사용자가 받은 편지 같은 메뉴를 선택하면 페이지의 오른쪽에 내용을 업데이트한다. 실제 응용프로그램에서는 선택된 메일박스의 내용을 가져와서 표시해야하지만 오라일리 메일에서는 선택한 옵션만 간단하게 보여준다.

오라일리 메일은 브라우저 히스토리에 메뉴 변경사항을 추가하고, 위치 바를 업데이트하는데 RSH 프레임워크를 사용하기 때문에 사용자가 응용프로그램을 북마크하고 브라우저의 뒤로, 앞으로 이동 버튼을 사용해서 메뉴 변경 이전으로 이동할 수 있다.

historyStorage 사용법을 설명하기 위해 Address Book(주소록)이라는 메뉴를 추가했다. 주소록은 이름과 이메일 주소를 자바스크립트 배열로 저장하고 있지만 실제 응용프로그램이라면 원격 서버에서 배열 내용을 가져와야 할 것이다. 그러나, 오라일리 메일에서는 배열을 직접 생성하고, 이름과 이메일 주소를 몇 개 추가한 다음에 historyStorage 객체에 저장한다. 사용자가 웹 페이지를 떠난후에 돌아오면 오라일리 메일 응용프로그램은 원격 서버에서 접속하는 대신 캐시에서 주소록을 가져온다.

주소록은 initialize() 메서드에서 저장하고 가져올 수 있다.

/** 페이지가 로딩을 끝낸 후에 초기화를 수행하는 함수 */
function initialize() {
    // DHTML 히스토리 프레임워크를 초기화한다
    dhtmlHistory.initialize();
   
    // DHTML 히스토리 리스너에 등록한다
    dhtmlHistory.addListener(handleHistoryChange);

    // 주소록을 가져올 수 없으면 직접 추가한 주소록을
    // 히스토리 저장소에서 캐싱한다.
   if (window.addressBook == undefined) {
         // 주소록을 전역 객체로 저장한다
       // 실제 응용프로그램에서는 백그라운드에서 서버로부터
       // 주소록을 가져와야한다
         window.addressBook =
             ["Brad Neuberg 'bkn3@columbia.edu'",
               "John Doe 'johndoe@example.com'",
               "Deanna Neuberg 'mom@mom.com'"];
               
         // 주소록이 있으면 이를 캐시에 보관한다
       // 사용자가 페이지를 떠난 후에 뒤로 이동으로 돌아온 경우에도 사용한다
       historyStorage.put("addressBook",
                                     addressBook);
    }
    else {
         // 히스토리 저장소에서 캐시된 주소록을 가져온다
         window.addressBook =
                      historyStorage.get("addressBook");
    }

히스토리 변경을 다루는 코드는 이해하기 쉽다. 아래 코드에서처럼 사용자가 뒤로 또는 앞으로 이동 버튼을 클릭할 때 handleHistoryChange가 호출된다. 그러면 newLocation을 갖게 된다. 이를 이용해서 사용자 인터페이스를 올바른 상태로 업데이트할 수 있다.

/** 히스토리 변경 이벤트를 처리한다 */
function handleHistoryChange(newLocation,
                                           historyData) {
    // 위치가 없으면 수신함의 기본 위치를 보여준다
    if (newLocation == "") {
         newLocation = "section:inbox";
    }
   
    // 위치 변화가 있으면 표시할 섹션을 추출한다.
    // newLocation은 "section:"으로 시작한다
    newLocation =
             newLocation.replace(/section\:/, "");
   
    // DHTML 히스토리 변경에 따라 브라우저를 업데이트한다
    displayLocation(newLocation, historyData);
}

/** 오른쪽 컨텐트 영역에 주어진 위치를 표시한다*/
function displayLocation(newLocation,
                                     sectionData) {
    // 선택한 메뉴 항목을 가져온다
    var selectedElement =
                  document.getElementById(newLocation);
                 
    // 이전에 선택된 메뉴 항목을 제거한다
    var menu = document.getElementById("menu");
    for (var i = 0; i < menu.childNodes.length;
                                                               i++) {
         var currentElement = menu.childNodes[i];
         // DOM 요소 노드인지 확인한다
         if (currentElement.nodeType == 1) {
             //모든 클래스 이름을 제거한다
             currentElement.className = "";
         }                                                         
    }
   
    // UI에서 다르게 나타나는 새로 선택된 메뉴 항목
    selectedElement.className = "selected";
   
    // 화면 오른쪽에 새로운 섹션을 표시한다.
    // sectionData에 따라 섹션을 결정한다

    // 앞서 캐시된 로컬 주소 데이터를 사용해서 주소록을 보여준다
    if (newLocation == "addressbook") {
         // 주소록을 보여준다
         sectionData = "<p>Your addressbook:</p>";
         sectionData += "<ul>";
         
         // 주소록이 아직 없다면 캐시에서 주소록을 가져온다
         if (window.addressBook == undefined) {
             window.addressBook =
                      historyStorage.get("addressBook");
         }
         
         // 주소록을 표시한다
         for (var i = 0;
                      i < window.addressBook.length;
                               i++) {
             sectionData += "<li>"
                                    + window.addressBook[i]
                                    + "</li>";                          
         }
         
         sectionData += "</ul>";
    }
   
    // sectionData가 없다면 원격으로 가져온다. 이 예제에서는 주소록을 제외한
    // 모든 데이터는 가짜를 이용하고 있다
    if (sectionData == null) {
         // 실제 응용프로그램에서는 섹션의 내용을 원격으로 가져와야한다
         sectionData = "<p>This is section: "
             + selectedElement.innerHTML + "</p>";  
    }
   
    // 제목과 내용을 업데이트한다
    var contentTitle =
             document.getElementById("content-title");
    var contentValue =
             document.getElementById("content-value");
    contentTitle.innerHTML =
                                    selectedElement.innerHTML;
    contentValue.innerHTML = sectionData;
}

오라일리 메일 데모를 체험하거나 소스 코드를 다운로드할 수 있다.

결론

RSH(Really Simple History) API를 사용해서 에이잭스 응용프로그램에서 즐겨찾기와 뒤로, 앞으로 이동 버튼을 사용하기 위한 방법을 보았으며 직접 에이잭스 응용프로그램을 작성하는데 발판이 될 수 있는 예제 코드들을 살펴보았다. 나는 즐겨찾기와 히스토리를 완전히 지원하는 여러분의 에이잭스 발명품들을 볼 수 있기를 기대한다.

감사의 글

이 글을 검토해준 모든 사람과 RSH 프레임워크를 제작한 모두에게 감사드린다: Michael Eakes, Jeremy Sevareid, David Barrett, Brendon Wilson, Dylan Parker, Erik Arvidsson, Alex Russell, Adam Fisk, Alex Lynch, Joseph Hoang Do, Richard MacManus, Garret Wilson, Ray Baxter, Chris Messina, and David Weekly.

참고자료

  • 이 기사의 모든 소스코드 다운로드
  • RSH 프레임워크 다운로드
  • 오라일리 메일 데모와 오라일리 메일 소스 코드 다운로드. 전체 예제 다운로드에는 시험할 수 있는 보다 많은 예제들이 있다
  • Coding in Paradise(코딩천국): AJAX, DHTML, 자바 기술, 위키위키와 같은 협업 기술 등을 다루는 저자의 웹로그
  • "Coding in Paradise: AJAX: Bookmarks and Back Buttons, Advanced Example"
  • "Coding in Paradise: Safari: No DHTML History Possible"
  • "Coding in Paradise: AJAX Tutorial: Saving Session Across Page Loads Without Cookies, On The Client Side"
  • "Coding in Paradise: AJAX History Libraries"

Bard Neuberg는 모질라, JXTA, 자카르타 피드 파서 등에 코드를 공헌하고 있으며, 오픈소스 커뮤니티에서 폭넓은 공헌을 하고 있다.

출처 - http://network.hanbitbook.co.kr/view.php?bi_id=1162

by 뭔일이여 2007. 1. 11. 14:34
KTF에서 제공한 자바 기초 문법 정리 파일입니다.
위피를 공부할 경우 참고하시면 좋겠네요~ ^^;
첨부파일 다운로드 하시면 됩니다.
출처 : mari's .NET
by 뭔일이여 2006. 11. 16. 12:06
◆  Recommended Documents for Beginners (!)
 
◆  Web Application Servers

  어플리케이션서버
  http://www.javaservice.net/~java/bbs/index.cgi?m=appserver&b=appserver

  ** 이하 ABC 순입니다.

by 뭔일이여 2006. 11. 16. 11:59
용어를 어떻게 써야할지 원 ㅡㅡ;
attachEvent, detachEvent 이야기를 할까 합니다.
Q&A보드에서 찾아봤지만 단 한건도 위에 대한 글이 없더군요.
모르는 사람이 없어서 그런건지는 잘 모르겠지만 ㅡ0ㅡ;

객체.attachEvent("이벤트명", 함수명);

위처럼 사용하면 해당 객체의 이벤트를 지정한 함수가 실행하게 됩니다.

해제는 객체.detachEvent("이벤트명", 함수명); 입니다.

ex)document.attachEvent("onmousedown", test);

위처럼 하면 문서에 마우스 다운시 test함수가 실행됩니다.
attachEvent, detachEvent 는 익스전용이며
넷스, 모질라에서는
객체.addEventListener("mousedown", test, true);
객체.removeEventListener("mousedown", test, true);
이렇게 쓰시면 됩니다.


IE 변수는 알아서 만드시고...

출처 : www.phpschool.com
by 뭔일이여 2006. 11. 16. 11:56
IE 전용인 innerText 함수를 모질라등 다른 브라우저에서 사용하는 방법입니다.
아래 코드를 소스에 넣으면 사용할 수 있습니다.

[CODE type=javascript]<script type="text/javascript">
var isMozilla = !(document.all);
if(isMozilla)
{
HTMLElement.prototype.__defineGetter__("innerText", function () {
var r = this.ownerDocument.createRange();
r.selectNodeContents(this);
return r.toString();
});
HTMLElement.prototype.__defineSetter__("innerText", function (sText) {
this.innerHTML = sText.replace("/&/g", "&").replace("/g", ">");
});
}
</script>[/HTML][/CODE]

by 뭔일이여 2006. 11. 16. 11:46
| 1 |