'분류 전체보기'에 해당되는 글 178건

  1. 2009.03.17 명품스타일 여성의류, 럭셔리스타일, 명품보세, 안나수이, 명품가방, 연예인 악세사리
  2. 2009.03.17 메소드 시그너처(method signature) 란?
  3. 2009.03.17 데이터 구조에 따른 DBMS 분류
  4. 2009.03.17 SQLJ란?
  5. 2009.03.16 역사의 정반합(正反合) 변증법적 순환
  6. 2009.03.16 홍콩명품 많은곳(루이비통, 구찌, 프라다, 샤넬, 로렉스, 까르띠에) : 지갑, 벨트, 가방, 시계
  7. 2009.03.12 stereotype 개념
  8. 2009.03.12 이통사별 MDN/MIN 조회 방법
  9. 2009.03.02 MySQL 원격접속 권한 설정
  10. 2009.02.27 Oracle DB를 MySQL DB로 마이그레이션 1
2009. 3. 17. 19:30

명품스타일 여성의류, 럭셔리스타일, 명품보세, 안나수이, 명품가방, 연예인 악세사리

http://www.bashu.co.kr/html/mainm.html
이쁜 모델이 직접 입고 있어 코디하기 좋네요.
2009. 3. 17. 13:50

메소드 시그너처(method signature) 란?

메소드의 특성과 메소드 이름, 파라미터, 반환값의 테이터타입을 가진 형태이다.
2009. 3. 17. 11:32

데이터 구조에 따른 DBMS 분류

DBMS는 원칙적으로 데이터베이스를 구성하는 3가지 구성요소의 측면에서 살펴야 한다.
3가지 구성요소는 데이터 구조, 데이터 조작, 데이터 무결성이다.
데이터 구조는 DB에 저장된 데이터가 담기는 곳으로서 파일(파일시스템), 세그먼트(HDB:Hierachical Database), 테이블(RDB:Relational Database), 레코드타입(NDB:Network Database), 클래스(OO/ORDB:Object Oriented Database/Object Relational Database)로 불린다.
2009. 3. 17. 11:05

SQLJ란?

Sqlj 무엇인가?

개발자들은 기존의 C언어를 이용해서 Oracle Database 접근 하고자 가지 방식을 이용했다. 하나는 “Pro*C” 방식이고, 다른 하나는 “OCI Library” 바로 call하는 방식이었다. 가지의 차이점은 “Pro*C” 경우 Embedded Sql문을 이용하기 때문에 기존의 C문장에 다음과 같이 삽입함으로써 Oracle Database에서 데이터를 가공할 있었다.

EXEC SQL DELETE FROM dept WHERE deptno = :v_deptno

그러나 만약, OCI Library 직접 call해서 위와 같은 내용을 수행하려면 low level coding 필요한 , 이와 비교해 Java 경우에는 전자와 같은 방식이 “sqlj”방식이고 후자와 같은 low level programming “JDBC API” 이용하는 방식이라 있겠다.

Sqlj JDBC API 이용 방식의 장단점이 있겠지만, 다음 표로 간단히 확인해 보자.

 

 

SQLJ

JDBC API

코딩의

간결하다.

많은 line 필요

sql syntax 검사

Pre-compile time시에 결정

runtime시에 결정

Host 변수

사용 가능

사용 불가능

Dynamic Sql이용

불가능

사용 가능

 [1 SQLJ JDBC API 비교]

 

위에서 언급된 부분을 살펴보면 SQLJ JDBC API 바로 이용하는 것보다 코딩 line수가 적으며, 이것은 개의 column 값을 update 확실히 있다. SQLJ sql문을 pre-compile time시에 syntax objects 존재 여부 type 검사 등을 위해서 미리 database 접속을 검증을 한다. 그러므로, compile-time시에 에러를 발생시키고, runtime시에 에러를 줄임으로써, 개발자들로 하여금 빠르고 쉬운 debugging 가능토록 한다.

또한, SQLJ “Host variables” 이용할 있으므로, 문장이 상당히 간결해 있으나 JDBC API 이용할 경우에는 그렇지 못하다. 그러나, SQLJ 경우 compile시에 sql문이 완전히 조합되어 있어야 하므로, “dynamic sql”등을 사용할 수가 없다. 만약 dynamic sql 이용하고자 한다면, “JDBC API” 이용해서 Dynamic SQL 구현해야 한다.

정리를 하면, “Static SQL” 해당하는 부분은 SQLJ 이용하는 것이 좋고, Dynamic SQL 해당하는 부분은 “JDBC API” 이용함으로써 개발 생산성과, rumtime시의 performance 극대화할 있겠다.

2009. 3. 16. 17:48

역사의 정반합(正反合) 변증법적 순환


정반합(正反合, 독일어: These, Antithese, Synthese)은 철학용어로 논리의 전개 방식의 하나이다. 헤겔변증법을 도식화한 것으로, 헤겔 본인에 의해서는 사용된 적이 없으나 이후에 그의 논리학을 해설하며 붙여진 용어이다.

기본적인 구도는 정(테제)가 그것과 반대되는 반(안티테제)와의 갈등을 통해 정과 반이 모두 배재되고 합(진테제)로 초월한다는 것이다. 카를 마르크스는 여기에서 정과 반의 갈등에 초점을 두어 변증법적유물론사적유물론의 이론적 배경으로 하였다.

-----------------------------------------------------------------------------------------------------


  •  
    사용자 삽입 이미지
▲ 독일 철학자 '헤겔'.
역사에 대한 철학적 관점은 크게 두 가지로 나눌 수 있다. 하나는 시간의 흐름 속에 일련의 과정이 반복적으로 등장한다고 이해하는 것이며, 다른 하나는 특정 방향을 향해 직선적으로 나아간다고 파악하는 것이다. 불교의 윤회설이 전자에 가장 가까운 역사관이라면 기독교의 역사관은 후자의 대표주자 격이다.

변증법으로 대표되는 헤겔의 역사관은 후자에 가깝다. 합(合)이 언제나 이전의 합(合)과는 다른, 보다 발전적이고 성숙한 모습을 갖는다고 해석했다는 점에서 그러하다. 하지만 그의 역사관을 올바르게 이해하기 위해서는 그러한 합(合)이 어떠한 시간적 흐름 속에서 자리매김하고 있는가를 살펴야 한다.

변증법의 3요소는 흔히 '정(正), 반(反), 합(合)'이라 일컬어진다. 헤겔은 역사를 정(正)에서 반(反)의 등장으로, 다시 정(正)과 반(反)에서 나타난 합(合)의 이행으로 설명한다. 물론 이 '합'은 다시 '정'이 되고, 이에 대한 '반'의 등장하며 또 다른 '합'으로의 이행이 진행된다. 그리곤 이 과정이 무한 반복된다. 이처럼 변증법은 정반합이라는 단순 요소들의 병렬적 나열이 아니라, 시간 속에서 변화하는 세계의 모습을 법칙적으로 해석한 것이다.

단순한 반복처럼 보이지만, 사실 변증법적 순환은 나아가 진보, 혹은 발전의 의미를 함축하고 있다. 헤겔은 단순한 시간의 연쇄를 발전적인 것으로 파악하는데, 이는 정과 반, 그리고 합의 관계를 통해 이해할 수 있다. 흔히 '정'은 어떤 사태의 현 상태를 지칭한다. 그리고 '반'은 그러한 현 상태에 대한 자기부정쯤으로 이해할 수 있다. 그리고 어느덧 현 상태와 자기부정의 끝없는 갈등을 극복하고, 또 다른 안정적 상태 즉 '합'이 도래한다.

풀어서 이야기하면 합은 앞선 정과 반의 치열한 갈등 속에서 등장하는 일종의 '해결책'인 셈이다. 따라서 합은 당연히 앞선 정보다 더 나은 결과적 상태이다. 물론 이렇게 나타난 현 상태(합)가 완전무결하다면 여기서 역사는 종결되겠으나, 그렇지 않다면 더 나은 합을 향해 또 다른 '반'과의 갈등이 불가피하다는 것이 헤겔의 생각이다.

헤겔의 역사관에서 갈등은 발전을 위해 매우 중요한 가치를 지닌다. 갈등이야말로 발전을 가능하게 하는 핵심요소다. 갈등이 없다면, 그러한 갈등을 극복하기 위한 노력 또한 필요 없기 때문이다.

갈등을 이처럼 긍정적인 것으로 파악하는 한, 현 상태를 긍정하는 '정'도, 그리고 이를 부정하는 '반'도 필연적으로 존재해야 한다. 싸움도 어느 정도 상대방의 존재를 인정할 때라야 비로소 가능하기 때문이다. 그것이 한 개인의 내적인 싸움이건, 혹은 사회적 정당이나 이익단체들끼리의 다툼이건 상대의 존재를 인정하는 것이 발전적 '합'을 위한 첫 걸음이다.

과거의 모습에 대해서도 유사한 해석이 가능하다. 어제를 잊고 싶다거나 잃어버렸다고 평가하는 것은 보다 나은 내일을 위해 아무런 도움도 되지 않는다. 그저 내일을 향해 달리라고만 한다면 그야말로 욕심을 채우기 위해 달리는 폭주기관차와 다를 바가 없다. 어제보다 나은 내일을 위하는 꿈꾸는 사람이라면 비록 입에 쓴 모습이라도 과거의 모습 또한 나, 혹은 사회를 구성하는 한 축이라는 점을 먼저 인정해야 한다.

그러한 인정이 있을 때라야 비로소 자신이 긍정하는 어제의 모습 속에서 문제점이 무엇인지 찾아낼 수 있다.

다시 3월이다. 많은 학생들이 새로운 학급, 학교에서 2010년 이맘때쯤 만나고 싶은 자신의 모습을 위해 휘황찬란한 계획을 세우곤 한다. 매년 똑같은 계획을 세우지만 매번 실패로 끝나는 사람들에게 당부하건데 어제까지의 일들은 모두 잊겠다는 말은 이제 그만 했으면 한다.

보다 나은 자신을 만들기 위해서라도 끊임없는 내적 투쟁은 필수적이다. 그런 사람들이 제일 먼저 해야 하는 것은 당연히 자신이 다퉈야 하는 상대가 무엇인지 깨우치는 것이다. 어제까지 누렸던 자신의 모습을 송두리째 부인하기만 해서는 자신이 도달해야 하는 발전적 합(合), 즉 내일의 모습은 그저 꿈일 수밖에 없을 터이다.

2009. 3. 16. 14:31

홍콩명품 많은곳(루이비통, 구찌, 프라다, 샤넬, 로렉스, 까르띠에) : 지갑, 벨트, 가방, 시계

http://www.lux99.co.kr/
홍콩명품 싸고 종류 많은곳
2009. 3. 12. 16:35

stereotype 개념

스테레오타입(Stereotype) 개념

UML을 처음 접하면서 가장 명쾌하게 이해되지 않는 개념 중 하나가 바로 스테레오타입(stereotype)일 것이다. 사전을 찾아보면 "연판, 관례, 고정 관념, 상투적인 문구, ..." 등의 의미로 나오지만 이미 의미를 알고 있다면 그런 용어가 알쏭 달쏭할 수는 있지만 그것으로부터 의미를 이해하기에는 불가능해 보인다. UML 명세에 나와있는 설명은 더 어렵다. 모델링 타임에 정의된 새로운 메타클래스(metaclass)라는 등, 사용상의 구별(usage distinction)이라는 등 역시 이미 UML 하부구조를 알고 있어야 하는 설명들이다.

스테레오타입은 그 정의로써 이해하기에는 다소 마음에 와 닿지 않을 것이므로 먼저 예를 들어보자. 윈도우 기반의 UI를 가지고 있으면서 DB를 다루는 간단한 프로그램을 모델링 한다고 가정하자. 이 때 주로 UML의 클래스(Class)를 사용해서 모델링을 하게 될 것이다. 속성(Attribute)과 연산(Operation)도 넣고 서로 간의 연관(Association) 및 일반화(Generalization)도 사용해서 말이다. 이렇게 모델링을 하고 나면 새로운 욕구가 발생하게 될 것이다. GUI를 구성하는 부분과  DB를 구성하는 테이블, 그리고 기타 프로그램 내부의 순수 로직 부분 모두 다 그냥 단지 클래스(Class)로만 표현되고 있을 뿐이다. 이것들을 그저 GUI, Business Logic, Database로 구분해두고 싶어질 것이다. 이런데 이러 경우는 비단 이러한 예 뿐만 아니라 너무도 많이 발생한다. 즉, 각각의 요소들을 모델러(modeler)의 기준에서 별도의 분류를 두고 싶을 때 스테레오타입(stereotype)을 사용하게 된다.

스테레오타입이 왜 필요한가?

UML은 매우 범용적이고 일반적인 모델링 언어이다. 따라서, 어떠한 개념이라도 무리 없이 모델링이 가능하지만 반면에 어떠한 개념도 정확하고 명확하게 나타내기는 힘들다. 우리 인간이 사용하는 자연어(한국어, 영어, 일본어)등도 결국 일상 용어 외에 특정 학문 분야에서 사용될 때에는 부족함이 많기 때문에 새로운 용어가 탄생하고 기존의 단어에 새로운 의미가 부여되게 되는 것이다. 일상 용어의 "Thread"와 컴퓨팅 분야의 "Thread"는 단어는 같으나 이해되는 의미는 다르다. UML도 마찬가지로 그러한 태생적인 한계가 있으며 이를 극복하기 위한 방안이 모색되었는데 그것이 바로 UML의 확장 메커니즘(extension mechanism)인 것이다.

스테레오타입의 사용

스테레오타입(stereotype)은 바로 UML 확장 메커니즘의 한 부분으로써 매우 중요한 역할을 수행하게 된다. 다시 한번 정리하면 "스테레오타입은 UML 모델링 요소들을 모델러의 기준에 따라 새로운 분류를 적용할 수 있도록 허용하는 메커니즘"이다. 따라서, 스테레오타입은 모델러 마음대로 정의해서 적용하면 되는 것이고 특별한 제약이나 규칙은 없다. 그리고 스테레오타입은 각 요소에 "<<" ">>" 사이에 이름을 부여하면 된다. 정확하게는 "<<", ">>"는 꺽쇠 괄호(angle-braket) 두개가 아니라 guillemets라 불리는 하나의 문자('«', '»')이다. 그러나, 통상적으로 이러한 문자를 사용하기가 불편하기 때문에 꺽쇠 괄호 두 개를 써도 무방하다.

스테레오타입은 위의 예에서 처럼 <<GUI>>, <<table>>과 같이 사용해도 되고, 특정한 플랫폼이나 프로그래밍 언어를 나타내기 위해 <<JavaClass>>, <<CORBAInterface>> 처럼 사용해도 된다. 아니면 특정 분야에서 사용되는 용어나 개념으로 표현하는 것도 좋은 예가 될 수 있다. 그러나 가급적 특정 기준을 두고 분류의 용도로 사용하는 것이 바람직하며 무조건적으로 부가적인 데이터들만 기입하는 방식은 좋은 사용의 예가 아닐 것이다. 예를 들어 클래스를 작성한 사람의 이름 <<minho>>, <<younghee>> 혹은 구현될 파일의 이름 <<DBAccess.java>>과 같이 사용하는 것은 그다지 좋은 방법은 아닐 것이다.

스테레오타입과 아이콘(Icon)

스테레오타입은 하나의 아이콘으로 표현될 수도 있다. 예를 들어 <<JavaBean>> 클래스를 콩 모양의 아이콘으로 나타내준다면 훨씬 보기에도 좋고 구별하기도 쉬울 것이다. UML은 이러한 확장이 가능하도록 허용하고 있다. 그리고 현대의 여러 툴들에서는 이를 지원하고 있기도 하다. <<table>>은 표 모양의 아이콘을, <<Database>>는 원통 모양의 아이콘을 사용할 수도 있는 것이다.

이렇게 아이콘을 사용할 수 있게 되다 보니 스테레오타입을 표현하는 방식에 몇 가지 선택사항이 생기게 되었다. 간단하게 생각해보더라도 <<JavaBean>>과 같이 텍스트 형식으로 나타내느냐 아니면 아이콘 형식으로 나타내느냐 혹은 둘 다를 나타내느냐 하는 선택을 할 수 있다. UML에서는 총 4가지의 옵션이 존재한다.



  • None : 스테레오타입을 나타내기 않음
  • Textual : 스테레오타입을 <<JavaBean>>과 같이 텍스트로 나타냄
  • Iconic : 콩 그림의 아이콘과 같이 아이콘으로 나타냄
  • Decoration : <<JavaBean>>과 콩 그림의 아이콘을 동시에 나타냄.
출처 : http://www.plasticsoftware.com/AGORAWEB/UMLKorea/Default.aspx
2009. 3. 12. 11:09

이통사별 MDN/MIN 조회 방법

MIN은 어떠한 목적에 따른 고유 번호라고 보고, MDN이 실제 폰번호라고 정의를 한다면
요. 이통사별로 HTTP Header로 조회할 수 있는 폰번호가 MIN과 MDN이 같은지 또는 동
일한지를 정리하면 다음과 같습니다.

1) SKT
UserAgent에서 구하는 값이 대부분 MIN과 MDN이 동일합니다.
허나 한가지 경우에 예외가 있는데요.
번호이동을 하면서 기존의 구형 SKT 단말로 가입을 하는 경우입니다.
이 경우 단말의 S/W 적으로 폰번호가 011 또는 017만 입력이 가능하다고 합니다.(SKT
의 얘기)
즉, 구형단말을 가지고 01033334444 번호로 가입을 하면 MIN 번호는 017xxxxxxx와 같은
번호로 부여를 하고, MDN은 01033334444가 되는 것입니다.

결론적으로 UA에 STI로 시작하는 단말은 MIN과 MDN이 같은 단말도 있으나, 다른 단말
도 있을 수 있다는 의미입니다.

그렇다면, MIN 번호를 가지고 MDN을 조회하는 것은 가능한가???
물론, 가능하지만 SKT의 CP에게만 허용을 하고 있습니다.

2) KTF
HTTP Header에서 구한 MIN은 MDN과 동일합니다. 물론, 브라우저에 따라서
821833334444 또는 01833334444, 8201833334444와 같이 다른 string 형태로 올려주는 경
우가 있으니 이런 것만 예외로 잘 처리를 하시면 MDN을 구하실 수 있습니다.

3) LGT
LGT의 경우는 브라우저에 따라서 다른데요.

A. UP Browser
MIN을 올려주지 않고 subno를 올려줍니다.
즉, subno와 MDN은 다르죠... 이 또한 subno로 MDN을 조회할 수 있으나, CP에게만 권
한을 준다고 하는군요.

B. AU / K / Lion Browser
MIN과 MDN이 동일합니다. 단지, UA에서 폰번호를 구하는 string 위치가 다릅니다. 이
부분만 조건에 따라 잘 구하시면 됩니다.

------------------------------------------------------------------------------
참고1 ) AnyBuilder 의 Provisioning 부분에서는 Include로 폰번호를 구하는 것을 제공합
니다.
참고2 ) 본 사이트의 "모바일 강좌"를 보시면 이통사 브라우저별로 string을 설명해 놓은
것이 있으니 참고하세요.

그럼, 즐거운 하루되세요.


----------------- 정한용님의 질문내용입니다. ----------------

>일반 WAP 페이지에서 carrier값하고 min 값을 얻어오면
>이 값은 MIN 값이 잖아요?
>
>DB에 번호 저장해서 사용할때~
>하고
>선물하기 할때 SKT 인지 구분하기 위해서~
>
>MIN 으로 MDN 을 또는 MDN 으로 MIN을 조회해야 될 것 같습니다.
>
>이와 관련해서 ASP 상에서 사용해 보신 분이나...
>
>예제나 샘플 있으시면...
>
>답변이나 메일로 보내 주시면 감사하겠습니다...
>
>이작업 때문에... 한달 고생했네요 ㅠ.ㅠ
>
>도와주세요...

출처 : http://www.anybil.com/community/developer_view.asp?modeType=read&pk=1460&SearchType=title&SearchTEXT=mdn&page=2
2009. 3. 2. 17:22

MySQL 원격접속 권한 설정

mysql 원격접속 권한 설정

>use mysql
>grant all privileges on *.* to 'oops'@'192.168.1.1'
>identified by 'passwd' with grant option;

ip대신 %를 주면 모든 호스트 접속허용!

oops라는 유저가 모든 권한을 부여받을 수 있다. 단 해당 IP의 Host 에서만,

이와 같은 설정은 select host, user from user;로 확인해 볼 수 있다.
2009. 2. 27. 10:32

Oracle DB를 MySQL DB로 마이그레이션

http://mysql.holywar.net/Downloads/Contrib/9168/177/oracledump.pl 

#!/usr/bin/perl -w
use strict;
use vars qw ( @ARGV $dbh $db_database $db_host $db_port $db_user $db_password
$default_precision $default_scale $default_index_length
$with_table_comments $with_col_comments
$no_data $no_foreign_keys $extended_inserts $complete_inserts $add_drop_table
$add_locks $insert_delayed $lock_tables $table_type $net_buffer_length
$nls_date_format $nls_time_format $nls_timestamp_format $verbose $output_tail);
use DBI;

#############################################
#
# oracledump.pl - Dumps table(s) from an Oracle database to MySQL format
#
# Use ./oracledump.pl without args to see usage info.
# You may also change internal default settings below
#
#
# Written by Johan Andersson <johan@andersson.net>, May 2001
# Needs DBI and DBD::Oracle Perl modules to work.
#############################################
#
# Changes by Guilhem Bichot <guilhem.bichot@mines-paris.org>, April 2002 :
# - Fixed little bugs
# * a one-column primary key was never included in the CREATE TABLE statement
# * an Oracle RAW column was not given any MySQL type
# * statements starting by ';' were produced for empty tables with extended-inserts
# - Oracle RAW columns are converted into VARCHAR BINARY or BLOB, instead of
# VARCHAR or TEXT.
# - Added foreign keys information in final ALTER TABLE ADD FOREIGN KEY statements
# and ALTER TABLE ADD INDEX (commented) as InnoDB may need additional indexes
# for referencing and referenced columns
# - Added option --no-foreign-keys, as retrieving foreign keys information
# from the Oracle views takes a long time
# - Added option --table-type=... to specify the MySQL table type
# in the CREATE TABLE statement
# - Added option --net-buffer-length. If using extended inserts, switches to a new INSERT
# when the length of the INSERT statement reaches net-buffer-length.
# - Made the connection method a bit more versatile : if the user specifies the database name,
# it can either be a valid connection descriptor
# alias specified in the tnsnames.ora file, or (this is what I have added) be of the type
# SID@host or SID@host:port .
# - Suppressed the tnsnames.ora check. In certain situations you had to tell the script
# where the tnsnames.ora was, while the Oracle OCI connection was able to find it without help.
# Moreover, 'grep' does not exist on Windows. Finally, if you specify a wrong
# connection alias descriptor, the Oracle connection dies with "TNS : could not resolve
# service name" which is a sufficient error message. So we do not need to check in the script,
# the Oracle connection does it enough.
# - Lenghtened the help message a bit

### SETTINGS #################################
#
# All settings here are default settings that are used if they're
# not specified as argument.
#

# DATABASE SETUP ####
$db_database = $ENV{'ORACLE_SID'} if defined($ENV{'ORACLE_SID'}); # Default Oracle SID
$db_host = undef;
$db_user = getlogin(); # Default username
$db_password = ''; # Default password

# Oracle session parameters for date/time formats. Do not change if you not
# know exactly what you're doing!
$nls_date_format = 'RRRR-MM-DD';
$nls_time_format = 'HH24:MI:SSXFF';
$nls_timestamp_format = "$nls_date_format $nls_time_format";


# DATA TYPE SETTINGS ####
$default_precision = 18; # Default when precision is missing on NUMBER/FLOAT
$default_scale = 0; # - " " - scale - " " - - " " - - " " -
$default_index_length = 10; # This only affects indexes that contain BLOB fields.
# Sets how big in bytes the index should be for those columns.

# MISC. SETTINGS
$no_data = 0; # Sets whether to retrieve table data or just the table structure
$no_foreign_keys = 0; # Sets whether to retrieve foreign keys or not
$with_col_comments = 1; # Enable comments to be included for each column (if they exist in Oracle)
$with_table_comments = 1; # Same, but for comments for each table.
$extended_inserts = 0; # Use extended INSERT INTO syntax to insert
# multiple rows within one statement (MySQL)
$complete_inserts = 0; # Use of complete inserts adds list of table column
# names used, after the INTO word in INSERT INTO
# statements (MySQL)
# Eg.:
# complete: INSERT INTO foo (col1, col2) VALUES (1,2);
# compact (default): INSERT INTO foo VALUES (1,2);
$add_drop_table = 0; # Specifies if we are going to add DROP TABLE
# statements in the output
$add_locks = 0; # Specifies whether to use locks around insert
# statements or not (MySQL)
$insert_delayed = 0; # Specified wheter to use INSERT DELAYED or not (MySQL)
$lock_tables = 0; # If true, all tables will be locked for read before
# fetching anything from them (Oracle)
$net_buffer_length = 1_047_551 ;

$verbose = 0; # If enabled, program activities are printed out on STDERR
##############################################

# Trap some useful signals to avoid seg fault, DBI handles left open etc.
$SIG{'TERM'} = *interrupt;
$SIG{'QUIT'} = *interrupt;
$SIG{'INT'} = *interrupt;

# Put auto-flush on
$| = 1;

# int main( void )
# Main sub routine
sub main {

# Parse arguments and get tables..
my @arg_tables = parseArgs();

# Create a database handle
$dbh = db_connect($db_database, $db_host, $db_port, $db_user, $db_password);
my $sth;

# Use the ALTER SESSION command to change the date format used
$dbh->do("ALTER SESSION SET NLS_DATE_FORMAT = '$nls_date_format'");
$dbh->do("ALTER SESSION SET NLS_TIME_FORMAT = '$nls_time_format'");
$dbh->do("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = '$nls_timestamp_format'");

# Store tables in an array
my @tables;

# Check if any tables are specified as argument(s)
if($#arg_tables < 0) {
# Fetch all tables from USER_TABLES
$sth = $dbh->prepare("SELECT TABLE_NAME FROM USER_TABLES");
$sth->execute();

my @row;
while(@row = $sth->fetchrow_array()) {
push @tables, $row[0];
}
$sth->finish();
}
else {
while(<;@arg_tables>) {
# Check if table exists
$sth = $dbh->prepare("SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME = ?");
$sth->execute($_);

if($sth->fetchrow_array()) {
push @tables, $_;
}
else {
warn "Table $_ does not existn";
}
$sth->finish();
}
}


# for each table

my $table;
foreach $table ( @tables ) {
print STDERR "* Checking table structure for table $tablen" if $verbose;

my @cols = describe_table($dbh, $table);
my %blobcols = (); # Keeps track on blob columns in indexes
my @colslist = ();
my $output = "";
my @quotecol = ();
my $lastcomment;

$output .= "nDROP TABLE IF EXISTS $table;" if $add_drop_table;
$output .= "nCREATE TABLE $table (";
for ( my $i = 0; $i <= $#cols; $i++ ) {
my(undef, undef, $datatype) = convert_dt($cols[$i]{'TYPE'}, $cols[$i]{'LENGTH'});
$output .= "nt".$cols[$i]{'NAME'}."t".$datatype;
$output .= " DEFAULT '".$cols[$i]{'DEFAULT'}."'" if defined($cols[$i]{'DEFAULT'});
$output .= " NOT NULL" if $cols[$i]{'NULL'} eq 'N';
$output .= "," if $i != $#cols;
$output .= "t# ".$cols[$i]{'COMMENT'} if defined($cols[$i]{'COMMENT'}) && $with_col_comments && $i != $#cols;

# We must save the last comment if such exists, otherwise we may get
# an error later since a separating comma may be printed on the wrong place
$lastcomment = $cols[$i]{'COMMENT'} if defined($cols[$i]{'COMMENT'}) && $with_col_comments && $i == $#cols;

# Save the insert values string

if($cols[$i]{'TYPE'} =~ /^(VAR)?CHAR2?|LONG( RAW)?|RAW|DATE$/) { #bug fix
$quotecol[$i] = 1;
}
else {
$quotecol[$i] = 0;
}

# Keep track on blob columns for indexes
if($datatype eq 'TEXT') {
$blobcols{$cols[$i]{'NAME'}} = 1;
}

# Keep a list of the columns to use when fetching data later
push @colslist, $cols[$i]{'NAME'};
}

# Get keys
print STDERR "* Fetching keys for table $tablen" if $verbose;
my %keys = get_keys($dbh, $table, $no_foreign_keys);

# Get primary key
my @pkcols = @{ $keys{'PRIMARY KEY'} };
my $pkstr = "";

if($#pkcols > -1) {
$output .= ",";

# print last column comment if such exist
if(defined($lastcomment)) {
$output .= "t# $lastcomment";
$lastcomment = undef;
}

$output .= "ntPRIMARY KEY (";

for(my $i=0; $i<=$#pkcols; $i++) {
# Keep track on columns in the PK in a string format (used later with indexes)
$pkstr .= $pkcols[$i]."-";

$output .= $pkcols[$i];
# Add index size if column is a blob column. Required by MySQL
$output .= "(".$default_index_length.")" if defined($blobcols{$pkcols[$i]});
$output .= "," unless $i == $#pkcols;
}
$output .= ")";
}
# Primary key done!

# Get foreign keys
my $type;
my @fkcols;
my $rtable;
my @rfkcols;
my $fkstr;
my $add_fk_statement="";


$type='FOREIGN KEY';
my %foreign_keys = %{ $keys{$type} };

my $number_of_foreign_keys = scalar keys(%foreign_keys);
if ($number_of_foreign_keys>=1) {
$add_fk_statement.= "nALTER TABLE $table" ;
}

my $j=0;

while( my($key) = each %foreign_keys ) {
@fkcols = @{ $foreign_keys{$key}{'COLUMNS'} };
$rtable = $foreign_keys{$key}{'RTABLE'} ;
@rfkcols = @{ $foreign_keys{$key}{'RCOLUMNS'} };

$fkstr = "ntADD ".$type." (";
$output_tail .= "n#ALTER TABLE $table ADD INDEX (";

for(my $i=0; $i<=$#fkcols; $i++) {
$fkstr .= $fkcols[$i];
$fkstr .= "," if $i != $#fkcols;
$output_tail .= $fkcols[$i];
$output_tail .= "," if $i != $#fkcols;
}

$fkstr .= ") REFERENCES ".$rtable." (";
$output_tail .= ");n#ALTER TABLE $rtable ADD INDEX (";
for(my $i=0; $i<=$#rfkcols; $i++) {
$fkstr .= $rfkcols[$i];
$fkstr .= "," if $i != $#rfkcols;
$output_tail .= $rfkcols[$i];
$output_tail .= "," if $i != $#rfkcols;

}

$fkstr .= ")";
$fkstr .= "," if $j != ($number_of_foreign_keys-1) ;
$output_tail .= ");";
$j++;

$add_fk_statement .= $fkstr;
}

if ($number_of_foreign_keys>=1) {
$output_tail .= "n#If the ALTER TABLE $table...ADD FOREIGN KEY... statement below fails with errno 150,n#uncomment some of the lines above and re-run the failed statementn";
$output_tail .= $add_fk_statement;
$output_tail .= ";n" ;
}

# Get indexes (non-unique and unique)
my @idxcols;
my $idxstr;
my $tmp_cols;

print STDERR "* Fetching indexes for table $tablen" if $verbose;

for $type ( 'UNIQUE', 'INDEX' ) {
my %indexes = %{ $keys{$type} };

while( my($key) = each %indexes ) {
@idxcols = @{ $indexes{$key} };

$idxstr = "nt".$type." ".$key." (";
$tmp_cols = "";

for(my $i=0; $i<=$#idxcols; $i++) {
# Keep track on index columns in a string format
$tmp_cols .= $idxcols[$i]."-";

$idxstr .= $idxcols[$i];
$idxstr .= "(".$default_index_length.")" if defined($blobcols{$idxcols[$i]});
$idxstr .= "," if $i != $#idxcols;
}

$idxstr .= ")";

# Check if this index is the PK index
# Since the PK already is specified above we should not
# include that index here.. But if the type not is UNIQUE
# this index is not the PK (just a non-unique duplicate of the
# PK index)
#
# You shouldn't be able to create such a index in Oracle
# (it would return an ORA-01408 error), but since MySQL may
# have duplicate indexes of different uniquenesses we do it
# the MySQL way to be sure..
if($tmp_cols ne $pkstr || $type eq 'INDEX') {
$output .= ",";

# Append last column comment if exists
if(defined($lastcomment)) {
$output .= "t# $lastcomment";
$lastcomment = undef;
}

$output .= $idxstr;
}
}
}

# Append last column comment if exists
if(defined($lastcomment)) {
$output .= "t# $lastcomment";
$lastcomment = undef;
}

$output .= "n)".( (defined($table_type)) ? " TYPE=$table_type" : "" ) .";n";

print STDERR "* Printing CREATE TABLE statement for table $tablen" if $verbose;
print $output;

if(!$no_data) {
# Fetch the data
print STDERR "* Obtaining locks on table $table on Oraclen" if $verbose && $lock_tables;
$dbh->do("LOCK TABLE $table IN SHARE MODE NOWAIT;") if $lock_tables;

print STDERR "* Preparing SELECT statement to fetch data from table $tablen" if $verbose;
$sth = $dbh->prepare("SELECT ".join(", ", @colslist)." FROM $table");
$sth->execute();

# Put together the insert statement. Take care of complete/"compact" options
my $insert_stmt = "INSERT ";
$insert_stmt .= "DELAYED " if $insert_delayed;
$insert_stmt .= "INTO $table ";
$insert_stmt .= "(".join(", ", @colslist).") " if $complete_inserts;
$insert_stmt .= "VALUES ";

my $istmt_nprinted = 1;
my $total_length;
my $tmpstr;

print STDERR "* Printing LOCK TABLES statement for table $tablen" if $verbose && $add_locks;
print "LOCK TABLES $table WRITE;n" if $add_locks;

print STDERR "* Starting to print INSERT INTO statement(s)n" if $verbose;


while(my @row = $sth->fetchrow_array()) {

$tmpstr = "(";

for(my $i=0; $i<=$#colslist; $i++) {
if(defined($row[$i]) && $quotecol[$i]) {
$tmpstr .= $dbh->quote(db_escape($row[$i]));
}
elsif(defined($row[$i]) && !$quotecol[$i]) {
$tmpstr .= $row[$i];
}
else {
$tmpstr .= "NULL";
}
$tmpstr .= "," if $i != $#colslist;
}
$tmpstr .= ")";

if(!$extended_inserts) {
print "$insert_stmt$tmpstr;n";
}
else {
if ($istmt_nprinted) {
print "$insert_stmt$tmpstr";$istmt_nprinted=0;
$total_length=length($insert_stmt)+length($tmpstr);
}
else {
if ( ($total_length+length($tmpstr))>($net_buffer_length-100) ) #100 if for security
#break the current extended INSERT statement and start a new one
{
print ";n$insert_stmt";
$total_length=length($insert_stmt)+length($tmpstr);
}
else {
print ",";$total_length+=length($tmpstr)+1;
}
print $tmpstr;
}
}
}

print ";n" if (($extended_inserts == 1) && ($istmt_nprinted == 0));

print "UNLOCK TABLES;n" if $add_locks;
$sth->finish();
print STDERR "* Done! Printed rows for table $tablen" if $verbose;

}
}

print STDERR "* Printing ALTER TABLE ADD FOREIGN KEY statements for all tablesn" if ($verbose && !$no_foreign_keys);
print $output_tail if !$no_foreign_keys;

$dbh->disconnect();
return 1;
}

# void interrupt ( void )
# This sub-routine is taking care of signals sent to the program
sub interrupt {
my ($sig) = @_;
print STDERR "Got $sig-signal; Issuing database disconnect and program exitn";
print STDERR "Warning: Active statements cannot be closed, exiting program now would cause a seg fault.nWarning: Quiting "safely" _without_ disconnecting from the database (to avoid seg. fault)n" if $dbh->{'ActiveKids'};

$dbh->disconnect() if ! $dbh->{'ActiveKids'};

exit(3);
}

# array describe_table( database_handle dbh, scalar table_name )
# Returns an array of hashes with info about the columns in the given table
sub describe_table {
my($dbh, $table_name) = @_;

# Get columns for the specified table
my $sth = $dbh->prepare("SELECT a.COLUMN_ID,
a.COLUMN_NAME,
a.DATA_TYPE,
a.DATA_LENGTH,
a.DATA_PRECISION,
a.DATA_SCALE,
a.NULLABLE,
a.DATA_DEFAULT,
b.COMMENTS
FROM USER_TAB_COLUMNS a, USER_COL_COMMENTS b
WHERE a.TABLE_NAME = ? AND b.TABLE_NAME = a.TABLE_NAME AND b.COLUMN_NAME = a.COLUMN_NAME");
$sth->execute($table_name);

my @row;
my @columns;
my $length;
while(@row = $sth->fetchrow_array()) {
if($row[2] eq "NUMBER" || $row[2] eq "FLOAT") {
# Set length to default precision/scale values when information
# is missing in the data
$length = (defined($row[4])) ? $row[4] : $default_precision;
$length .= ",";
$length .= (defined($row[5])) ? $row[5] : $default_scale;
}
else {
$length = $row[3];
}

# Trim default data (and remove quotes that oracle stores from CREATE/ALTER command)
$row[7] =~ s/^'([^']+)'s*$/$1/ if defined($row[7]);

# Strip linebreaks in comments
$row[8] =~ s/n// if defined($row[8]);

# Build hash of info about this column
my %column = ( 'NAME' => $row[1],
'TYPE' => $row[2],
'LENGTH' => $length,
'NULL' => $row[6],
'DEFAULT' => $row[7],
'COMMENT' => $row[8] );
# Add the info about this column to the @columns array,
# set the index to the COLUMN_ID to get the "original" order
$columns[--$row[0]] = { %column };
}
$sth->finish();

# Return list of hashes
return @columns;
}

# hash get_keys( database_handle dbh, scalar table_name, scalar no_foreign_keys )
# returns hash of hashes with information of the constraints in the given table
#
# hash = {
# 'PRIMARY KEY' = [ COLNAME1, COLNAME2, ... ],

# 'FOREIGN KEY' = {
# KEYNAME => { 'COLUMNS' => [COLNAME1, COLNAME2, ... ],
# 'RTABLE' => RTABLENAME, "R" means referenced
# 'RCOLUMNS' => [ RCOLNAME1, RCOLNAME2, ... ]
# };
# },

# 'UNIQUE' = {
# KEYNAME => [ COLNAME1, COLNAME2, ... ]
# },
# 'INDEX' = {
# KEYNAME => [ COLNAME1, COLNAME2, ... ]
# }
# }

sub get_keys {
my($dbh, $table_name, $no_foreign_keys) = @_;

my %keys = (
'PRIMARY KEY' => [],
'FOREIGN KEY' => {},
'UNIQUE' => {},
'INDEX' => {}
);
my ( @row, $type, $sth );

# Fetch primary key

$type = 'PRIMARY KEY' ;
$sth = $dbh->prepare("SELECT a.constraint_name, a.column_name, a.position
FROM user_cons_columns a, user_constraints b
WHERE a.table_name=? AND a.constraint_name=b.constraint_name AND
b.constraint_type='P'
ORDER BY a.constraint_name, a.position");
$sth->execute($table_name);

while( @row = $sth->fetchrow_array()) {
$keys{$type}[--$row[2]] = $row[1];
}

$sth->finish();
# Primary key done!

# Retrieve foreign keys information
# Slow due to a 3-view join
if (!$no_foreign_keys)
{
$type = 'FOREIGN KEY' ;
$sth = $dbh->prepare("SELECT a.constraint_name, a.column_name, a.position,
c.table_name,c.column_name
FROM user_cons_columns a, user_constraints b,
user_cons_columns c
WHERE a.table_name=? AND a.constraint_name=b.constraint_name AND
b.constraint_type='R'
AND b.r_constraint_name=c.constraint_name
AND a.position=c.position
ORDER BY a.constraint_name");
$sth->execute($table_name);

while( @row = $sth->fetchrow_array()) {
$keys{$type}{$row[0]}{'COLUMNS'}[$row[2]-1] = $row[1];
$keys{$type}{$row[0]}{'RTABLE'} = $row[3];
$keys{$type}{$row[0]}{'RCOLUMNS'}[$row[2]-1] = $row[4];
}

$sth->finish();
# foreign keys done!
}

# Fetch indexes
$sth = $dbh->prepare("SELECT a.index_name, a.uniqueness, b.column_name, b.column_position
FROM user_indexes a, user_ind_columns b
WHERE a.table_name = ? AND b.table_name = a.table_name AND b.index_name = a.index_name
ORDER BY a.uniqueness, a.index_name");
$sth->execute($table_name);

while( @row = $sth->fetchrow_array() ) {
# Get index type; UNIQUE or INDEX (non-unique of course)
$type = "UNIQUE" if $row[1] eq 'UNIQUE';
$type = "INDEX" if $row[1] eq 'NONUNIQUE';

$keys{$type}{$row[0]}[--$row[3]] = $row[2];
}
$sth->finish();

return %keys;
}

# scalar db_escape ( scalar string )
# Escapes a string to be used within a SQL statement
sub db_escape {
my($str) = @_;

my $newstr = "";
for(my $i=0; $i<length($str); $i++) {
my $c = substr($str, $i, 1);

if(ord($c) == 10) {
$newstr .= chr(92).'n';
}
elsif(ord($c) == 13) {
$newstr .= chr(92).'r';
}
elsif(ord($c) == 9) {
$newstr .= chr(92).'t';
}
elsif(ord($c) == 34 || ord($c) == 92) {
$newstr .= chr(92).chr(ord($c));
}
else {
$newstr .= chr(ord($c));
}
}

return $newstr;
}

# list convert_dt( scalar datatype, scalar datalength )
# Converts datatype to mysql format and returns it
sub convert_dt {
my($datatype, $datalength) = @_;

############################################
# Rules are..:
# Datatype (ORA) Length Returns (MySQL)
# NUMBER Any NUMERIC
# DEC Any NUMERIC
# DECIMAL Any NUMERIC
# NUMERIC Any NUMERIC
# DOUBLE PRECISION Any NUMERIC
# FLOAT Any NUMERIC
# REAL Any NUMERIC
# SMALLINT Any SMALLINT
# VARCHAR <256 VARCHAR
# VARCHAR2 <256 VARCHAR
# CHAR <256 CHAR
# VARCHAR2 >255 TEXT
# VARCHAR >255 TEXT
# CHAR >255 TEXT
# LONG <256 VARCHAR
#LONGRAW does not exist, it is LONG RAW
# LONG RAW <256 VARCHAR BINARY (in Oracle RAW means binary data)
# RAW <256 VARCHAR BINARY
# LONG >255 TEXT
# LONG RAW >255 BLOB
# RAW >255 BLOB
# DATE - DATETIME (Since DATE in oracle can include time information!)
#
# List return consists of:
# 1. Datatype name
# 2. Datalength
# 3. Complete datatype spec. to be used within CREATE TABLE statement
#############################################
if($datalength eq '0') {
$datalength = 32767;
}

return ('NUMERIC', $datalength, 'NUMERIC('.$datalength.')') if $datatype =~ /^DEC(IMAL)?|NUMERIC|NUMBER|DOUBLE PRECISION|FLOAT|REAL$/;
return ('INTEGER', 38, 'INTEGER(38)') if $datatype =~ /^(SMALL)?INT(EGER)?$/;

return ('VARCHAR', $datalength, 'VARCHAR('.$datalength.')') if $datatype =~ /^N?VARCHAR2?|LONG$/ && $datalength <= 255;
return ('TEXT', '', 'TEXT') if $datatype =~ /^N?(VAR)?CHAR2?|LONG$/ && $datalength > 255;

return ('VARCHAR BINARY', $datalength, 'VARCHAR('.$datalength.') BINARY') if $datatype =~ /^LONG RAW|RAW$/ && $datalength <= 255;
return ('BLOB', '', 'BLOB') if $datatype =~ /^LONG RAW|RAW$/ && $datalength > 255;

return ('CHAR', $datalength, 'CHAR('.$datalength.')') if $datatype =~ /^N?CHAR$/ && $datalength <= 255;
return ('DATETIME', '', 'DATETIME') if $datatype eq 'DATE';
}

# db_connect( scalar database, scalar host, scalar port, scalar user, scalar password )
# database_handle connects to the database
sub db_connect {
my($database, $host, $port, $user, $password) = @_;

my $connect_string = defined($host) ? ("host=$host;sid=$database".(defined($port) ? ";port=$db_port" : "")) : $database ;

return DBI->connect( "dbi:Oracle:$connect_string", $user, $password,
{ AutoCommit => 0, RaiseError => 0, PrintError => 1, LongReadLen => 0, LongTruncOk => 1 } );
}

# array parseArgs( void )
# returns array of tables given as argument or invokes the printError() sub-routine
# if some error occurs, which exits the program
sub parseArgs {

if($#ARGV < 0) {
printUsage();
exit;
}

my $tmpcmd = undef;
my @arg_tables;
my $db_database_complete;
my $got_db = 0;
my $show_config_only = 0;
my $use_default_db = 0;

while(<;@ARGV>) {
my $arg = $_;
if(defined($tmpcmd)) {
SWITCH: for ($tmpcmd) {
/^user$/ && do {
$db_user = $arg;
$tmpcmd = undef;
last SWITCH;
};
/^password$/ && do {
$db_password = $arg;
$tmpcmd = undef;
last SWITCH;
};
}
}
else {
SWITCH: {
/^-h|--help$/ && do {
printUsage();
exit 0;
};
/^-u|--user=(.+)$/ && do {
if(defined($1)) {
$db_user = $1;
}
else {
$tmpcmd = 'user';
}
last SWITCH;
};
/^-p|--password=(.+)$/ && do {
if(defined($1)) {
$db_password = $1;
}