오라클 테이블의 레코드 사이즈 계산을 쉽게하자

오라클 DB 테이블의 레코드 사이즈 계산을 할 필요가 있었다.

구할려고 보니, 데이터 형별로 계산 공식이 틀리다.


쉽게 계산하기 위해 HTML 로 작성해봤다.

사용방법은 DB테이블 Description의 레코드별 사이즈 부분을 TextArea에 붙여 넣고 실행하면 된다.


주요 소스 내용은 아래와 같다.


<head>
	<title>테이블 레코드 계산</title>
	<script src="http://code.jquery.com/jquery-1.5.min.js" type="text/javascript" 
                      charset="utf-8"></script>
    <script>
        /* 계산 공식 출처 
        	http://epoonet.egloos.com/4479971
        */
    	var pTable = [
    		{ type: "char", 	calc:function(n){ return n; }},
    		{ type: "varchar2", calc:function(n){ return n; }},
    		{ type: "nchar",	calc:function(n){ return 2 * n;  }},
    		{ type: "nvarchar2",calc:function(n){ return 2 * n; }},
    		{ type: "number",   calc:function(n){ return 1+ Math.ceil(n/2); }},
    		{ type: "date",		calc:function(n){ return 7; }},
    		{ type: "raw",		calc:function(n){ return n; }},
    		{ type: "long",		calc:function(n){ return n; }},
    		{ type: "long raw", calc:function(n){ return n; }},
    		{ type: "bfile", 	calc:function(n){ return 530; }},
    		{ type: "rowid", 	calc:function(n){ return 6; }},
    		{ type: "timestamp",calc:function(n){ return 13; }}
    	];
    	
        $(document).ready(
            function(){
            $("#DoIt").click(function() {
				var resultText = "";
				var inputText = $("textarea#src").val().toLowerCase().split("\n");
				var lineString;
				var size =0, sum =0;
				var buf;
				
				for(var i=0; i<inputText.length; i++) {
				
					size = 0;
				
					if ( lineString=$.trim(inputText[i]) ) {
						for(var j=0; j<pTable.length; j++) {
							if ( lineString.substr(0, pTable[j].type.length) 
                                                              == pTable[j].type ) {
								try {
								   size = Number(lineString.split("(")[1].split(")")[0]);
								} catch (e) { 
								   size = 0;
								}

								size = pTable[j].calc(size);
								break;
							}
						}
					}
					
					sum += size;
					resultText += lineString + " : " + size + "<br/>";
					
				}
				
				resultText += "<br/><b>sum: " + sum + "</b>";
				$("#result").html( resultText );
				
            });
        });
    </script>
	<style type="text/css">
        * { font-size:12px; font-family:맑은고딕 }
    </style>
</head>


<body>
<textarea id="src" rows="20" cols="80"></textarea>
<br/>
<input type="button" value="Do It!" id="DoIt">
<br/>
<br/>
<span id="result"></span>


직접 실행을 위한 URL은 아래와 같다.

http://host.newtype.pe.kr/tools/ora_table_size.htm 

CVS Commit 로그를 남겨보자

-. 요구사항 파악 및 설계

적용 패키지 작성을 위해 수정된 파일 목록을 추출 할 방법을 찾아 보기로 했다.
업무 때문에 소스 관리를 CVS 로 하고 있다. CVS의 단점은 개별 파일이력은 확인 할 수 있는데, 
수정된 파일 목록을 뽑기가 쉽지 않다는 것이다.

구글링을 해보니 CVS에서 Commit 시점에 뭔가 처리할 수 있다는 것을 알았다.

먼저, CVS 서버에 접속해서 저장소의 CVSROOT 디렉토리를 보자

-rwxrwxr-- 1 cvs cvs       544  4월 22 09:23 checkoutlist

-rwxrwxr-- 1 cvs cvs       694  3월 21  2009 checkoutlist,v

-rwxrwxr-- 1 cvs cvs       882  4월 26 16:03 commitinfo

-rwxrwxr-- 1 cvs cvs       959  3월 21  2009 commitinfo,v

-rwxrwxr-- 1 cvs cvs       993  3월 21  2009 config

-rwxrwxr-- 1 cvs cvs      1192  3월 21  2009 config,v

-rwxrwxr-- 1 cvs cvs       602  2월  8 16:32 cvswrappers

-rwxrwxr-- 1 cvs cvs       801  3월 21  2009 cvswrappers,v

-rwxrwxr-- 1 cvs cvs      1025  3월 21  2009 editinfo

-rwxrwxr-- 1 cvs cvs      1224  3월 21  2009 editinfo,v

-rwxrwxr-- 1 cvs cvs 292081967  4월 29 18:14 history

-rwxrwxr-- 1 cvs cvs      1245  4월 21 11:32 loginfo

-rwxrwxr-- 1 cvs cvs      1367  3월 21  2009 loginfo,v

-rwxrwxr-- 1 cvs cvs      1151  3월 21  2009 modules

-rwxrwxr-- 1 cvs cvs      1350  3월 21  2009 modules,v

-rwxrwxr-- 1 cvs cvs       564  3월 21  2009 notify

-rwxrwxr-- 1 cvs cvs       763  3월 21  2009 notify,v

-rwxrwxr-- 1 cvs cvs       640  4월 25 12:43 passwd

-rwxrwxr-- 1 cvs cvs       649  3월 21  2009 rcsinfo

-rwxrwxr-- 1 cvs cvs       848  3월 21  2009 rcsinfo,v

-rwxrwxr-- 1 cvs cvs       879  3월 21  2009 taginfo

-rwxrwxr-- 1 cvs cvs      1078  3월 21  2009 taginfo,v

-rwxrwxrw- 1 cvs cvs       187 11월 10 17:15 val-tags

-rwxrwxr-- 1 cvs cvs      1026  3월 21  2009 verifymsg

-rwxrwxr-- 1 cvs cvs      1225  3월 21  2009 verifymsg,v


위와 같은 파일들을 볼 수 있는데.. 
여기서 commitinfo 란 파일이 CVS에서 Commit 하기 바로전에 실행되는 파일이다.

방향은 정해졌다. 
작업 구성은 아래와 같은 순서로 하기로 했다.

     1. CVS가 Commit 되는 시점에 파일명을 DB에 저장한다.
         -> CVSROOT/commitinfo에 등록할 쉘 스크립트를 작성.
     2.  저장된 DB를 조회할 간단한 WEB Page 제작
         -> 평소 관심을 갖고 있던, jQuery를 이용.

[ 1. CVS가 Commit 되는 시점에 파일명을 DB에 저장한다 ]

commitinfo 파일에 아래와 같이 내용을 추가 한다.

$ vi CVSROOT/commitinfo 

ALL /home/cvs/myproject/CVSROOT/cvscommitlog.sh 


DB에 테이블을 생성 한다.

CREATE TABLE CVS_COMMIT
(
   SEQ              NUMBER(10) NOT NULL,
   USERID           VARCHAR2(20) NOT NULL,
   REG_DATE         DATE DEFAULT SYSDATE,
   PROJECT          VARCHAR2(50) NOT NULL,
   FILENAME         VARCHAR2(500) NOT NULL
);

* index는 REG_DATE, TO_CHAR(reg_date, 'YYYY/MM/DDHH24:MI'), USERID, PROJECT 를 걸었다.

commitinfo 파일이 실행할 쉘스크립트를 작성한다.

#!/bin/sh
export ORACLE_BASE=/oracle
export ORACLE_HOME=$ORACLE_BASE/product/10.2.0/db_1
export ORACLE_SID=ORACLE_SID
export PATH=$PATH:$ORACLE_HOME/bin
export ORACLE_OWNER=oracle
export LANG=c
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib;

DATE=`date "+%Y-%m-%d %H:%M:%S"`
DT=`date "+%Y%m%d"`
LOG_FILE="/home/cvs/cvs_log/commit.$DT.log"
DIR=$1
USER=$USER
PROJECT=`echo $DIR | cut -d/ -f4`
#(echo ""; id;) >> $LOG_FILE
shift
for file in $*
do
    echo "$PROJECT, $USER, $DATE, $DIR/$file" >> $LOG_FILE
        result=`$ORACLE_HOME/bin/sqlplus oracle_user/oracle_pwd@oracledb <<EOF 
        INSERT INTO CVS_COMMIT 
        VALUES ( (SELECT NVL(MAX(SEQ), 0) +1 FROM CVS_COMMIT), 
                       '$USER', TO_DATE('$DATE', 'YYYY-MM-DD hh24:mi:ss'), 
                       '$PROJECT', '$DIR/$file');
        COMMIT;
        EOF
        `
done



[ 2.  저장된 DB를 조회할 간단한 WEB Page 제작 ]
jsp 파일 하나와 html파일 하나로 이루어졌고, jQuery와 JSON을 이용 했다.
DATE Picker는 jQuery Plugin 중에 하나를 이용했다.

html 내용 보기


jsp 내용 보기



내 인생을 하루로 계산 하면..

김난도 교수의 "아프니까 청춘이다" 라는 책에 보면 "인생 시계"라는 말이 나온다.
평균 수명 80살을 하루로 계산해서,  1년을 18분 쯤으로 계산 한 것인데..

내 인생 나이는 얼마나 될까?
내 인생은 오전 10시 43분 이란다.

인생 시간을 계산 해보자.

http://host.newtype.pe.kr/1day/ 

  

소스 보기


jQuery를 이용했고,
테스트를 해보니, 약간의 오차가 있는 듯 하다.
 


allow_url_fopen off 일때, proxy 구현 방법.

jQuery에 관심이 생기면서, javascript 만으로 RSS 리더기를 만들어 보기로 했다.
jQuery가 워낙에 많은 Plugin들을 지원하고 있어서, rss Parser도 금방 찾을 수 있었다.
jFeed 라는 것인데, 소스도 간단하고.. 복잡한 기능이 필요없는 용도로는 적당했다.

그런데, 예상치도 못한 문제가 있었다.
Ajax에서 다른 도메인의 페이지를 읽기 위해 proxy를 구현 해야 하는데..
셈플 소스에 포함된 것이 정상적으로 동작하지 않는 것이다.

셈플 소스에 포함된 코드는 아래와 같다.
<?php
header('Content-type: application/xml');
$handle = fopen($_REQUEST['url'], "r");

if ($handle) {
    while (!feof($handle)) {
        $buffer = fgets($handle, 4096);
        echo $buffer;
    }
    fclose($handle);
}
?>

원인은 호스팅을 받고 있는 cafe24 에서는 보안상의 이유로 php.ini 파일에서 fopen 함수의 사용을 막아 놓은 것이다.



업체에서 제안하는 방법은, fsockopen 이용하는 방법으로 셈플 소스는 아래와 같다.
function get_url_fsockopen( $url ) {
	$URL_parsed = parse_url($url);

	$host = $URL_parsed["host"];
	$port = $URL_parsed["port"];
	if ($port==0)
		$port = 80;

	$path = $URL_parsed["path"];
	if ($URL_parsed["query"] != "")
		$path .= "?".$URL_parsed["query"];

	$out = "GET $path HTTP/1.0\r\nHost: $host\r\n\r\n";

	$fp = fsockopen($host, $port, $errno, $errstr, 30);

	if (!$fp) {
		echo "$errstr ($errno)<br>\n";
	} else {
		fputs($fp, $out);
		$body = false;
		while (!feof($fp)) {
			$s = fgets($fp, 128);
			if ( $body )
			$in .= $s;
			if ( $s == "\r\n" )
			$body = true;
		}

		fclose($fp);
		echo $in;
	}
}

하지만,  이방법도.. connection, write는 성공하지만, read 부분에서 데이터를 가져오질 못했다.
업체 문의 결과, www 폴더안에 ".htaccess" 파일을 만들고 파일 내용으로, 
php_flag allow_url_fopen 1

를 넣어 주면 된다고 한다. 단, 취약점을 통한 보안적 위험에 대한 책임을 보장할 수 없단다.
왠지 찝찝하다. 

좀 더 뒤져보니, curl 이란 php 라이브러리가 있다. 이넘이 물건이다. 좀 잡다한 기능들이 많아 무거워 보이긴 한데.. 일단 동작은 잘 된다.

curl 라이브러리를 이용한 소스는 아래와 같다.
<?php

function get_url_content($url) {

	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
	curl_setopt($ch, CURLOPT_HEADER, true);
   
	$html = curl_exec($ch);  
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);  
  
  	$inc=1;
	while ($http_code == 301 || $http_code == 302)
	{
		$header = curl_getinfo($ch, CURLINFO_HEADER_OUT);
		curl_close($ch);

		list($header, $html) = explode("\n\n", $html, 2);
		preg_match('/Location: (.*?)\n/', $header, $matches);
		$url = $matches[1];
		if (strlen(trim($url)) <= 0 )
			return "[".$http_code."] forwarding error, not found url.<br/>";

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL,$url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
		$html = curl_exec($ch);
		$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		if ( $inc++ > 5 ) {
			curl_close($ch);
			return "to many forwarding...<br/>";
		}
	}

	curl_close($ch);

	return substr($html, strpos($html, '<?xml'));;
}

echo get_url_content( $_REQUEST['url'] );

?>

소스의 기능은 아래와 같다.
   
    1. HTTP CODE가 301, 302의 Forwarding 관련된 것이면 해당 URL로 이동.
        : CURLOPT_HEADER 옵션, while문 안의 해더 파싱 부분.
    2. Forwaring이 5번 이상이면, 에러 처리.
        : while문 안의 if문 
    3. HTTP 해더 부분 제거.
        : return 전의 substr 구문. rss 리더를 위한 proxy 이므로 필요 하다.

마지막 소스를 이용해 proxy 문제를 해결 했다.

JQuery를 이용한 둥근 테두리 테이블 만들기

웹눈 님의 Round Table 소스를 JQuery를 이용하는 소스로 수정해봤습니다.

JQuery를 요 몇일 보고 있는데, 재미있네요..
이제 막 시작한 단계로 더 깔끔하게 다듬을 수 있을 것도 같은데..
아직은 내공이 부족하네요.

좋은 방법 있으면 공유 해주시면 고맙겠습니다.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
function roundTable(objID) {
	var $obj = $("table#" + objID);
	var s, r;
	var y, x, MAX;
	var w, h;

	r = parseInt($obj.attr('radius'));
	if (r == null || r < 1) r = 1;
	else if (r > 6) r = 6;

	MAX = r * 2 + 1;

	$obj.before("<TABLE id='tmpRoundTbl'></TABLE>")
	$("table#tmpRoundTbl")
		.attr("cellSpacing", 0)
		.attr("cellPadding", 0)
		.append("<TBODY></TBODY>");

	for (y=0; y < MAX; y++) {
		$("table#tmpRoundTbl TBODY").append("<TR></TR");
		s = Math.abs(y - parseInt(r));
		for (x=0; x < MAX; x++) {
			
			$("table#tmpRoundTbl TBODY TR:eq("+y+")")
				.append("<TD></TD>");

			w = '1px'; h = '1px';
			if (x == 0 || x == MAX - 1) h = null;
			else if (y == 0 || y == MAX - 1) w = null;
			else if (r > 2) {
				if (Math.abs(x - r) == 1) w = '2px';
				if (Math.abs(y - r) == 1) h = '2px';
			}

			if (w != null) 
				$("table#tmpRoundTbl TBODY TR:eq("+y+") TD:eq("+x+")")
					.css("width", w);
			if (h != null) 
				$("table#tmpRoundTbl TBODY TR:eq("+y+") TD:eq("+x+")")
					.css("height", h);

			if (s == x || s == MAX - x - 1) 
				$("table#tmpRoundTbl TBODY TR:eq("+y+") TD:eq("+x+")")
					.css("backgroundColor", $obj.attr('rborder') );
			else if (x > s && s < MAX - x - 1) 
				$("table#tmpRoundTbl TBODY TR:eq("+y+") TD:eq("+x+")")
					.css("backgroundColor", $obj.attr('rbgcolor') );
		}
	}

	$("table#tmpRoundTbl TBODY TR:eq("+s+") TD:eq("+r+")").append( $obj );
}
</script>


<table id="ta" width="300" height="100" border="0" 
    radius="3" rborder="#999999" rbgcolor="#F8F8F8">
<tbody><tr>
<td valign="top">테스트입니다</td>
</tr>
</tbody></table>
<span>
<script>roundTable("ta");</script>
</span>



[ 참고 ]