JavaScript UDF ์†Œ๊ฐœยถ

JavaScript๋กœ UDF(์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜)์˜ ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์„น์…˜์˜ ํ•ญ๋ชฉ์—์„œ๋Š” JavaScript ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์„ค๊ณ„ํ•˜๊ณ  ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

UDF ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ์–ธ์–ด ๋ชฉ๋ก์„ ํฌํ•จํ•˜์—ฌ, UDF์— ๋Œ€ํ•œ ์†Œ๊ฐœ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜ ๊ฐœ์š” ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ์žˆ์œผ๋ฉด SQL๋กœ UDF๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. SQL์„ ์‚ฌ์šฉํ•˜์—ฌ UDF์„ ๋งŒ๋“ค๊ฑฐ๋‚˜ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜ ์ƒ์„ฑํ•˜๊ธฐ ๋˜๋Š” UDF ์‹คํ–‰ํ•˜๊ธฐ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ๋กœ๊ทธ ๋ฐ ์ถ”์  ๋ฐ์ดํ„ฐ๋ฅผ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋กœ๊น…, ์ถ”์  ๋ฐ ๋ฉ”ํŠธ๋ฆญ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ฐธ๊ณ 

JavaScript UDF ์ฒ˜๋ฆฌ๊ธฐ์™€ ๊ด€๋ จ๋œ ์ œํ•œ ์‚ฌํ•ญ์€ JavaScript UDF ์ œํ•œ ์‚ฌํ•ญ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ด ํ•ญ๋ชฉ์˜ ๋‚ด์šฉ:

JavaScript ์ฒ˜๋ฆฌ๊ธฐ ์ž‘๋™ ๋ฐฉ์‹ยถ

์‚ฌ์šฉ์ž๋Š” UDF๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ UDF์˜ ์ด๋ฆ„๊ณผ ์ธ์ž๋ฅผ Snowflake์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. Snowflake๋Š” UDF์˜ ๋…ผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๊ด€๋ จ ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ(์ธ์ž๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์ธ์ž๋„ ํฌํ•จ)๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ฒ˜๋ฆฌ๊ธฐ ํ•จ์ˆ˜๋Š” ์ถœ๋ ฅ์„ Snowflake๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ  Snowflake๋Š” ์ด๋ฅผ ๋‹ค์‹œ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

UDF์— ์ „๋‹ฌ๋œ ๊ฐ ํ–‰์— ๋Œ€ํ•ด UDF๋Š” ์Šค์นผ๋ผ(์ฆ‰, ๋‹จ์ผ) ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜, ํ…Œ์ด๋ธ” ํ•จ์ˆ˜๋กœ ์ •์˜๋œ ๊ฒฝ์šฐ ํ–‰ ์„ธํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆยถ

๋‹ค์Œ ์˜ˆ์ œ์˜ ์ฝ”๋“œ๋Š” ์ž…๋ ฅ ARRAY๋ฅผ ๋ฐ›์•„ ์—ญ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ ์š”์†Œ๋ฅผ ํฌํ•จํ•œ ARRAY๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ๋กœ my_array_reverse ๋ผ๋Š” UDF๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. Snowflake๋Š” SQL-JavaScript ๋ฐ์ดํ„ฐ ํƒ€์ž… ๋งคํ•‘ ์— ์„ค๋ช…๋œ ๋งคํ•‘์— ๋”ฐ๋ผ JavaScript ์ธ์ž ๋ฐ ๋ฐ˜ํ™˜ ์œ ํ˜•์„ SQL๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ๊ทธ ๋ฐ˜๋Œ€๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

JavaScript ์ฝ”๋“œ๋Š” SQL ์ฝ”๋“œ์—์„œ ์ด๋ฆ„์ด ๋Œ€๋ฌธ์ž๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋„ ์ž…๋ ฅ ๋งค๊ฐœ ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ๋ชจ๋‘ ๋Œ€๋ฌธ์ž๋กœ ์ฐธ์กฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

-- Create the UDF.
CREATE OR REPLACE FUNCTION my_array_reverse(a ARRAY)
  RETURNS ARRAY
  LANGUAGE JAVASCRIPT
AS
$$
  return A.reverse();
$$
;
Copy

JavaScript ๋ฐ์ดํ„ฐ ํƒ€์ž…ยถ

SQL ๋ฐ JavaScript UDF๋Š” ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ง€์›์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์œ ์‚ฌํ•˜๋˜ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. Snowflake ๋ฐ JavaScript ๋‚ด์˜ ์˜ค๋ธŒ์ ํŠธ๋Š” ๋‹ค์Œ ๋งคํ•‘์„ ์‚ฌ์šฉํ•˜์—ฌ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

์ •์ˆ˜ ๋ฐ Doubleยถ

JavaScript์—๋Š” ์ •์ˆ˜ ํ˜•์‹์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์ˆซ์ž๋Š” Double๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. JavaScript UDF๋Š” ํ˜•์‹ ๋ณ€ํ™˜์„ ํ†ตํ•œ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ์ •์ˆ˜ ๊ฐ’์„ ํ—ˆ์šฉํ•˜๊ฑฐ๋‚˜ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ฆ‰, Double์„ ํ—ˆ์šฉํ•˜๋Š” JavaScript UDF์— ์ •์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Œ).

Snowflake SQL๊ณผ JavaScript๋Š” ๋‘˜ ๋‹ค Double ๊ฐ’์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ’์€ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

๋ฌธ์ž์—ดยถ

Snowflake SQL๊ณผ JavaScript๋Š” ๋‘˜ ๋‹ค ๋ฌธ์ž์—ด ๊ฐ’์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ’์€ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

์ด์ง„ ๊ฐ’ยถ

๋ชจ๋“  ์ด์ง„ ๊ฐ’์€ JavaScript Uint8Array ์˜ค๋ธŒ์ ํŠธ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ˜•์‹ํ™”๋œ ๋ฐฐ์—ด์€ ์ผ๋ฐ˜ JavaScript ๋ฐฐ์—ด๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋” ํšจ์œจ์ ์ด๊ณ  ์ถ”๊ฐ€ ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

JavaScript UDF๊ฐ€ Uint8Array ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์ด๋Š” Snowflake SQL ์ด์ง„ ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

๋‚ ์งœยถ

๋ชจ๋“  ํƒ€์ž„์Šคํƒฌํ”„ ๋ฐ ๋‚ ์งœ ํ˜•์‹์€ JavaScript Date() ์˜ค๋ธŒ์ ํŠธ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. JavaScript ๋‚ ์งœ ํ˜•์‹์€ Snowflake SQL์˜ TIMESTAMP_LTZ(3)์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

๋‚ ์งœ ๋˜๋Š” ์‹œ๊ฐ„์„ ํ—ˆ์šฉํ•˜๋Š” JavaScript UDF์— ๋Œ€ํ•ด ๋‹ค์Œ ์ฐธ๊ณ  ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

  • ๋ฐ€๋ฆฌ์ดˆ๋ฅผ ์ดˆ๊ณผํ•˜๋Š” ๋ชจ๋“  ์ •๋ฐ€๋„๋Š” ์†์‹ค๋ฉ๋‹ˆ๋‹ค.

  • SQL TIMESTAMP_NTZ์—์„œ ์ƒ์„ฑ๋œ JavaScript Date ๋Š” ๋” ์ด์ƒ โ€œ๋ฒฝ์‹œ๊ณ„โ€ ์‹œ๊ฐ„์œผ๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ผ๊ด‘ ์ ˆ์•ฝ ์‹œ๊ฐ„์ œ์˜ ์˜ํ–ฅ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์ด๋Š” TIMESTAMP_NTZ๋ฅผ TIMESTAMP_LTZ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ์˜ ๋™์ž‘๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

  • SQL TIMESTAMP_TZ์—์„œ ์ƒ์„ฑ๋œ JavaScript Date ๋Š” ํƒ€์ž„์กด ์ •๋ณด๋ฅผ ์†์‹คํ•˜์ง€๋งŒ, ์ž…๋ ฅ๊ณผ ๋™์ผํ•œ ์‹œ๊ฐ„์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค(TIMESTAMP_TZ๋ฅผ TIMESTAMP_LTZ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ์™€ ์œ ์‚ฌ).

  • SQL DATE๋Š” ํ˜„์ง€ ํƒ€์ž„์กด์˜ ํ˜„์žฌ ์ž์ •์„ ๋‚˜ํƒ€๋‚ด๋Š” JavaScript Date ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, DATE ๋ฐ TIMESTAMP ํ˜•์‹์„ ๋ฐ˜ํ™˜ํ•˜๋Š” JavaScript UDF์— ๋Œ€ํ•ด ๋‹ค์Œ ์ฐธ๊ณ  ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

  • JavaScript Date ์˜ค๋ธŒ์ ํŠธ๋Š” TIMESTAMP_LTZ(3)์—์„œ ๋ฐ˜ํ™˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ์˜ ์บ์ŠคํŠธ์™€ ๋™์ผํ•œ ๋ณ€ํ™˜ ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ์ค€์ˆ˜ํ•˜๋ฉด์„œ UDF์˜ ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

  • VARIANT ์˜ค๋ธŒ์ ํŠธ ๋‚ด๋ถ€์— ์ค‘์ฒฉ๋œ JavaScript Date ์˜ค๋ธŒ์ ํŠธ๋Š” ํ•ญ์ƒ TIMESTAMP_LTZ(3) ํ˜•์‹์ž…๋‹ˆ๋‹ค.

๋ฒ ๋ฆฌ์–ธํŠธ, ์˜ค๋ธŒ์ ํŠธ, ๋ฐฐ์—ดยถ

JavaScript UDF๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฒ ๋ฆฌ์–ธํŠธ ๋ฐ JSON ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ณ  ์ง๊ด€์ ์œผ๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. UDF์— ์ „๋‹ฌ๋œ ๋ฒ ๋ฆฌ์–ธํŠธ ์˜ค๋ธŒ์ ํŠธ๋Š” ๊ธฐ๋ณธ JavaScript ํ˜•์‹ ๋ฐ ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ด์ „์— ๋‚˜์—ด๋œ ๋ชจ๋“  ๊ฐ’์€ ํ•ด๋‹น JavaScript ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ๋ฒ ๋ฆฌ์–ธํŠธ ์˜ค๋ธŒ์ ํŠธ ๋ฐ ๋ฐฐ์—ด์€ JavaScript ์˜ค๋ธŒ์ ํŠธ ๋ฐ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, UDF์—์„œ ๋ฐ˜ํ™˜๋œ ๋ชจ๋“  ๊ฐ’์€ ์ ์ ˆํ•œ ๋ฒ ๋ฆฌ์–ธํŠธ ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. UDF๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์˜ค๋ธŒ์ ํŠธ์™€ ๋ฐฐ์—ด์—๋Š” ํฌ๊ธฐ์™€ ๊นŠ์ด ์ œํ•œ์ด ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

-- flatten all arrays and values of objects into a single array
-- order of objects may be lost
CREATE OR REPLACE FUNCTION flatten_complete(v variant)
  RETURNS variant
  LANGUAGE JAVASCRIPT
  AS '
  // Define a function flatten(), which always returns an array.
  function flatten(input) {
    var returnArray = [];
    if (Array.isArray(input)) {
      var arrayLength = input.length;
      for (var i = 0; i < arrayLength; i++) {
        returnArray.push.apply(returnArray, flatten(input[i]));
      }
    } else if (typeof input === "object") {
      for (var key in input) {
        if (input.hasOwnProperty(key)) {
          returnArray.push.apply(returnArray, flatten(input[key]));
        }
      }
    } else {
      returnArray.push(input);
    }
    return returnArray;
  }

  // Now call the function flatten() that we defined earlier.
  return flatten(V);
  ';

select value from table(flatten(flatten_complete(parse_json(
'[
  {"key1" : [1, 2], "key2" : ["string1", "string2"]},
  {"key3" : [{"inner key 1" : 10, "inner key 2" : 11}, 12]}
  ]'))));

-----------+
   VALUE   |
-----------+
 1         |
 2         |
 "string1" |
 "string2" |
 10        |
 11        |
 12        |
-----------+
Copy

JavaScript ์ธ์ž ๋ฐ ๋ฐ˜ํ™˜ ๊ฐ’ยถ

์ธ์ž๋Š” JavaScript ๋‚ด์—์„œ ์ด๋ฆ„์œผ๋กœ ์ง์ ‘ ์ฐธ์กฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ์šฉ๋˜์ง€ ์•Š์€ ์‹๋ณ„์ž๋Š” ๋Œ€๋ฌธ์ž๋กœ ๋œ ๋ณ€์ˆ˜ ์ด๋ฆ„์œผ๋กœ ์ฐธ์กฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ธ์ž ๋ฐ UDF๋Š” JavaScript ๋‚ด์—์„œ ์ฐธ์กฐ๋˜๋ฏ€๋กœ ์œ ํšจํ•œ JavaScript ์‹๋ณ„์ž์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ UDF ๋ฐ ์ธ์ž ์ด๋ฆ„์€ ๋ฌธ์ž ๋˜๋Š” $ ๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๋ฉฐ ํ›„์† ๋ฌธ์ž๋Š” ์˜์ˆซ์ž, $ ๋˜๋Š” _ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ด๋ฆ„์€ JavaScript ์˜ˆ์•ฝ์–ด์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์„ธ ๊ฐ€์ง€ ์˜ˆ๋Š” ์ด๋ฆ„์œผ๋กœ ์ฐธ์กฐ๋˜๋Š” ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” UDF๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

-- Valid UDF.  'N' must be capitalized.
CREATE OR REPLACE FUNCTION add5(n double)
  RETURNS double
  LANGUAGE JAVASCRIPT
  AS 'return N + 5;';

select add5(0.0);

-- Valid UDF. Lowercase argument is double-quoted.
CREATE OR REPLACE FUNCTION add5_quoted("n" double)
  RETURNS double
  LANGUAGE JAVASCRIPT
  AS 'return n + 5;';

select add5_quoted(0.0);

-- Invalid UDF. Error returned at runtime because JavaScript identifier 'n' cannot be resolved.
CREATE OR REPLACE FUNCTION add5_lowercase(n double)
  RETURNS double
  LANGUAGE JAVASCRIPT
  AS 'return n + 5;';

select add5_lowercase(0.0);
Copy

NULL ๋ฐ ์ •์˜๋˜์ง€ ์•Š์€ ๊ฐ’ยถ

JavaScript UDF๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” NULL ๊ฐ’์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ํ–‰ ๋ฐ ๋ณ€์ˆ˜์— ์„ธ์‹ฌํ•œ ์ฃผ์˜๋ฅผ ๊ธฐ์šธ์ด์‹ญ์‹œ์˜ค. ํŠนํžˆ Snowflake์—๋Š” ๋‘ ๊ฐœ์˜ ๊ณ ์œ ํ•œ NULL ๊ฐ’(SQL NULL ๋ฐ ๋ฒ ๋ฆฌ์–ธํŠธ์˜ JSON null)์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๋ฐ˜๋ฉด, JavaScript์—๋Š” null ์™ธ์— undefined ๊ฐ’์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

JavaScript UDF์— ๋Œ€ํ•œ SQL NULL ์ธ์ž๋Š” JavaScript undefined ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๋ฐ˜ํ™˜๋œ JavaScript undefined ๊ฐ’์€ SQL NULL ๋กœ ๋‹ค์‹œ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฒ ๋ฆฌ์–ธํŠธ๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ํƒ€์ž…์— ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค. ๋ฒ ๋ฆฌ์–ธํŠธ ์ด์™ธ ํ˜•์‹์˜ ๊ฒฝ์šฐ, ๋ฐ˜ํ™˜๋œ JavaScript null ๋„ SQL NULL ๊ฐ’์ด ๋ฉ๋‹ˆ๋‹ค.

๋ฒ ๋ฆฌ์–ธํŠธ ํ˜•์‹์˜ ์ธ์ž ๋ฐ ๋ฐ˜ํ™˜๋œ ๊ฐ’์€ JavaScript์˜ undefined ๊ฐ’๊ณผ null ๊ฐ’์„ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค SQL NULL ์€ JavaScript undefined ๋กœ ๊ณ„์† ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค(JavaScript undefined ๋Š” SQL NULL ๋กœ ๋ณ€ํ™˜). ๋ฒ ๋ฆฌ์–ธํŠธ JSON null ์€ JavaScript null ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค(JavaScript null ์€ Variant JSON null ๋กœ ๋‹ค์‹œ ๋ณ€ํ™˜). JavaScript ์˜ค๋ธŒ์ ํŠธ์— ๊ฐ’์œผ๋กœ ํฌํ•จ๋˜๊ฑฐ๋‚˜ ๋ฐฐ์—ด์— ํฌํ•จ๋œ undefined ๊ฐ’์œผ๋กœ ์ธํ•ด ์š”์†Œ๊ฐ€ ์ƒ๋žต๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด๊ณผ ํ•˜๋‚˜์˜ NULL ๊ฐ’์ด ์žˆ๋Š” ํ…Œ์ด๋ธ”์„ ๋งŒ๋“œ์‹ญ์‹œ์˜ค.

create or replace table strings (s string);
insert into strings values (null), ('non-null string');
Copy

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฌธ์ž์—ด์„ NULL ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  NULL ์„ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ์‹ญ์‹œ์˜ค.

CREATE OR REPLACE FUNCTION string_reverse_nulls(s string)
    RETURNS string
    LANGUAGE JAVASCRIPT
    AS '
    if (S === undefined) {
        return "string was null";
    } else
    {
        return undefined;
    }
    ';
Copy

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์‹ญ์‹œ์˜ค.

select string_reverse_nulls(s) 
    from strings
    order by 1;
+-------------------------+
| STRING_REVERSE_NULLS(S) |
|-------------------------|
| string was null         |
| NULL                    |
+-------------------------+
Copy

SQL NULL ์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ๊ณผ ๋ฒ ๋ฆฌ์–ธํŠธ JSON null ์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ ์‚ฌ์ด์˜ ์ฐจ์ด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งŒ๋“œ์‹ญ์‹œ์˜ค.

CREATE OR REPLACE FUNCTION variant_nulls(V VARIANT)
      RETURNS VARCHAR
      LANGUAGE JAVASCRIPT
      AS '
      if (V === undefined) {
        return "input was SQL null";
      } else if (V === null) {
        return "input was variant null";
      } else {
        return V;
      }
      ';
Copy
select null, 
       variant_nulls(cast(null as variant)),
       variant_nulls(PARSE_JSON('null'))
       ;
+------+--------------------------------------+-----------------------------------+
| NULL | VARIANT_NULLS(CAST(NULL AS VARIANT)) | VARIANT_NULLS(PARSE_JSON('NULL')) |
|------+--------------------------------------+-----------------------------------|
| NULL | input was SQL null                   | input was variant null            |
+------+--------------------------------------+-----------------------------------+
Copy

undefined ๋ฐ˜ํ™˜, null ๋ฐ˜ํ™˜, ๊ทธ๋ฆฌ๊ณ  undefined ๋ฐ null ์„ ํฌํ•จํ•˜๋Š” ๋ฒ ๋ฆฌ์–ธํŠธ ๋ฐ˜ํ™˜ ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งŒ๋“œ์‹ญ์‹œ์˜ค(undefined ๊ฐ’์€ ๋ฐ˜ํ™˜๋œ ๋ฒ ๋ฆฌ์–ธํŠธ์—์„œ ์ œ๊ฑฐ๋จ).

CREATE OR REPLACE FUNCTION variant_nulls(V VARIANT)
      RETURNS variant
      LANGUAGE JAVASCRIPT
      AS $$
      if (V == 'return undefined') {
        return undefined;
      } else if (V == 'return null') {
        return null;
      } else if (V == 3) {
        return {
            key1 : undefined,
            key2 : null
            };
      } else {
        return V;
      }
      $$;
Copy
select variant_nulls('return undefined'::VARIANT) AS "RETURNED UNDEFINED",
       variant_nulls('return null'::VARIANT) AS "RETURNED NULL",
       variant_nulls(3) AS "RETURNED VARIANT WITH UNDEFINED AND NULL; NOTE THAT UNDEFINED WAS REMOVED";
+--------------------+---------------+---------------------------------------------------------------------------+
| RETURNED UNDEFINED | RETURNED NULL | RETURNED VARIANT WITH UNDEFINED AND NULL; NOTE THAT UNDEFINED WAS REMOVED |
|--------------------+---------------+---------------------------------------------------------------------------|
| NULL               | null          | {                                                                         |
|                    |               |   "key2": null                                                            |
|                    |               | }                                                                         |
+--------------------+---------------+---------------------------------------------------------------------------+
Copy

JavaScript ๋‚ด ํ˜•์‹ ๋ณ€ํ™˜ยถ

JavaScript๋Š” ๋‹ค์–‘ํ•œ ํ˜•์‹ ๊ฐ„์— ๊ฐ’์„ ์•”์‹œ์ ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์ด ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒฝ์šฐ, ๊ฐ’์€ SQL ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜๋˜๊ธฐ ์ „์— ์š”์ฒญ๋œ ๋ฐ˜ํ™˜ ํ˜•์‹์œผ๋กœ ๋จผ์ € ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ˆซ์ž๊ฐ€ ๋ฐ˜ํ™˜๋˜์—ˆ์ง€๋งŒ, UDF๊ฐ€ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์„ ์–ธ๋œ ๊ฒฝ์šฐ, ์ด ์ˆซ์ž๋Š” JavaScript ๋‚ด์—์„œ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ํ˜•์‹์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ JavaScript ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์˜ค๋ฅ˜๋Š” ์ด ๋™์ž‘์œผ๋กœ ์ธํ•ด ์ˆจ๊ฒจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ๊ฐ’์˜ ํ˜•์‹์„ ๋ณ€ํ™˜ํ•˜๋Š” ๋™์•ˆ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜ํƒ€๋‚˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

JavaScript ์ˆซ์ž ๋ฒ”์œ„ยถ

์ •๋ฐ€๋„๊ฐ€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋˜๋Š” ์ˆซ์ž์˜ ๋ฒ”์œ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

-(2^53 -1)

~

(2^53 -1)

Snowflake NUMBER(p, s) ๋ฐ DOUBLE ๋ฐ์ดํ„ฐ ํƒ€์ž…์˜ ์œ ํšจํ•œ ๊ฐ’ ๋ฒ”์œ„๊ฐ€ ๋” ํฝ๋‹ˆ๋‹ค. Snowflake์—์„œ ๊ฐ’์„ ๊ฒ€์ƒ‰ํ•˜์—ฌ JavaScript ์ˆซ์ž ๋ณ€์ˆ˜์— ์ €์žฅํ•˜๋ฉด ์ •๋ฐ€๋„๊ฐ€ ์†์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ:

CREATE OR REPLACE FUNCTION num_test(a double)
  RETURNS string
  LANGUAGE JAVASCRIPT
AS
$$
  return A;
$$
;
Copy
select hash(1) AS a, 
       num_test(hash(1)) AS b, 
       a - b;
+----------------------+----------------------+------------+
|                    A | B                    |      A - B |
|----------------------+----------------------+------------|
| -4730168494964875235 | -4730168494964875000 | -235.00000 |
+----------------------+----------------------+------------+
Copy

์ฒ˜์Œ ๋‘ ์—ด์€ ์ผ์น˜ํ•ด์•ผ ํ•˜๊ณ  ์„ธ ๋ฒˆ์งธ ์—ด์€ 0.0์„ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” JavaScript ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜(UDF) ๋ฐ ์ €์žฅ ํ”„๋กœ์‹œ์ €์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

getColumnValue() ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ €์žฅ ํ”„๋กœ์‹œ์ €์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ, ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ์„ ํ†ตํ•ด ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ๊ฒ€์ƒ‰ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

getColumnValueAsString()
Copy

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ €์žฅ ํ”„๋กœ์‹œ์ €์—์„œ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋ฌธ์ž์—ด์„ SQL์˜ ์ˆซ์ž ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ์บ์ŠคํŒ…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

JavaScript ์˜ค๋ฅ˜ยถ

JavaScript๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋™์•ˆ ๋ฐœ์ƒํ•œ ๋ชจ๋“  ์˜ค๋ฅ˜๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ SQL ์˜ค๋ฅ˜๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๊ตฌ๋ฌธ ๋ถ„์„ ์˜ค๋ฅ˜, ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜, UDF ๋‚ด์—์„œ ๋ฐœ์ƒํ•œ ํฌ์ฐฉ๋˜์ง€ ์•Š์€ ์˜ค๋ฅ˜๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์˜ค๋ฅ˜์— ์Šคํƒ ์ถ”์ ์ด ํฌํ•จ๋œ ๊ฒฝ์šฐ, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์ฟผ๋ฆฌ๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  SQL ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์˜ค๋ฅ˜๋ฅผ ํฌ์ฐฉํ•˜์ง€ ์•Š๊ณ  ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์€ ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋””๋ฒ„๊น…ํ•  ๋•Œ SQL ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ…์ŠคํŠธ์— ๋‚˜ํƒ€๋‚˜๋„๋ก ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์ธ์ž ๊ฐ’์„ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์ด ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ์ •์  UDF์˜ ๊ฒฝ์šฐ, ์ด๋Š” ๋กœ์ปฌ JavaScript ์—”์ง„์—์„œ ์˜ค๋ฅ˜๋ฅผ ์žฌํ˜„ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์€ ์ „์ฒด JavaScript UDF ๋ณธ๋ฌธ์„ try-catch ๋ธ”๋ก์— ๋ฐฐ์น˜ํ•˜๊ณ , ํฌ์ฐฉ๋œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ์ธ์ž ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๊ณ , ํ™•์žฅ๋œ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์— UDF๋ฅผ ๋ฐฐ์น˜ํ•˜๊ธฐ ์ „์— ์ด๋Ÿฌํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ๊ฐ’์„ ๊ธฐ๋กํ•  ๊ฒฝ์šฐ, ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜๋„์น˜ ์•Š๊ฒŒ ๋“œ๋Ÿฌ๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋Š” ๋ฏธ๋ฆฌ ์ •์˜๋œ ์˜ˆ์™ธ ๋˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ • ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ํฌ์ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ๊ฐ€ ์—ฌ๊ธฐ ์— ์žˆ์Šต๋‹ˆ๋‹ค.

JavaScript UDF ๋ฌธ์ œ ํ•ด๊ฒฐ ๋„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

JavaScript UDF ๋ณด์•ˆยถ

JavaScript UDF๋Š” ์—ฌ๋Ÿฌ ๊ณ„์ธต์˜ ์ฟผ๋ฆฌ ๋ฐ ๋ฐ์ดํ„ฐ ๊ฒฉ๋ฆฌ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์•ˆ์ „๊ณผ ๋ณด์•ˆ์„ ๊ฐ–์ถ”๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • JavaScript UDF๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฐ€์ƒ ์›จ์–ดํ•˜์šฐ์Šค ๋‚ด์˜ ์ปดํ“จํŒ… ๋ฆฌ์†Œ์Šค๋Š” ์‚ฌ์šฉ์ž ๊ณ„์ • ๋‚ด์—์„œ๋งŒ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ฆ‰, ์›จ์–ดํ•˜์šฐ์Šค๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ๋‹ค๋ฅธ Snowflake ๊ณ„์ •๊ณผ ๊ณต์œ ํ•˜์ง€ ์•Š์Œ).

  • ๋ฌด๋‹จ ์•ก์„ธ์Šค๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ๋Š” ๊ฐ€์ƒ ์›จ์–ดํ•˜์šฐ์Šค ๋‚ด์—์„œ ์•”ํ˜ธํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • JavaScript ์ฝ”๋“œ๋Š” ์ œํ•œ๋œ ์—”์ง„ ๋‚ด์—์„œ ์‹คํ–‰๋˜์–ด JavaScript ์ปจํ…์ŠคํŠธ์—์„œ ์‹œ์Šคํ…œ ํ˜ธ์ถœ์„ ๋ฐฉ์ง€ํ•˜๊ณ (์˜ˆ: ๋„คํŠธ์›Œํฌ ๋ฐ ๋””์Šคํฌ ์•ก์„ธ์Šค ์—†์Œ) ์—”์ง„, ํŠนํžˆ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ, JavaScript UDF๋Š” ์ •์˜๋œ ํ•จ์ˆ˜๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ์—๋งŒ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ•ฉ๋ฆฌ์ ์ธ ์–‘์˜ ๋ฉ”๋ชจ๋ฆฌ์™€ ํ”„๋กœ์„ธ์„œ ์‹œ๊ฐ„์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ๊ธฐ๋ณธ ์‹œ์Šคํ…œ์˜ ์ƒํƒœ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.