pl/pgsql을 이용한 테이블 업데이트(Update)

기존의 테이블에 새로운 필드를 추가하고, 이 필드에 값을 넣어야 할 필요가 있습니다. 상황은 지적도가 저장된 테이블의 PNU 필드를 파싱해서 번지값을 만들어 저장해야 합니다. 예를 들어서 PNU가 ‘2911011200200470001’라면 ’47-1산’으로 만들어야 한다는 것입니다.

사용하는 데이터베이스가 PostgreSQL이므로 pl/pgsql을 이용하였는데요. cursor를 이용하는 방식과 cursor를 이용하지 않는 방식이 있는데.. 먼저 cursor를 이용하지 않는 방식은 아래와 같습니다.

DO $$
DECLARE
    r RECORD;
    n1 INTEGER;
    n2 INTEGER;
    s TEXT;
    v TEXT;
BEGIN
    FOR r IN SELECT * FROM ecl_cadastral LOOP
        n1 = substr(r.pnu, 12, 4)::INTEGER;
        n2 = substr(r.pnu, 16, 4)::INTEGER;
        s = substr(r.pnu, 11, 1);
        
        IF n2 = 0 THEN
            v = n1;
        ELSE
            v = n1 || '-' || n2;
        END IF;

        IF s = '2' THEN
            v = v || '산';
        END IF;

        UPDATE ecl_cadastral SET label = v WHERE fid = r.fid;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

동일한 기능으로 cursor를 이용하는 방식은 아래와 같습니다.

DO $$
DECLARE
    c CURSOR FOR SELECT * FROM ecl_cadastral;
    r RECORD;
    n1 INTEGER;
    n2 INTEGER;
    s TEXT;
    v TEXT;
BEGIN
    FOR r IN c LOOP
        n1 = substr(r.pnu, 12, 4)::INTEGER;
        n2 = substr(r.pnu, 16, 4)::INTEGER;
        s = substr(r.pnu, 11, 1);
        
        IF n2 = 0 THEN
            v = n1;
        ELSE
            v = n1 || '-' || n2;
        END IF;

        IF s = '2' THEN
            v = v || '산';
        END IF;

        UPDATE ecl_cadastral SET label = v WHERE CURRENT OF c;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

속도는 cursor를 이용하는 방식이 약 20% 정도 빨랐습니다.

FingerEyes-Xr for HTML5의 레이어 추가시 연결 완료 이벤트

FingerEyes-Xr에서 레이어를 추가하기 위한 매서드는 LayerManager의 add 입니다. 이 add 매서드는 2개의 인자를 받는데요. 첫번째는 추가하고자 하는 Layer 객체이고 두번째는 선택 사항으로 추가하려는 레이어가 네트워크를 통해 성공적으로 연결되었을 때 호출할 callback 함수입니다. 이 callback 함수는 레이어 추가시 개별적으로 세밀한 흐름 제어를 위해 사용됩니다. 이와 관련한 예는 아래와 같습니다.

var baseLyr = new Xr.layers.TileMapLayer(layerName,
    {
        url: "http://localhost/....",
        ext: "jpg"
    }
);

var lm = map.layers();

lm.add(baseLyr, 
    function (lyr) {
        lm.moveToFirst(layerName);
        map.updateLayer(layerName);
    }
);

위의 코드는 배경지도를 새롭게 추가할 때 추가된 레이어를 가장 첫번째 순위로 이동하고 추가된 레이어만을 새롭게 화면상에 업데이트하라는 코드입니다. 이러한 코드는 해당 레이어가 네트워크를 통해 완전히 연결된 이후에 실행되어야 하는 코드이므로 callback 함수의 사용에 적합합니다.

웹서버에 대한 Cross Domain 허용하기

개발 시에 다양한 웹서버에 대한 자원에 접근하기 위해 일시적인 방안으로 Cross Domain 접근을 허용할 필요가 있습니다. 이에 대해 각 웹서버에서의 방법이 상이한데요. 이에 대해 정리해 봅니다.

IE Express

IE Express가 실치된 Program Files(x86)/IIS Express/AppServer 폴더 안에 존재하는 applicationhost.config 파일에서 <customHeaders/> 부분에 <add name=”Access-Control-Allow-Origin” value=”*” />와 <add name=”Access-Control-Allow-Headers” value=”Content-Type” />를 추가합니다. 예를 들어 아래와 같습니다.

<httpProtocol>
    <customHeaders>
        <clear/>
        <add name="X-Powered-By" value="ASP.NET"/>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
    </customHeaders>
    <redirectHeaders>
        <clear/>
    </redirectHeaders>
</httpProtocol>

NGINX

NGINX가 설치된 폴더 안에 conf/nginx.conf 파일에서 ‘location /’ 부분의 블럭에 ‘add_header ‘Access-Control-Allow-Origin’ ‘*’;’ 추가합니다. 예를 들어 아래와 같습니다.

location / {
    #root   html;
    root e:/;
    add_header 'Access-Control-Allow-Origin' '*';
    index  index.html index.htm;
}

JavaScript 새로운 문법 정리

자바스크립트에서 var로 정의된 변수의 유효범위는 함수입니다. 일반적인 프로그래밍 언어에서 변수의 유효범위는 블럭(Block)인데요. 자바스크립트에서 블럭의 범위 지정을 위한 시작은 ‘{‘이며 끝은 ‘}’입니다. let을 통한 변수의 정의는 바로 이러한 블럭 범위에서만 유효한 변수를 정의할 수 있도록 합니다.

이러한 let 키워드를 통해 보다 분명한 의미로 변수를 정의해, 필요한 시점에서만 메모리에 적재되어 사용되고 필요하지 않은 시점에서는 메모리에서 제거되도록 할 수 있는데요. 아래의 예는 배열에 대한 각 요소를 저장하기 위해 i라는 변수를 let으로 선언하고 있습니다.

let a = [1, 2, 3];
for (let i of a) {
    alert(i);
}

let 키워드는 IE나 Chrome 모두에서 지원되지만, 위의 for 문은 IE(v11)에서 지원하지 않습니다.

아래의 코드는 배열에 대한 각 소요를 순회하며 처리할 수 있는 함수를 지정할 수 있는 배열의 forEach 매서드에 대한 예제 코드입니다.

function logArrayElements(element, index, array) {
    alert("a[" + index + "] = " + element);
}

[2, 5, 9].forEach(logArrayElements);

아래의 코드는 C++, Java, C#의 람다 함수와 매우 유사한 Javascript의 문법입니다. IE(v11)에서는 지원하지 않으며 Chrome에서만 지원합니다.

// Case 1 Start
sayHello = name => alert("Hello, " + name);
sayHello("Dip2K");
// Case 1 End

// Case 2 Start
setTimeout(() => alert("timeout!"), 2000);
// Case 2 End

// Case 3 Start
[2, 4, 8].forEach(item => alert(item));
// Case 3 End  
      
// Case 4 Start
calcCircumference = diameter => {
    return Math.PI * diameter;
}

alert(calcCircumference(10));
// Case 4 End

Javascript에서 함수를 정의시에 인자에 기본값을 지정할 수 있는데요. 아래의 코드에서 그 예를 명확히 살펴볼 수 있습니다.

function volume(l = 10, w, h = 10) {
    alert(l + " " + w + " " + h);
}

volume();

volume2 = (l = 10, w, h = 10) => {
    alert(l + " " + w + " " + h);
};

volume2();

Javascript에서는 C나 C#에서처럼 변수를 활용한 형식화된 문자열을 쉽게 구성할 수 있는 문법을 제공합니다. 아래는 first와 last라는 변수를 문자열을 구성하기 위해서 ${} 사용하고 있습니다. 문자열 구성을 위해 외따움표(‘)나 쌍따움표(“)가 아닌 `를 사용해야 한다는 점에 유의해야 합니다.

let first = "Kim";
let last = "Hyoung Jun";

const welcome = `You have logged in as ${first} ${last}`;

alert(welcome);

아래의 문법은 IE(v11)에서는 지원하지 않지만, 매우 유용한 것으로서 배열을 합치거나 복제하는데 유용하게 사용될 수 있습니다.

// Case 1 Start
const odd = [1, 3, 5];
const nums = [2, 4, 6, ...odd];
alert(nums);
// Case 1 End

// Case 2 Start
const odd2 = [...odd];
alert(odd2);
// Case 2 End

// Case 3 Start
const { a, b, ...z } = { a: 1, b: 2, c: 3, d: 4 };
alert(a);
alert(b);
alert(z);
// Case 3 End

Case 1은 odd 배열과 nums 배열을 합치는 것이고, Case 2는 odd 배열을 odd2 배열로 복제(참조가 아닌)하는 것입니다. Case 3는 다소 그 성격이 다른데 a는 1, b는 2, z는 {c:3, d:4} 객체가 됩니다.

아래의 문법은 Javascript의 람다 함수(명확히 람다 함수라고 불르는 것이 맞는지는 확실치 않으나)를 사용해 코드를 간결하게 표현한 것으로써, 배열의 요소 중 특정 조건에 일치하는 요소를 검색하는 것으로, 특정 조건을 람다 함수로 정의해 표현하고 있습니다.

const pets = [
    { type: 'Dog', name: 'Max' },
    { type: 'Cat', name: 'Karl' },
    { type: 'Dog', name: 'Tommy' }
];

pet = pets.find(pet => pet.name === 'Tommy');
alert(pet.type);

FingerEyes-Xr for HTML5의 DeferableLabelText 추상 클래스 사용하기

FingerEyes-Xr에서 제공하는 DeferableLabelText 클래스는 이원화된 DBMS로부터 데이터와 공간 데이터를 연계해 라벨의 텍스트로 표현할 수 있는 기능을 제공합니다. 이 글은 DeferableLabelText 클래스의 활용예에 대해서 최대한 간략하게 정리한 글입니다.

먼저 DeferableLabelText를 상속받은 예는 아래와 같습니다.

MyDeferableLabelText = Xr.Class({
    name: "MyDeferableLabelText",
    extend: Xr.theme.DeferableLabelText,

    construct: function () {
        this.superclass();
    },

    methods: {
        /* void */ requestLabelText: function (fid) {
            var that = this;

            // 이 부분은 DBMS로부터 데이터를 가져오는 AJAX 코드로 대체되어야 할 부분  
            setTimeout(function () {
                that.setText(fid, "HELLO");
            }, 1000);
        }
    }
});

이렇게 정의한 MyDeferableLabelText 클래스는 수치지도 레이어에 지정되며 아래의 예와 같습니다.

var lyr = new Xr.layers.ShapeMapLayer(layerId, ...);
lyr.deferableLabelText(new MyDeferableLabelText());