자바에서 String 다룰 때 오해와 진실

어자피 다들 먹고사는데 자바 안다뤄본 사람 있나? 어? 자바 안해봤어? 넌 그럼 축복받은 거야. 축하한다.
어쨌든, 자바에서 String 을 다룰 때 여러 조언들이 있다. 초보부터 중고급까지 짚어야 할 것들을 추려서 간단하게 소개하겠다.
나중에 문자열을 잘 다뤄서 자바 앱 성능 잘 나온다고 고마워하고 싶으면 언제든 해라.

이 글은 자바 1.8을 기준으로 작성하였다. 9 이상에서는 아래 내용에서 꽤 달라질 수 있으니 주의를 요한다.
라고 하기엔 당장에 StringConcatFactory 클래스가 뭔지 소개하는 한글 문서조차도 없어 시발놈들…

자바에서 + 연산을 통한 문자열 합치기를 지양하라!

반은 맞고 반은 틀리다.
내가 전에도 관련해서 블로그 포스트에 올렸었다. 자바는 + 연산을 사용하면 String.concat 메소드를 쓰는 게 아니라,
컴파일 전 내부적으로 StringBuilder 클래스를 만든 후 다시 문자열로 돌려준다.
전 포스트에선 StringBuffer로 기재했는데, StringBuilder맞다고 한다.
참고로 닷넷은 + 연산 시 연산자 오버로딩 본문에 내부적으로 String.Concat 메소드를 사용하여 합치도록 구현되어 있다.

String a = "hello" + "world";
// 는 아래와 같다.
String b = new StringBuilder("hello").append("world").toString();

이런 특성 때문에 문자열을 합치는 일이 많을 경우 단순히 + 연산을 쓰면 성능이 떨어질 수밖에 없고, 메모리 비효율은 덤이다.

String a = "";

for(int i = 0; i < 10000; i++) {
    a = a + i;
}

// 이런 짓거리 하면 이렇게 구현하는 것과 같다.

String b = "";

for(int i = 0; i < 10000; i++) {
    b = new StringBuilder(b).append(i).toString();
}

이런 경우에는 주저없이 처음부터 StringBuilder 클래스를 사용하여 문자열을 합치는 게 더 좋다.


final StringBuilder a = new StringBuilder(); for(int i = 0; i < 10000; i++) { a.append(i); } final String b = a.toString();

위와 같이 코딩하면 특히 비동기에 대응하기 수월하다는 장점도 가질 수 있다.

그렇다면, 다음과 같은 궁금증이 생길 것이다.
StringBuffer 또는 StringBuilderString.concat 중 어느게 더 좋을까다.
당연히 승자는 StringBufferStringBuilder 이다. 왜냐? String.concat 내용을 보면 바로 답이 나온다.

    public String concat(String var1) {
        int var2 = var1.length();
        if (var2 == 0) {
            return this;
        } else {
            int var3 = this.value.length;
            char[] var4 = Arrays.copyOf(this.value, var3 + var2);
            var1.getChars(var4, var3);
            return new String(var4, true);
        }
    }

여기서 핵심이 새 배열에 복사하는 행위인데, 이거나 + 나 겉보기엔 원리에 별 차이가 없다.
단지, + 연산은 내부적으로 위에서 언급했던 과정을 거치기 때문에 조금 더 느리고,
이 메소드는 호출할 때마다 원체(문자)의 매번 배열을 재구성 하는 과정을 거치기 때문에 당연히 느릴 수밖에 없다.
StringBuilderStringBuffer는 처음부터 배열 크기를 일정하게 잡고 시작하기 때문에 합치는 과정이 concat 보다 월등히 빠르다.

참고: String concatenation with Java 8

다시한번 강조하지만, 단순히 문자열을 합친다면 그냥 + 연산이 효율적이고, 반복문 등 합치는 일이 잦을 경우 StringBuilderStringBuffer를 써라. 꼭이다.

자바에서는 문자열을 효율적으로 합치는 클래스가 StringBuffer 뿐이다?

어디 학원에서 배우셨어요?

Difference Between String , StringBuilder And StringBuffer Classes With Example : Java
오라클 직원이었던 글을 참고하여 설명 들어가겠다.
사실 둘의 차이는 하나 말고는 없다.
바로 쓰레드에서 안전하냐 아니냐 이 차이 뿐이다.

  • StringBuffer 클래스는 쓰레드에서 안전하다.
  • StringBuilder 클래스는 쓰레드에서 안전하지 않다.

기본 성능은 당연히 쓰레드 안전성을 버린 StringBuilder 클래스가 우월하다. + 연산 시 StringBuilder 쓰는 이유가 있다.

만약 평소처럼 쓸 때, 특히 비동기에 사용할 일이 없으면, + 연산이나 StringBuilder를 써라.
하지만 통신이나, 다른 쓰레드와 공유하거나, 비동기 작업이 필요하다면 StringBuffer가 효율적이라고 보면 된다.

뭐… 이것도 적재적소에 쓰는 게 맞다고 보면 된다. 예제는 어자피 위에서 클래스 바꾸면 다를 게 하나도 없으므로 안 쓰겠다.

위 둘의 성격을 잘 설명한 글이 있으니 참고하라.
Java에서 String, StringBuilder, StringBuffer의 차이

혹시 StringBuilder가 닷넷스럽다고 쓰지 말라는 미친새끼 있으면 나한테 불러와라. 뚝배기 깨버려줄테니.

자바에서 문자열을 비교할 때 반드시 .equals() 메소드를 써야 한다!

어느정도 맞다.

내가 왜 애매하게 반드시 그렇게 해야 한다도 아니고 어느정도 맞다고 했는가?
아마 자배 배울 때 아래와 같이 배웠을 것이다.

  • 자바의 == 연산자는 레퍼런스 비교이다.
  • 문자열은 클래스이기 때문에 레퍼런스가 서로 달라 문자열을 아무리 비교해도 반드시 false가 나온다.
  • 따라서 문자열 비교할 때는 반드시 .equals() 메소드를 써서 비교해야 한다.

일단은 맞다. 내가 이거 부정한 적은 없다. 하지만 2번째 가르침은 잘못 가르친 거다. 왜냐?
당연하겠지만 정말 개념찬 자바 강의가 아니면, 대학교조차 String.intern() 메소드를 그냥 지나가는 경우가 많다.
하지만 자바나 닷넷은 문자열을 관리할 때, 반드시 거쳐가야 한다. 안그러면 자바 최적화에서 놓치기 쉽기 때문이다.

문자열 Pool이라 들어봤을 것이다. 보통 우리는 문자열을 정의할 때, "a" 처럼 쌍따옴표를 쓰지 new String 쓰지 않는다.
그렇다고 new String("a") 이렇게 선언한다고? 세상에 미친 짓도 이런 미친 짓은 없을 것이다. 메모리 2번 먹는다 생각하면 된다.
어쨌든, 쌍따옴표로 문자열을 정의하면, 아래와 같이 해석된다.

String a = "hello";
// 위 구문은 아래 구문으로 해석한다.
String b = new String(new char[]{'h', 'e', 'l', 'l', 'o'}).intern();

intern 메소드의 쓰임새는 그다지 어렵지 않은데, 문자열을 메모리에 담는다. 그리고 서로 다른 문자열끼리 메모리에 담게 된다.
따라서 아래와 같이 정의하면 새로이 문자열이 추가되는 일은 없다.

String a = "hello"; // 새로운 hello 문자열을 저장소에 담는다.
String b = "hello"; // 이미 담았으므로 다시 불러와 정의된다.

즉, 자바로 치자면 중복없는 컬렉션을 담당하는 Set 기반 클래스에 String.equals() 메소드로 비교하여 담는다고 생각하면 쉬울 것이다.
그렇기 때문에, 자바의 문자열 비교는 의외로 놀라운 결과를 보여주기도 한다.

String a = "a";
String b = "a";
String c = "b";
String d = new String(new char[]{'b'});

System.out.println(a == a); // true
System.out.println(a == b); // true
System.out.println(b == c); // false
System.out.println("b" == c); // true
System.out.println(c == d); // false

변수 ab의 경우, a 변수에 선언할 때, 풀에 문자열을 담게 되고, b 변수에 선언할 땐 풀에 있으므로 다시 불러오게 된다.
그렇기 때문에 String 클래스의 레퍼런스조차 같다. 그렇기 때문에 a == b 의 결과는 true가 되는 것이다.
하지만 "a""b" 는 딱 봐도 다른 문자열이기 때문에 레퍼런스도 틀리다. 당연히 결과는 false가 된다.
하지만 d 변수는 아예 클래스로 선언했다. 풀에 담지 않았기 때문에 문자열이 같아도 레퍼런스는 틀리다. 그래서 c == d의 결과는 false가 된다.

여기까지 하면 굳이 equals 안써도 된다고 생각하기 쉬운데… 안타깝게도 자바는 자비로운 놈이 아니다.
그 이유인 즉슨, 바로 String 클래스의 멤버부터 StringBuilderStringBuffer, Stream 계열의 문자열 버퍼 스트림 클래스 등이 문제가 되는데,
이들은 반환 값이 모두 new String 이렇게 문자열 클래스로 선언하여 보내준다. 왠만한 클래스 내의 toString 메소드 오버라이딩도 마찬가지다.
굳이 이유를 알려주자면, 문자 임을 잊지 말자. String 클래스 소스 까보면 알겠지만, 문자열을 다룰 때 문자열 자체를 다루는 게 아니라 내부적인 char[]에 담아 처리하게 된다.
당연하겠지만 결국 번거롭게 작업하는 대신 성능을 높이려는 신의 한수라고 생각하면 된다. 이건 버퍼나 스트림 처리할 때도 마찬가지이다.
그래서 같은 문자열 내용이라도, 레퍼런스 비교는 틀리다 보니 결국 이런 결과가 나온다.

System.out.println("abc".substring(0,1) == "a"); // false

만약 굳이 == 비교를 통해 비교하려면, .intern() 메소드를 써야 가능해진다.

System.out.println("abc".substring(0,1).intern() == "a"); // true

하지만 누가 번거롭게 일일이 intern 메소드를 쓰는가? 게다가 메모리 효율성에 전혀 좋지 않는 짓이다.
왜냐면 문자열을 intern 으로 호출하면, 그 문자열은 풀에 담게 되는데, 다들 불변성(Immutable)이라 들어봤을 것이다.
게다가 intern 메소드는 네이티브 메소드다. 네이티브에서 메모리를 직접 관리한다. 그래서 불멸성이 가능한 것이다.
대신, 이로 인해 개발자는 자바 내에서 저 문자열에 대한 메모리 관리는 영영 빠이빠이 되는 것이다.

문자열 관리의 3규칙, 명심하자. 다른 글에서도 질리도록 강조한다.

  • 따옴표로 감싼 정적 문자열은 적당히 쓰자. 너무 많으면 선언부터 사용까지 골치아픈 일이 발생한다.
  • 암호화나 해시처럼 문자를 세부적으로 다루지 않는 이상 new String 처럼의 클래스 초기화는 필요 없다.
  • 동적으로 생성된 문자열은 대부분 풀에 담지 않은 문자열 클래스이기 때문에, 값 비교엔 equals 메소드로 비교하라.

그래서 문자열을 비교할 때 결국 equals 메소드를 쓰라는 결과가 나오는 것이다.
내부적으로 String.equals 메소드가 값을 비교하도록 정의되어 있기에, 문자열 비교에 효율적일 수밖에 없을 것이다.

자, 물론 결론은 진실은 맞지만, 아는 사람들은 다 아는 뻔한 얘기지만, 이런 불편한 진실이 있다는 것을 상기시켜 주기 위해 추가했다.
참고로 닷넷 또한 자바의 문자열 관리와 비슷하다. 대신 == 비교 시 연산자 오버로딩에 의해 내부적으로 String.Equals 메소드로 비교하기 때문에 레퍼런스로 비교되는 일은 없다.

만약 더 있으면 추가하도록 하겠다.
끗.

composite / 2018년 5월 18일 / Piss Development / 0 Comments

IP 0.0.0.0 주소가 가지는 의미?

지금부터 내가 싸지르는 글은 서버 개발자를 위한 글이 아니다.
그냥 당신이 어느정도 컴퓨터 좀 다룰 줄 아는 모든 이들을 대상으로 쓰는 유용한 팁 글이다.
마음을 비우고 차분히 읽어보기 바란다.

일단 먼저 이론부터 보자면, IP 주소 0.0.0.0 은 유효한 주소다.
근데 이론만이다.

하지만 실제로 0.0.0.0 주소는 당연하겠지만 할당 가능한 IP 주소가 아니며, 논리적 용도로 사용한다.
위키페디아 0.0.0.0 문서를 보면 여러 의미로 사용되곤 한다.
문서 상에서는 메타 주소라 칭하고 있다. 그렇다. 우리식 대로는 물리적 주소가 아닌, 논리적 주소라 해석해도 손색이 없다.

하지만 한국에서는 0.0.0.0 얘기를 꺼내기 시작하면, TCP/IP 이론부터 들고 일어나 서버쪽 공부를 시키게 될 것이다.
당장에 구글 한국어 검색이나 네이버를 뒤지면 이런 얘기들 뿐이다.
서버에 관심 없거나 모르는 사람을 위해, 서버측 이론을 당장 한 마디로 함축하면,
0.0.0.0 주소는 “나는 어떤 IP 주소로 서비스할 지 모르니 아무 IP 대역 다 서비스 해 줘.” 라는 뜻이 되겠다.
여기서 다른 방향으로 넘어가면, 서버 프로그램이 0.0.0.0 주소를 어떻게 사용하느냐 나름이겠지만, 묵시적 규칙으로 대부분 이렇게 사용한다.

하지만 네트워크 클라이언트에서도 0.0.0.0 주소를 사용하기도 한다.
당장 OS 상관없이 가장 빠르고 쉽게 접할 수 있는 가장 대표적인 예로 HOSTS 파일이 있다.
자, 하지만 서버와는 달리 0.0.0.0 의 쓰임새도 없다. 할당할 IP가 없다. 그렇다면 뭐다? 없다.
그렇다. HOSTS 파일의 0.0.0.0 IP 주소는 “어느 IP 주소도 할당하지 마라.” 라는 뜻으로 보면 된다.
만약 우리가 HOSTS 파일에 0.0.0.0 naver.com 줄을 추가하여 저장 후 브라우저를 킨다면?
네이버 접속하자마자 바로 페이지를 찾을 수 없다고 뜰 것이다. 1초의 망설임도 없이 컴퓨터는 접속 오류를 내뱉을 것이다.
왜냐, 0.0.0.0 이 가지는 라우터도 없고, 물리적 할당 공간도 모르며, 어디로 접속해야 할 지 아예 정해지지 않았기 때문이다.
그래서 HOSTS 파일 작성 시, 원치 않는 도메인을 바인딩하려고 할때 (주로 광고나… 어둠의 유지용) 127.0.0.1 대신 사용하라는 것이다.
127.0.0.1 주소는 다들 아시다시피 로컬 IP 주소다. 만약 이 주소로 바인딩을 시도하면, 컴퓨터는 자신의 컴퓨터를 “가상 루프백 네트워크 드라이버”를 통해 접속하려 할 것이다.
그러다가 접속할 수 없으면 접속 오류가 뜬다. 그렇기 때문에 HOSTS 에서는 원치 않는 도메인을 127.0.0.1 대신 바로 접속을 중지해버리는 0.0.0.0 주소를 권장하는 것이다.

네트워크 클라이언트에서도 0.0.0.0 주소는 요긴한 기능으로 사용하기도 한다. 상기 위키페디어를 가면 알겠지만,
당신의 랜 카드에 IP를 할당해야 하는데, 모르겠다? 그냥 자동으로 받고 싶다? 그러면 우리가 보기에는 DHCP 사용에 체크하거나 설정할 것이다.
그러면 네트워크 연결 프로그램은 이걸 할당 IP 주소를 내부적으로 0.0.0.0 으로 설정한 다음, 접속 가능한 게이트웨이로부터 자동으로 IP를 받는 서버로 IP를 할당받으려 할 것이다.
그러지 못하면 169.254.xxx.xxx 라는 듣도보도 못한 IP 주소를 받고 네트워크 활동을 못하는 참사가 일어나겠지.
어쨌든, 네트워크 연결 프로그램에서는 0.0.0.0 주소의 의미는 “나는 어떤 IP 주소를 할당받을 지 모르겠으니 자동으로 받아 주시오.” 뜻이 되겠다.

지금까지 IP 얘기는 IPv4 기준이었고, IPv6 에서 같은 역할을 담당하는 주소는 콜론 2개 딸랑 :: 쓰면 된다. 참으로 간편하지 아니한가?

올바르지만 올바르지 않는 0.0.0.0 IP의 세계는 결국 앱이 정하는 기준에 따른다고 보면 된다. 전체적으로는 “몰라, 안써!” 의미가 되겠다. 하지만 이 의미가 유용하게 쓰이기도 한다는 점을 알아두기 바란다.
끗.

composite / 2018년 5월 8일 / Piss Development / 0 Comments

사설 네트워크를 위한 네트워크 서비스

1. Hamachi

말할것도 없다. 일단 가장 유명하고, 많은 사용자를 보유하고 있다.

  • 무료: 5명까지 연결 가능, 대역폭 제한.
  • 유료: 32 네트워크 지원 월 49$/월, 이상의 플랜 제공, 대역폭 제한 없음.
  • 지원 플랫폼: 윈도우, 리눅스, 맥

2. Tunngle

게이머에게 유명하다. 255명 이상의 네트워크를 지원하는 대신 공개 네트워크이며, 매 접속시 다른 IP를 할당받는다.
베이직 플러스 이상에서만 고정 IP를 할당받을 수 있다. 무료의 경우 광고도 있다.

  • 무료: 공개 내트워크 내 255명까지 지원
  • 유료: 베이직 플러스, 프리미엄과 평생 라이선스가 있으며, 각각 1.18$/월, 2.37$/월, 23.74$. 프리미엄 이상에서만 비공개 네트워크 구축 가능.
  • 지원 플랫폼: 윈도우
  • 게이밍에 특화된 네트워크 플랫폼으로 사설 네트워크에 적합하지 않음.

게임의 특화된 네트워크 서비스는 그냥 구글검색 해줘라. 아니면 꺼라위키 가던가.

3. NetOverNet

하마치와 비슷하긴 한데, 하마치하고 달리 내장 VPN도 지원하는 프로그램(PPTP, L2TP 등). 대신 무료 플랜이 3개 컴퓨터와 4mbps/s로 좀 짜긴 하다.

  • 무료: 비공개 네트워크 내 3명 지원, 대역폭 제한.
  • 유료: 베이직 5$/월 8개의 연결 지원, 어드밴스드 10$/월 16개의 연결 지원, 그 이상의 옵션 협의
  • 지원 플랫폼: VPN Client를 지원하는 모든 운영 체제 및 윈도우 프로그램 제공

4. FreeLAN

일단 성격은 VPN인데, 실장 가상LAN이다. contact 외부 주소가 없으면 내부 네트워크용이 되는거고, 정말 개인 네트워크스럽다.
그리고 GUI 프로그램이 없으며, 텍스트 방식의 설정 파일과 콘솔 프로그램이 전부이다.
하지만 무료, 무제한 개인 네트워크 구축은 상당히 매리트가 있다고 보면 된다. 네트워크도 생각보다 안정적이라고 한다.

  • 지원 플랫폼: 윈도우, 리눅스, 맥
  • 인터넷을 통한 LAN 접속 시 서버 쪽에서 방화벽 오픈해야 함.

5. LAN Bridger

제공된 정보가 없다. 대신 개인 네트워크 범위를 제공한다. 윈도우만 지원한다. 공식 사이트에서는 게이밍을 강조했으니 게이밍에 적합할 듯 하다.

6. NeoRouter

2가지 방식을 제공한다. 자체 서버 구축 방식과 Mesh라 해서 클라우드 구축 방식이다. 서버와 클라이언트 모두 프로그램이 별도로 필요하긴 하지만,
클라이언트의 경우 왠만한 데스크톱과 모바일 플랫폼 모두 지원한다. 방화벽이 뚫려있는 네트워크 환경이거나 회사 환경에서는 괜찮은 방법이다.

  • 지원 플랫폼: 윈도우, 리눅스, 맥, iOS 및 안드로이드, 라즈베리, FreeBSD, OpenWRT 지원 공유기 등
  • 무료: 255개 연결.
  • 유료: 연결 수 단위 패키지 판매 또는 클라이드 월정액 판매. 고급 사용자 관리 및 방화벽, 모니터링 및 추적 기능 제공.

7. ZeroTier

위 NeoRouter Mesh와 비슷한 버전이라 생각하면 된다. 중계 서버를 제공하는데, 공개형과 비공개형이 있다.
공개형 네트워크는 무제한 연결이 가능하며, 비공개형 네트워크는 100개의 연결을 지원한다.
전에도 언급했듯이 네트워크 연결 시 마이페이지에서 승인해야 하는 점은 여전하다. (단, 컴퓨터 당 한 번만 승인하면 된다.)

  • 무료: 무제한 공개 연결 및 100개 비공개 연결 (계정당)
  • 유료: 무제한 비공개 연결을 지원하는 베이직(29$/월) 및 자체구축을 지원하는 프로(100$/월)이 있음.
  • 지원 플랫폼: 윈도우, 맥, 리눅스, 몇몇 유명 NAS (GPL 오픈소스), iOS 및 안드로이드.

8. DynVPN

베타라서 언제 끊기나 했는데 아직도 멀쩡히 잘 살아있고, 공식 페이지에서도 가능한 영원히 무료로 제공하겠다고 공언했다. 일단 베타 딱지는 끊은 듯.
비공개 무제한 네트워크를 무료로 제공하는 특징이 있다. 방식도 여전히 컴퓨터를 미리 등록 후 나오는 비밀 키를 컴퓨터에 설치 시 등록하는 점이 되겠다.

  • 지원 플랫폼: 윈도우, 맥, 리눅스, 라즈베리파이

composite / 2018년 4월 30일 / Dog's bullshit / 0 Comments

즉석 관리자 권한을 위한 윈도우 BATCH 스크립트

간단한 팁을 주도록 하겠다.
아마 가장 짧은 관리자 권한 상승 후 실행 스크립트 되겠다.

배치 파일을 작성하다 보면 관리자 권한 상승을 요할 때도 있다.
그러다가 관리자 권한 여부를 확인 후 아니면 관리자 권한 달라고 메시지 날리고 끌 수도 있긴 하다.
하지만 사용자에겐 불편할 수밖에 없다.
그래서 Stack overflow에서도 배치 파일로 관리자 권한 상승에 대한 커뮤니티 연구가 진행되었고.
우린 윈도우 7 까지는 관리자 권한 상승을 아예 꺼서 못느꼈을 수도 있겠지만,
윈도우 8부터는 관리자 권한을 끄면 여간 불편한 일이 생기는 게 한두개가 아니고 레지 건드리는 방법 외엔 없어서
국내 액티브엑스도 처음엔 관리자 권한 끄라고 요청했다가 보안 전문가들에게 털리고 이제 관리자 권한 상승을 요구한다.

어쨌든, 이 마법의 구분을 공개하도록 하겠다.

@ECHO OFF

NET SESSION 2>nul >nul
IF %ERRORLEVEL% NEQ 0 (
IF "%1" == "ELEVATED" GOTO NOTELEVATED
GOTO ELEVATE
)
GOTO ADMINTASKS

:ELEVATE
pushd %~dp0
MSHTA "javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', 'ELEVATED', '', 'runas', 1);close();"
EXIT

:ADMINTASKS
REM 여기에 관리자 권한 상승 후 배치 내용 나열
PAUSE
EXIT

:NOTELEVATED
echo No admin rights
PAUSE
EXIT

자, 처음에 NET SESSION 이라는 꽤 생소한 명령어가 있다. 보통 NET 명령어는 서비스 시작/종료하거나 방화벽 설정 시 자주 사용한다.
SESSION 명령어는 당신 컴퓨터로 공유 폴더던 뭐던 접속할 때 컴퓨터 목록을 띄우는 명령어인데, 목록이 있던 없던 종료 코드는 0이고, 대체적으로 관리자 권한이 없는 경우 외에 오류 코드가 없기 때문에 사용한 것이다.
게다가 NET 명령어는 HELP 수식어가 없으면 무조건 관리자 권한이 필요한 특징을 가지고 있다. 그래서 가장 간단하게 관리자 권한 여부를 확인할 수 있는 마법의 명령어 되시겠다.
뒤에 2>nul >nul 은 아무것도 출력하지 못하게 하는 연산 명령어다. 보통 파일명 붙이면 명령어 출력 결과를 파일로 저장하는데, nul은 일종의 블랙홀 되시겠다.
2는 오류 출력을 가리키는데, 오류 출력도 가리고, 일반 출력도 가리게 하는 연산 명령어라 보면 된다.

이리하여 if 문으로 명령어 결과 코드가 0이면 관리자 권한으로 넘어가면 되고, 그 외 숫자일 경우 관리자 권한을 요청하여 분기로 나눈다.
이제 중요한 부분인데, 보통 BAT 자체로는 관리자 권한 상승이 불가능하기 때문에 임시 폴더 등에 Shell.Application 객체가 담긴 vbs 파일을 만들어 실행했었다.
하지만 이번에는 시스템급 웹 페이지를 띄우는 .hta 파일을 실행하는 mshta를 사용했다. javascript: 프로토콜도 먹힌다. 애초에 엔진이 IE니까.
그리고 내용이야 vbs 생성 내용과 크게 다를 거 없다. 단지 특징이 있다면 배치 파일 자신을 다시 실행하는 거다. 이것도 기존과 크게 다를 게 없다.
이리하여 관리자 권한을 얻으면 다시 BAT 파일을 실행하게 되고, 못얻으면 그냥 종료된다.
관리자 권한을 얻게 되면, ADMINTASKS 부분으로 이동하여 명령어를 실행하게 된다. 그 부분 아래 원하는 명령어 내용을 입력하면 된다.
말이 거창하지만 짧고 간결하며 윈도우 10 최신 환경에서도 실행 잘되는 배치 파일 되시겠다. 유용하게 쓰도록.

출처: Stack overflow – How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?

composite / 2018년 4월 27일 / Piss Development / 0 Comments

경력있는 신입 개발자 공채 안내 (부제: 그 회사는 믿고 걸러라)

요즘 스타트업부터 중소, 중견기업, 심지어 대기업까지 소위 경력있는 신입 개발자를 뽑고 있다.
경력있는 개발자의 예를 들자면,

경력있는 신입 개발자 예

여기서 경력있는 신입 개발자를 뽑는 특징을 분석하면 대충 이러하다.

  • 절대 경력을 뽑지 않는다. 대부분 선임 개발자가 있는 경우가 대부분이기 때문.
  • 선임 개발자와, 대표 또는 인사담당자 간의 충원 안건 협의 후, 어자피 지식은 없으니 형식적으로 기술.
  • 또는, 선임 개발자의 인사업무 경력 없는 의도적인 서술.
  • 가장 대표적인 예로 필요한 기술들을 아는대로 일단 나열하고 보는 식.
  • 심지어는 신입을 뽑는데 경력을 요구하는 경우. 예) 회계 업무 경험자
  • 그리고 마지막으로 지원자격과 우대사항을 거창하게 써놓고 그 다음 복리후생 같은 안내와 채용 과정을 대충 싸갈기거나 취업 사이트 기본 템플릿 그대로 기재.
  • 연봉낚시 (요즘 신입 연봉 4000 이상 심지어 5000 내외 준다는 낚시성 공채가 많다)

대부분 공채에 해당하며, 추천의 경우는 저런 거창한 내용이 없으므로 그냥 기존 개발자 주위에 적당한 인맥에 맞는 인재 구해다 쓰는 경우가 대부분이다.

이런 회사들에 들어갈 경우, 일단 서류와 면접은… 거창한 내용과 달리 별 다를 게 없다. 정말로.
하지만 헬게이트는 입사 확정하는 순간부터이다. 당연하겠지만…

  • 중소기업이나 스타트업 주제에 신입 연봉으로 4000 이상을 준다고? 천만에. 절대로 안준다. 무조건 핑계대면서 신입 연봉으로 맞춘다. 무조건이다. 100%다.
  • 의무는 정직원, 권리는 프리랜서(즉, 없다. 수습기간은 기본으로 깔고, 4대포험 외의 복리후생 따위는 없고, 휴가도 없다).
  • 무능력한 선임 개발자 또는 악랄한 선임 개발자, 또는 곧 나갈 개발자 셋 중 하나 이상을 만난다.
  • 인수인계 기간이 짧다. 10년 경력의 고급 개발자도 1달 미만의 인수인계 기간이 벅찬데, 신입에게 2주의 인수인계 기간을?
  • 개발자가 아닌 직원 및 대표는 아마 뽑힌 개발자가 맥가이버인줄 안다.
  • 유난히 성과를 중시하는데, 특히 개발자에게 성과는 의무다. 왜냐고? 개발자는 인력 투자가 아닌, 손실 비용으로 취급하기 때문…
  • 이들 회사는 해당 직원에 대한 유사시 대비를 위해 취업부터 퇴직까지 온갖 안전장치와, 정부지원 두마리 토끼를 잡아 먹고산다. (대부분 중소기업의 종특)

내가 감히 신입 개발자에게 취업 조언을 하자면, 물론 예전보다 좀 빡세진 감은 있긴 하다. 하지만 어쩔 수 없다. 기술이 발달했기 때문에.

  • 초봉 평균 3000 정도다. 물론 이상 주는 곳도 있다. 하지만 너무 많이 준다하면 아무리 네임드라도 위 사례처럼 사기성이 짙다. 가지 마라.
  • 코딩 시험 및 이론은 필수다. 반드시 익히고 그런 스킬을 요구하는 곳으로 들어가라. 요구하는 곳은 최소한 날로 먹는 개발 실무진들이 아니다.
  • 포폴은 하나씩 준비하라. TODO 같은 허접한 프로그램이라도 상관없다. 자신의 기술로 만들 수 있다는 거 하나씩 준비하라. 많은 도움이 될 것이다.
  • 인맥은 반드시 챙겨라. 이건 그 어느 직종이던 무조건 필수 사항이다. 인재추천으로 쉽게 들어갈 정도는 아니지만, 경험에서 우러나온 팁이 인터넷에 돌아다니는 팁보다 더욱 알차다.
  • 흔히 사용하는 언어로 하되(자바, 파이썬 등), 남이 잘 안하는 기술은 허접해도 상관없으니 익혀라. (예: 인공지능, 블록체인 등). 필요 시 당신의 구세주가 되줄 수 있다.
  • 자신의 주력기술을 파악하고 단련하라. 그 어떤 언어던, 기술이던 상관없다. 맞다 싶으면 미치도록 파라. 선배 및 선임에게 신임을 주기 아주 좋은 모습 바로 그 모습이다.
  • 확실한 취미를 가져라. 여러 사람이 가질 수록 더욱 좋다. 테니스나 탁구, 오타쿠가 되어도 상관없다. 단체 생활의 기본이다. 특히 취업 후 퇴근이 부드러워진다.
  • 만약 자신이 할 수 있으면 어느 곳이던 참여하라. 그게 경력이고 커리어다. 세미나나 기술발표 등, 회사에 양해를 구해서라도 참여하라. 인맥과 기술단련 두마리 토끼가 잡힌다.

끗.

composite / 2018년 4월 26일 / Piss Development / 0 Comments

개인적으로 Cygwin을 절대 비추하는 이유 (부제: 걍 WSL 써라)

지금은 윈도우 10에 서브시스템 우분투를 설치해 우분투 내에서 할거 하고 있다.

node.js 가 아직 윈도우를 지원하지 않던 시절, 나는 한번 cygwin 을 깔아서 node.js를 설치했다.
잘 된다. 일단은. 일부 기능이 빠졌다고 나와 있다고는 하지만 딱히 불만은 없었다.
하지만 cygwin을 쓰면서 네이티브 리눅스와보다 불편한 감을 지울 수 없었고,
게다가 MS가 직접 나서서 libuv를 윈도우 포팅에 성공하여 node.js가 윈도우에서도 쓸 수 있는 날이 왔고,
나는 이제 더 이상 cygwin이 필요 없어서 지우려고 했으나… 안됐다.
결국 나는 윈도우를 밀어서 cygwin의 흔적을 지워버렸다.

Cygwin은 UNIX 콘솔의 편리함을 그대로 윈도우에서 쓸 수 있는 일종의 미들웨어이다.
Cygwin에서 유닉스 기반의 네이티브 컴파일도 가능하고 왠만한 도구들(쉘, 프로그램, 도구, ssh, git 버전관리 등등)을 그대로 지원한다.
하지만, 나는 이걸 쓰는 것보다 차라리 윈도우 10을 깔고, 거기에 서브시스템 리눅스를 깔라고 하고 싶다.
위키에서도 소개되긴 했지만… 왜그런지 짧게 설명자면…

  • 패키지 관리자의 부재 (apt, yum 등)
  • Windows 계정 종속적인 사용자 (Bitvise SSH Server도 마찬가지긴 하지만…)
  • 일부 커널 종속적인 프로그램 미지원 (docker 등)
  • 편해 보이지만 은근 불편한 언인스톨 시스템
  • 더럽게 느린 성능
  • 애매한 보안 정책 (관리자 계정은 root…)

아무리 장점이 많아도 단점이 모두 씹어먹기 때문에 나는 앞으로도 cygwin을 이용할 생각 절대로 없다고 보면 된다.
만약 윈도우에서 리눅스를 돌리고자 한다면, 나는 단 1초의 고민도 없이 윈도우 10의 서브시스템 리눅스를 권유하거나, 가상OS를 권하고 싶다.
VMWARE나 VirtualBox 등 가상 사용법이야 뭐 다들 알 것 같으니 넘어가고, 윈도우 10의 리눅스 기능에 짧막하게 소개하겠다.
일단, 윈도우에서 설치 가능한 리눅스는 아래와 같으며,
심지어 윈도우 서버 2016에서 빌드 1706 이상일 경우에도 일부 리눅스 설치가 가능하다.

  • Ubuntu (서버 2016 지원)
  • openSUSE (서버 2016 지원, Hyper-V 공식지원)
  • SLES (SUSE Linux Enterprise Server) (서버 2016 지원, Hyper-V 공식지원)
  • Kali Linux

해킹과 보안에 매달리는 사용자는 Kali까지 지원되니 고민 없이 설치하면 된다.
비록 설치 시 손 댈 곳은 많지만, 완벽한 리눅스 환경을 제공하면서, 게다가 커널도 일반 리눅스 커널이라 지원되는 커널이 있는 프로그램이라면 모두 설치가 가능하다.
게다가 성능은 기존 자원을 유동적으로 활용하기 때문에 사양에 따르긴 하겠지만 Cygwin보다 훨씬 부드럽게 동작한다.
나는 Ubuntu를 설치했는데, 재밌는 점이 윈도우 상에서 관리자 권한을 필요한 폴더나 파일일 경우 Ubuntu 에서도 sudo 등의 권한 상승을 요구한다는 점이다.
물론 TrustedInstaller 권한이 있는 파일이나 폴더는 죽어도 못건드린다…

어쨌든 간에, 회사에서 리눅스 개발이나 테스트를 겸하고 싶다면, 2가지 방법이 있는데,
스냅샷 등의 크리티컬 테스트를 요하는 환경이라면 아무래도 가상환경이 가장 이득이며,
그게 아닌 왠만한 실행 테스트 환경을 원한다면 윈도우 10에 리눅스 환경을 설치하는 것이 좋다. 회사에서는 그게 더 싸다. 물론 아예 리눅스 까는것보단 비싸긴 하겠지만, 문서작업 때문에 윈도우 쓸 수밖에 없는데 뭐.

추가내용:
WSL에서는 docker 못돌린다. 커널과 환경은 docker 사양에 맞긴 하지만 가장 중요한 chroot 명령어가 없기 때문이다… 이는 WSL에 SSH 서버 돌리는 법에서도 언급했다.
docker 같은 크리티컬한 작업을 원한다면 가상 돌리는 게 훨씬 이득이다. 그밖에 가벼운 일반적인 사용 용도(node.js나 python 돌리는 등)에 WSL 쓰도록.

composite / 2018년 4월 24일 / Piss Development / 0 Comments

MacOS를 고민하는 개발자에게…

MacOS를 권장할 개발자

  • iOS 환경이 필요한 모바일 개발자
  • 크로스 플랫폼 개발자 (웹 제외)
  • 파이썬, 루비, 자스 등 스크립트 기반 언어 전문 개발자
  • 자동화와 키보드에 익숙한 개발자
  • 해외에서 개발할 개발자

MacOS를 쓰지 말아야 할 개발자

  • Eclipse 외에 안쓰는 자바 개발자
  • 전자정부로 먹고사는 개발자
  • Visual Studio 외에 안쓰는 닷넷/응용 개발자
  • Docker 등 컨테이너 위주의 개발자 (Docker 배포만 할 개발자 제외)
  • 심심할 때 게임할 개발자
  • 윈도우 7 이하 설치한 개발자
  • 마우스에 익숙한 애매한 개발자
  • 카공족

자바 개발자들, 이클립스는 리눅스에서 쓰기가 더 편하다는 거 알랑가몰라.(우분투 같은 GUI 기반)
만약 당신이 자바 개발자이고, 우분투 등의 리눅스 개발환경에서 자바 개발하는 선배 개발자를 만나면, 깍듯이 예를 대하거라. 보통 내공이 아닌 분이니라.

composite / 2018년 4월 18일 / Piss Development / 0 Comments

MacOS 하이시에라 root 로그인 겸 취약점

어느 OS던 보안에 자유로울 수 없다. 이건 당연하다.
그래서 각자 나름의 보안 정책으로 OS의 보안을 책임진다.

윈도우를 예를 들면,
Administrator 계정은 윈도우 설치 시 비활성화한다. (기본값 User, 튜닝으로 자동 활성화는 가능, 서버 제품군은 제외)
윈도우는 “비번 없음” 과 “비활성화” 속성이 다름에 유의하라.
그리고 어떤 계정이던 간에 비밀번호를 설정하지 않으면 원격 데스크톱 접속을 막는다.
그리고 UAC.

리눅스와 맥이야 UAC 비슷하게 시스템을 건드리는 작업이 발견되면 인증을 요구한다.
요즘 리눅스는 root 비밀번호가 없다. 비밀번호가 없다면 그 계정은 비활성화나 다름없는 것이다.
대신에 sudo를 통해 root 행세를 할 수 있고, 필요시 sudo passwd -u root 명령어로 비번을 바꿈으로 인해 root 계정 활성화는 가능하다.

대충 이런 식이다.

근데… 맥. 그것도 최신 버전인 하이 시에라에서는…
root 비번이 없는데도 불구하고 활성화가 가능한 어이 상실하는 취약점이 발견됐다.

방법은 이렇다.

설정(Preferences)에 들어간 뒤, 아무 설정이나 간다. 계정 관련 설정이면 접근이 더 쉬울 것이다.
그리고, 우측 하단 자물쇠가 있는데 그 아이콘을 누른다.

설정

그리고 사용자엔 root 입력한 뒤, 비번은 입력하지 않고 승인(Unlock) 버튼을 누르면 된다.
물론 한번에 안된다. 여러번 하면 된다. 여러번.

그러면 로그인 성공한 것처럼 인증 창이 닫히면서 자물쇠가 풀린다.

자. 이제 당신의 맥은 좆됐다는 마음가짐으로 임해야 한다.

이제 이로 인해 당신의 맥의 잠재적인 위험성이 뭐가 있을까?

  • 만약 당신의 맥을 원격으로 ssh 명령어를 통해 접근할 경우 비번 없이 root에 접근할 수 있다.
  • ssh 뿐만이겠나? VNC 등 원격으로 접근 가능한 모든 수단이 털릴텐데.

뭐 대충 설명해도 위험성은 충분히 인지했으리라 믿는다. 공중 WiFi 들어가는 순간 니 맥은 공공재가 되는 것이다.

그렇다고 그걸 막는 방법이 없는 건 아니다.
가장 간단한 방법은 우분투에 root 비번 바꿨던 것처럼 명령어를 이용해 바꾸는 것이다.
터미널 열고,
sudo passwd -u root
그리고 원하는 강력한 비번을 입력하면 조치는 끗. 제발 특문까지 들어간 강력한 비번 써라. 제발이다.

아래는 간단한 root 인증여부를 확인하는 스크립트이다. 대충 UI 자동화 스크립트라고 보면 되겠다.
osascript -e 'do shell script "id" with administrator privileges user name "root" password ""'

이 문제는 하이 시에라에서만 발생한 문제이고 수정 사항이며, 하위 버전은 신경 안 써도 된다.
당연히 발견자는 애플에게 보고했고, 이제 애플의 응답만 남았다. 왜냐면 이건 한국시각으로 글을 최초로 쓴 날 새벽에 발견한 취약점이기 때문이다.

끗.

composite / 2017년 11월 29일 / Piss Development / 0 Comments

Windows 10/Server 2016 이상에서 원격 액세스 및 라우터 없이 NAT 사용하기

보통 윈도우 환경에서 공유기 같은 환경을 구성하기 위해서 NAT 소프트웨어나, 또는 서버의 경우 원격 액세스 및 라우터 기능을 설치한다.
윈도우 10부터, 또는 서버 2016 부터, 이제 원격 엑세스 기능이 없어도 NAT 기능을 제공하는 powershell cmdlet 을 제공한다.
바로 NetNat 모듈이다.

https://docs.microsoft.com/en-us/powershell/module/netnat/?view=win10-ps

모듈 이름 그대로 NAT 환경을 제공한다. 이로 인한 이점은 아래와 같다.

  • 윈도우 10에서 사용 가능. 특히 원격 액세스 및 라우터 없어도 환경설정 가능
  • 위 기능으로 바로 Hyper-V 내부 네트워크 구성에다가 인터넷 연결이 가능
  • 심지어 여러 NAT 구성 가능

기능상 이점으로 주로 Hyper-V 환경을 구축할 때 많이 이용한다.
사용 방법을 알아보자.

인터페이스 구축

실제 랜카드

공유로 사용할 랜카드에 원하는 게이트웨이 IP를 설정하면 된다. 예를 들면 IP는 192.168.0.1 넷마스크 255.255.255.0 끝.
DNS는 원하면 구축하고 싫으면 안하면 된다. 비워도 어자피 ISP에서 제공하는 DNS 물려받게 되어 있다.
그냥 파워쉘로도 당연히 IP 부여가 가능하다. 자세한 설명은 아래 섹션 참고하자.

New-NetIPAddress –IPAddress 192.168.0.1 -PrefixLength 24 -InterfaceAlias "공유로 쓸 네트워크 이름"

Hyper-V

주로 Hyper-V 환경을 예시로 들도록 하겠다. 준비물은 Powershell 관리자 권한이 부여된 콘솔 창을 띄우기만 하면 준비 끝.
Hyper-V 관리자에서 가상 스위치 관리자를 통해 내부 네트워크에 원하는 이름으로 생성한 뒤, 네트워크 및 공유 센터 > 어댑터 변경에서 실제 랜카드처럼 생성한 Hyper-V 내부 내트워크의 IP를 원하는 게이트웨이 IP로 설정해도 되고, powershell 로 가상 내부 내트워크를 생성한 뒤 바로 IP 부여가 가능하다.

먼저, Hyper-V 가상 스위치 중 내부 네트워크 드라이버를 하나 생성한다.

New-VMSwitch –SwitchName "원하는이름" –SwitchType Internal

실행 후 vEthernet (원하는이름) 이런 식으로 명명된 가상 네트워크가 인터페이스가 생성될 것이다.
그다음 생성한 인터페이스의 IP를 부여한다. IP는 예시를 든 것이므로 원하는 IP 대역으로 수정하도록 한다.
PrefixLength 는 CIDR 마스킹 넘버로 24는 255.255.255.0을 가리킨다. 이것도 상황에 따라 원할 경우 변경할 수 있다.

New-NetIPAddress –IPAddress 192.168.0.1 -PrefixLength 24 -InterfaceAlias "vEthernet (원하는이름)"

사실 UI에서 네트워크 및 공유 센터 > 어댑터 변경 을 통해 변경해도 지장 하나도 없다.

NAT 환경 구성

이제 본격적으로 NAT를 구성하도록 하겠다.
라고 하지만 사실 별거 없다. 이제 파워쉘을 준비했으면 한줄 추가하면 끝.
마지막 InternalIPInterfaceAddressPrefix 인자에서 마스킹 IP를 입력하면 되는데,
예를 들어 192.168.0.1 넷마스크 255.255.255.0 설정했으면 192.168.0.0/24 이렇게 입력하면 된다.
원하는공유명칭 에 원하는 공유 식별자를 입력하면 되는데, 삭제 시 적어두었던 식별자를 통해 삭제할 수 있다.

New-NetNat –Name 원하는공유명칭 –InternalIPInterfaceAddressPrefix 192.168.0.0/24

끝이다. 허무할 정도로 간단하게 NAT 설정은 끝났고 공유기처럼 환경 구성하는 방법은 준비가 완료된 것이다.

참고로 삭제는 아래와 같다.

Remove-NetNat –Name 원하는공유명칭

포트 포워딩

만약 가상 컴퓨터의 특정 포트를 외부에서 접속하거나, 지금 윈도우 컴퓨터로 연결된 하위 네트워크에 있는 서비스 포트에 외부로 접속하고 싶다면,
물론 안전하게 VPN 구축해서 서비스하는 것을 추천하지만, 필요할 경우 포트포워딩도 추가 및 관리가 가능하다.
내부 공유 컴퓨터에서 80번 포트를 통해 웹 서비스하고 있는 걸 외부에서 82번 포트를 통해 접속하고자 할 경우를 예를 들어 작성하도록 하겠다.

Add-NetNatStaticMapping -NatName "원하는포트포워드명" -Protocol TCP -ExternalIPAddress 0.0.0.0 -InternalIPAddress 192.168.0.2 -InternalPort 80 -ExternalPort 82

그렇다. InternalPort 인자에 내부 공유 컴퓨터가 서비스하는 포트, ExternalPort 인자에 외부에서 접속할 포트를 입력하면 된다.
그리고, Protocol 이야 TCP, UDP 등 일반적인 인터페이스일 테고,
ExternalIPAddress 인자에 외부에서 허용할 IP 대역을 입력하는데, 0.0.0.0 이면 모든 외부 접속이 허용된다고 보면 된다.
그리고 InternalIPAddress 인자에다가 내부 컴퓨터나 가상컴 IP를 입력하면 된다.

반대로 삭제하고자 할 경우 아래처럼 하면 된다.

Remove-NetNatStaticMapping -NatName "원하는포트포워드명"

DHCP는?

만약 윈도우 10이면, 기능 없다. 외부 프로그램 아니면 포기하는게 편하다.
그리고 윈도우 서버다? 그러면 할 수 없이 DHCP 서버를 깔아야 한다.
윈도우 서버의 DHCP 서버 사용 방법은 직접 검색하거나 도움말 보거나 하면 되고,
윈도우 10이면, 몇가지 도구와 방법이 제공되는데, 링크 가서 알아보면 되겠다.

  1. DHCP Server for Windows
  2. TFTP32 – 주로 네트워크 부팅 서버 구축에 많이 사용되는데 DHCP도 제공한다.
  3. isc-dhcp-server DHCP 서버 설치
    윈도우 우분투 서브시스템 이용, 완전한 서버를 유지하도록 사용하기 위해서는 내 글 참고.

이상 끗.

참고

NetNat – cmdlet – MSDN
SET UP A HYPER-V VIRTUAL SWITCH USING A NAT NETWORK

composite / 2017년 11월 23일 / Piss Development / 0 Comments

오라클 12C의 유용한 배열 처리기능

현재 내가 있는 프로젝트는 오라클 12c를 쓰고 있다.
하지만 치매걸린 DBA는 오라클 8i 시절의 기술을 요구한다.
예를 들면, ANSI JOIN 쓰지 말고 오라클 전용 JOIN 문 작성, 가능한 단일 쿼리로 모두 해결하라 등…
오라클이 그렇게 ANSI JOIN 써라 써라 해도 치매걸린 새끼들은 한국 IT의 하느님 오라클 말도 씹고 그러는데 뭐.

이럴 거면 시발 8i를 깔지 뭐하러 비싸게 12c 구축하고 지랄이야.
하긴 10g 이하는 더이상 판매도 하지 않는데 뭐…

뭐 다른 건 모르겠고, 한가지 국내 오라클 개발자들이 구미가 당길만한 새로운 기능을 소개하고자 글을 쓴다.
12c 나온지 좀 됐긴 하지만, 12c 구축한 곳 치고는 12c의 혜택을 보는 프로젝트는… 절래절래 할 것이다.
당장 내가 소속된 프로젝트부터 2000년대부터 치매걸린 아키새끼들이 프로젝트 설계했는데 뭘 더 바라겠냐만은…

본문으로 들어가서, 오라클의 SQL에서는 TABLE이라는 함수가 있다.
다들 알다시피, 테이블 함수를 테이블로 이끌기 위해 많이들 쓸 것이다.

SELECT * FROM TABLE(MY_TABLE_FUNC('FOO'))

하지만 그 뿐. 한계가 많았는데, 먼저 배열 타입(TABLE OF, VARRAY()) 조차도 지원 안한다. 테이블 함수와 외부 테이블 등을 지원한다.
예를 들면, 11g 까지는 이렇게 쿼리 짜면 안돌아간다.

CREATE OR REPLACE TYPE emp_typ IS OBJECT (
   emp_name VARCHAR2(16);
   emp_rank NUMBER(1);
);
CREATE OR REPLACE TYPE emp_arr IS TABLE OF my_texts;
/
DECLARE

  my_emp emp_arr;

BEGIN

  SELECT emp_name, emp_rank
  BULK COLLECT INTO my_emp
  FROM emp
  WHERE emp_rank < 10;

  FOR my_row IN (
    SELECT * FROM TABLE(my_emp)
  ) LOOP

    DBMS_OUTPUT.PUT_LINE(my_row.emp_name);

  END LOOP;

END;

테스트는 안해봤지만, 문법에 문제가 없다 해도 “cannot access rows from a non-nested table” 오류가 뜰 것이다.
이제 12c부터는 배열이 지원된다. CREATE TYPE 문을 통해 선언한 배열은 당연히 지원되고, 심지어 CREATE PACKAGE 안에 있는 배열까지 지원한다.
백문이 불여일견, 예제를 보자.

CREATE OR REPLACE PACKAGE test_api AS
  TYPE t_row IS RECORD (
    empno NUMBER(4),
    ename VARCHAR2(10)
  );

  TYPE t_tab IS TABLE OF t_row
    INDEX BY BINARY_INTEGER;

  PROCEDURE test1 (l_tab1 test_api.t_tab);
END;
/

CREATE OR REPLACE PACKAGE BODY test_api AS

  PROCEDURE test1 (l_tab1 test_api.t_tab) IS
  BEGIN
    DBMS_OUTPUT.put_line('Loop Through Collection');
    FOR cur_rec IN (SELECT *
                    FROM   TABLE(l_tab1))
    LOOP
      DBMS_OUTPUT.put_line(cur_rec.empno || ' : ' || cur_rec.ename);
    END LOOP;
  END;

END;
/


declare

tt test_api.t_tab;

begin

select 1,'a'
bulk collect into tt
from dual;

test_api.test1(tt);

end;

안타깝게도 SQLFIDDLE은 아직 오라클 11g라 테스트를 돌려볼 수 없다.
대신 오라클에서 교육 용도로 무료로 오라클 실행환경을 제공하는 Oracle Live SQL 에서 테스트 가능하다.
어찌저찌 12c에서 실행하면 잘 되는데, TABLE(l_tab1) 부분을 주목하자.
엄연히 패키지 내에 선언한 배열이고, 그 배열은 심지어 RECORD 형식이다.
보통 RECORD 형식은 PL/SQL 전용 문이기 때문에 SQL 쿼리문에서는 절대 안돌아가는 게 정석이다. 11g까지는.
하지만 패키지에 한해 RECORD 형식도 SELECT 문 같은 쿼리문이 지원되니 참 편하지 아니할 수가 없다.

하지만 이 기능도 한계가 있다. SQLPL/SQL 문은 컨텍스트가 틀리다.
당연히 데이터베이스에서 선언해야 쿼리가 돌아가는 특성상,
인라인 형식(익명 블록 내 DECLARE)에서 선언한 배열은 지원하지 않는다. 물론 거기서 선언한 RECORD 문은 말할 것도 없고.
패키지의 경우에서는 PACKAGE BODY 문에서 선언한 배열이나 RECORD 형식에서 선언하면 지원하지 않는다.
이들 모두 “cannot access rows from a non-nested table” 오류가 뜰 것이다.
보통 개발자들에게 TYPE 권한을 잘 안열고, 프로시저, 함수, 패키지에 한해 권한을 어느정도 오픈하는 환경이기 때문에, 12c가 구축된 환경에서는
쿼리를 짜는데 있어서 부담이 덜할 수 있는 좋은 기능이다.

뭐 MSSQL의 테이블 변수 기능에 흠뻑 젖은 개발자라면 여전히 불편한 건 매한가지다.

끗.

참고

composite / 2017년 11월 10일 / Piss Development / 0 Comments

1 2 3 24