Java UDF ์„ค๊ณ„ยถ

์ด ํ•ญ๋ชฉ์€ Java UDF๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

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

๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒํ•˜๊ธฐยถ

์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „์—:

  • ํ•จ์ˆ˜๊ฐ€ ์ธ์ž๋กœ ์ˆ˜๋ฝํ•ด์•ผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…, ๊ทธ๋ฆฌ๊ณ  ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์„ ํƒํ•˜์‹ญ์‹œ์˜ค.

  • ํƒ€์ž„์กด ๊ด€๋ จ ๋ฌธ์ œ๋ฅผ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

  • NULL ๊ฐ’์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•˜์‹ญ์‹œ์˜ค.

๋งค๊ฐœ ๋ณ€์ˆ˜ ๋ฐ ๋ฐ˜ํ™˜ ํ˜•์‹์— ๋Œ€ํ•œ SQL-Java ๋ฐ์ดํ„ฐ ํƒ€์ž… ๋งคํ•‘ยถ

Snowflake๊ฐ€ Java์™€ SQL ๋ฐ์ดํ„ฐ ํƒ€์ž… ๊ฐ„์— ์ „ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ SQL ๋ฐ ์ฒ˜๋ฆฌ๊ธฐ ์–ธ์–ด ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž… ๋งคํ•‘ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

TIMESTAMP_LTZ ๊ฐ’ ๋ฐ ํƒ€์ž„์กดยถ

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

NULL ๊ฐ’ยถ

Snowflake๋Š” ๋‘ ๊ฐ€์ง€ ๊ณ ์œ ํ•œ NULL ๊ฐ’์„ ์ง€์›ํ•˜๋Š”๋ฐ, ์ด๋Š” SQL NULL ๊ณผ VARIANT์˜ JSON null ์ž…๋‹ˆ๋‹ค. (Snowflake VARIANT NULL์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ NULL ๊ฐ’ ์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.)

Java๋Š” ๊ธฐ๋ณธ์ด ์•„๋‹Œ ๋ฐ์ดํ„ฐ ํƒ€์ž…์—๋งŒ ํ•ด๋‹นํ•˜๋Š” ํ•˜๋‚˜์˜ null ๊ฐ’์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

Java UDF์— ๋Œ€ํ•œ SQL NULL ์ธ์ž๋Š” Java null ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜๋˜์ง€๋งŒ, null ์„ ์ง€์›ํ•˜๋Š” Java ๋ฐ์ดํ„ฐ ํƒ€์ž…์—๋งŒ ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๋œ Java null ๊ฐ’์€ SQL NULL ๋กœ ๋‹ค์‹œ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

๋ฐฐ์—ด๊ณผ ๊ฐ€๋ณ€ ๊ฐœ์ˆ˜์˜ ์ธ์žยถ

Java UDF๋Š” ๋‹ค์Œ Java ๋ฐ์ดํ„ฐ ํƒ€์ž…์˜ ๋ฐฐ์—ด์„ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • String

  • boolean

  • double

  • float

  • int

  • long

  • short

์ „๋‹ฌ๋œ SQL ๊ฐ’์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์€ ํ•ด๋‹น Java ๋ฐ์ดํ„ฐ ํƒ€์ž…๊ณผ ํ˜ธํ™˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ํƒ€์ž… ํ˜ธํ™˜์„ฑ์— ๋Œ€ํ•œ SQL-Java ๋ฐ์ดํ„ฐ ํƒ€์ž… ๋งคํ•‘ ์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ง€์ •๋œ ๊ฐ Java ๋ฐ์ดํ„ฐ ํƒ€์ž…์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ๊ทœ์น™์ด ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • boolean: Snowflake ARRAY๋Š” BOOLEAN ์š”์†Œ๋งŒ ํฌํ•จํ•ด์•ผ ํ•˜๋ฉฐ NULL ๊ฐ’์„ ํฌํ•จํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

  • int/short/long: Snowflake ARRAY๋Š” ์Šค์ผ€์ผ์ด 0์ธ ๊ณ ์ • ์†Œ์ˆ˜์  ์š”์†Œ๋งŒ ํฌํ•จํ•ด์•ผ ํ•˜๋ฉฐ NULL ๊ฐ’์„ ํฌํ•จํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

  • float/double: Snowflake ARRAY๋Š” ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ARRAY๋Š” NULL ๊ฐ’์„ ํฌํ•จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Java ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ ์ด๋Ÿฌํ•œ ๋ฐฐ์—ด์„ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Java์˜ ๋ฐฐ์—ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • Java์˜ varargs (๊ฐ€๋ณ€ ์ธ์ž ์ˆ˜) ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ SQL ์ฝ”๋“œ๋Š” ARRAY ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ARRAY๋ฅผ ํ†ตํ•ด ์ „๋‹ฌยถ

Java ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ๋ฐฐ์—ด๋กœ ์„ ์–ธํ•˜์‹ญ์‹œ์˜ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ ๋ฉ”์„œ๋“œ์˜ ์„ธ ๋ฒˆ์งธ ๋งค๊ฐœ ๋ณ€์ˆ˜๋Š” ๋ฌธ์ž์—ด ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค.

static int myMethod(int fixedArgument1, int fixedArgument2, String[] stringArray)
Copy

๋‹ค์Œ์€ ์™„์ „ํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค๊ณ  ๋กœ๋”ฉํ•ฉ๋‹ˆ๋‹ค.

CREATE TABLE string_array_table(id INTEGER, a ARRAY);
INSERT INTO string_array_table (id, a) SELECT
        1, ARRAY_CONSTRUCT('Hello');
INSERT INTO string_array_table (id, a) SELECT
        2, ARRAY_CONSTRUCT('Hello', 'Jay');
INSERT INTO string_array_table (id, a) SELECT
        3, ARRAY_CONSTRUCT('Hello', 'Jay', 'Smith');
Copy

UDF๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

CREATE OR REPLACE FUNCTION concat_varchar_2(a ARRAY)
  RETURNS VARCHAR
  LANGUAGE JAVA
  HANDLER = 'TestFunc_2.concatVarchar2'
  TARGET_PATH = '@~/TestFunc_2.jar'
  AS
  $$
  class TestFunc_2 {
      public static String concatVarchar2(String[] strings) {
          return String.join(" ", strings);
      }
  }
  $$;
Copy

UDF๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

SELECT concat_varchar_2(a)
  FROM string_array_table
  ORDER BY id;
+---------------------+
| CONCAT_VARCHAR_2(A) |
|---------------------|
| Hello               |
| Hello Jay           |
| Hello Jay Smith     |
+---------------------+
Copy

Varargs๋ฅผ ํ†ตํ•ด ์ „๋‹ฌํ•˜๊ธฐยถ

varargs๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

Java ์ฝ”๋“œ์—์„œ Java์˜ varargs ์„ ์–ธ ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

static int myMethod(int fixedArgument1, int fixedArgument2, String ... stringArray)
Copy

๋‹ค์Œ์€ ์™„์ „ํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค. ์ด ์˜ˆ์™€ ์ด์ „ ์˜ˆ(๋ฐฐ์—ด์˜ ๊ฒฝ์šฐ) ๊ฐ„์˜ ์œ ์ผํ•œ ์ค‘์š”ํ•œ ์ฐจ์ด์ ์€ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ๋งค๊ฐœ ๋ณ€์ˆ˜ ์„ ์–ธ์ž…๋‹ˆ๋‹ค.

ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค๊ณ  ๋กœ๋”ฉํ•ฉ๋‹ˆ๋‹ค.

CREATE TABLE string_array_table(id INTEGER, a ARRAY);
INSERT INTO string_array_table (id, a) SELECT
        1, ARRAY_CONSTRUCT('Hello');
INSERT INTO string_array_table (id, a) SELECT
        2, ARRAY_CONSTRUCT('Hello', 'Jay');
INSERT INTO string_array_table (id, a) SELECT
        3, ARRAY_CONSTRUCT('Hello', 'Jay', 'Smith');
Copy

UDF๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

CREATE OR REPLACE FUNCTION concat_varchar(a ARRAY)
  RETURNS VARCHAR
  LANGUAGE JAVA
  HANDLER = 'TestFunc.concatVarchar'
  TARGET_PATH = '@~/TestFunc.jar'
  AS
  $$
  class TestFunc {
      public static String concatVarchar(String ... stringArray) {
          return String.join(" ", stringArray);
      }
  }
  $$;
Copy

UDF๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

SELECT concat_varchar(a)
    FROM string_array_table
    ORDER BY id;
+-------------------+
| CONCAT_VARCHAR(A) |
|-------------------|
| Hello             |
| Hello Jay         |
| Hello Jay Smith   |
+-------------------+
Copy

Snowflake์—์„œ ๋ถ€๊ณผํ•œ ์ œ์•ฝ ์กฐ๊ฑด ๋‚ด์—์„œ ์œ ์ง€๋˜๋Š” Java UDFs ์„ค๊ณ„ํ•˜๊ธฐยถ

Snowflake์—์„œ ์ž˜ ์‹คํ–‰๋˜๋Š” ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ ์„ค๊ณ„์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ Snowflake์—์„œ ์ ์šฉํ•œ ์ œ์•ฝ ์กฐ๊ฑด ๋‚ด์—์„œ ์œ ์ง€๋˜๋Š” ์ฒ˜๋ฆฌ๊ธฐ ์„ค๊ณ„ํ•˜๊ธฐ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

ํด๋ž˜์Šค ์„ค๊ณ„ํ•˜๊ธฐยถ

SQL ๋ฌธ์ด Java UDF๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด Snowflake๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž‘์„ฑํ•œ Java ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. Java ๋ฉ”์„œ๋“œ๋ฅผ โ€œํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œโ€ ๋˜๋Š” ์ค„์—ฌ์„œ โ€œํ•ธ๋“ค๋Ÿฌโ€๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  Java ๋ฉ”์„œ๋“œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฉ”์„œ๋“œ๋Š” ํด๋ž˜์Šค์˜ ์ผ๋ถ€๋กœ ์„ ์–ธ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๋Š” ํด๋ž˜์Šค์˜ ์ •์  ๋ฉ”์„œ๋“œ ๋˜๋Š” ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์ด๊ณ  ํด๋ž˜์Šค๊ฐ€ ์ธ์ž๊ฐ€ ์—†๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒฝ์šฐ, Snowflake๋Š” ์ดˆ๊ธฐํ™” ์‹œ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ •์  ๋ฉ”์„œ๋“œ์ธ ๊ฒฝ์šฐ, ํด๋ž˜์Šค์—๋Š” ์ƒ์„ฑ์ž๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•ธ๋“ค๋Ÿฌ๋Š” Java UDF์— ์ „๋‹ฌ๋œ ๊ฐ ํ–‰์— ๋Œ€ํ•ด ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. (์ฐธ๊ณ : ํด๋ž˜์Šค์˜ ์ƒˆ ์ธ์Šคํ„ด์Šค๋Š” ๊ฐ ํ–‰์— ๋Œ€ํ•ด ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Snowflake๋Š” ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์˜ ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ๋‘ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ๋™์ผํ•œ ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ๋‘ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

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

ํด๋ž˜์Šค ์„ค๊ณ„์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋Š” Java UDF ์ฒ˜๋ฆฌ๊ธฐ ์ƒ์„ฑํ•˜๊ธฐ ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์Šค์นผ๋ผ UDFs์—์„œ ์ดˆ๊ธฐํ™” ์ตœ์ ํ™”ํ•˜๊ธฐ ๋ฐ ์ „์—ญ ์ƒํƒœ ์ œ์–ดํ•˜๊ธฐยถ

๋Œ€๋ถ€๋ถ„์˜ ํ•จ์ˆ˜ ๋ฐ ํ”„๋กœ์‹œ์ € ์ฒ˜๋ฆฌ๊ธฐ๋Š” ์•„๋ž˜ ์ง€์นจ์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ํ–‰ ๊ฐ„์— ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๊ณต์œ  ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ๊ธฐ ํ•จ์ˆ˜ ์™ธ๋ถ€์—์„œ(์˜ˆ: ๋ชจ๋“ˆ์ด๋‚˜ ์ƒ์„ฑ์ž์—์„œ) ์ดˆ๊ธฐํ™”ํ•˜์‹ญ์‹œ์˜ค.

  • ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•˜๋„๋ก ์ฒ˜๋ฆฌ๊ธฐ ํ•จ์ˆ˜ ๋˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜์‹ญ์‹œ์˜ค.

  • ํ–‰ ๊ฐ„์— ๋™์  ์ƒํƒœ๋ฅผ ์ €์žฅ ๋ฐ ๊ณต์œ ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

UDF๊ฐ€ ์ด๋Ÿฌํ•œ ์ง€์นจ์„ ๋”ฐ๋ฅผ ์ˆ˜ ์—†๊ฑฐ๋‚˜ ์ด๋Ÿฌํ•œ ์ง€์นจ์˜ ์ด์œ ๋ฅผ ๋” ๊นŠ์ด ์ดํ•ดํ•˜๋ ค๋Š” ๊ฒฝ์šฐ, ๋‹ค์Œ ๋ช‡ ๊ฐ€์ง€ ํ•˜์œ„ ์„น์…˜์„ ์ฝ์œผ์‹ญ์‹œ์˜ค.

ํ˜ธ์ถœ ๊ฐ„ ์ƒํƒœ ๊ณต์œ ํ•˜๊ธฐยถ

Snowflake๋Š” ์Šค์นผ๋ผ UDF๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœ ๊ฐ„์— ๊ณต์œ ๋˜๋Š” ์ƒํƒœ์— ์˜์กดํ•˜๋ฉด ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์‹œ์Šคํ…œ์—์„œ ํ–‰์„ ์ž„์˜์˜ ์ˆœ์„œ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์—ฌ๋Ÿฌ JVM(Java ๋˜๋Š” Scala๋กœ ์ž‘์„ฑ๋œ ์ฒ˜๋ฆฌ๊ธฐ์˜ ๊ฒฝ์šฐ) ๋˜๋Š” ์ธ์Šคํ„ด์Šค(Python์œผ๋กœ ์ž‘์„ฑ๋œ ์ฒ˜๋ฆฌ๊ธฐ์˜ ๊ฒฝ์šฐ)์— ๊ฑธ์ณ ์ด๋Ÿฌํ•œ ํ˜ธ์ถœ์„ ๋ถ„์‚ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

UDF๋Š” ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ํ˜ธ์ถœ์—์„œ ๊ณต์œ  ์ƒํƒœ์— ์˜์กดํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ UDF์—์„œ ๊ณต์œ  ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๋ ค ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฐ ํ–‰์— ๋Œ€ํ•ด ๋ฐ˜๋ณตํ•˜๊ณ  ์‹ถ์ง€ ์•Š์€, ๋ถ€๋‹ด์ด ํฐ ์ดˆ๊ธฐํ™” ๋…ผ๋ฆฌ๊ฐ€ ํฌํ•จ๋œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

  • ์บ์‹œ์™€ ๊ฐ™์ด ํ–‰ ๊ฐ„์— ๊ณต์œ  ์ƒํƒœ๋ฅผ ํ™œ์šฉํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ํ–‰์—์„œ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•˜๊ณ  ํ•ด๋‹น ์ƒํƒœ๊ฐ€ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์Šคํ„ด์Šค ์ˆ˜์ค€ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ด ๊ณต์œ  ์ƒํƒœ๋ฅผ ๋งŒ๋“œ์‹ญ์‹œ์˜ค. ์ƒ์„ฑ์ž๋Š” ์ธ์Šคํ„ด์Šค๋‹น ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋Š” ๋ฐ˜๋ฉด ํ•ธ๋“ค๋Ÿฌ๋Š” ํ–‰๋‹น ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋˜๋ฏ€๋กœ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์—ฌ๋Ÿฌ ํ–‰์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ƒ์„ฑ์ž์—์„œ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์ด ๋ถ€๋‹ด์ด ๋” ์ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ƒ์„ฑ์ž๋Š” ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ์ž๋Š” ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•˜๋„๋ก ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ๋˜๋Š” ๊ณต์œ  ์ƒํƒœ๋ฅผ UDF๊ฐ€ ์ €์žฅํ•˜๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ์ƒํƒœ์— ๋Œ€ํ•œ ๋™์‹œ ์•ก์„ธ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ค€๋น„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋‘ ์„น์…˜์—์„œ๋Š” ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๋ฐ ๊ณต์œ  ์ƒํƒœ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Java UDF ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ์ดํ•ดํ•˜๊ธฐยถ

์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด Snowflake๋Š” JVM ์ „์ฒด์— ๊ฑธ์ณ, ๊ทธ๋ฆฌ๊ณ  JVM ๋‚ด์—์„œ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.

  • JVM ์ „์ฒด์— ๊ฑธ์ณ:

    Snowflake๋Š” ์›จ์–ดํ•˜์šฐ์Šค ์˜ ์ž‘์—…์ž ์ „์ฒด์— ๊ฑธ์ณ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ์ž‘์—…์ž๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ JVM์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ „์—ญ ๊ณต์œ  ์ƒํƒœ๊ฐ€ ์—†์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๊ปํ•ด์•ผ ๋‹จ์ผ JVM ๋‚ด์—์„œ๋งŒ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • JVM ๋‚ด์—์„œ:

    • ๊ฐ JVM์€ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์˜ ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ‘๋ ฌ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๊ฐ€ ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•ด์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

    • UDF๊ฐ€ IMMUTABLE์ด๊ณ  SQL ๋ฌธ์ด ๋™์ผ ํ–‰์— ๋Œ€ํ•ด ๋™์ผ ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ UDF๋ฅผ ๋‘ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ, UDF๋Š” ํ•ด๋‹น ํ–‰์˜ ๊ฐ ํ˜ธ์ถœ์— ๋Œ€ํ•ด ๋™์ผ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, UDF๊ฐ€ IMMUTABLE์ธ ๊ฒฝ์šฐ ๋‹ค์Œ์€ ๊ฐ ํ–‰์— ๋Œ€ํ•ด ๋™์ผ ๊ฐ’์„ ๋‘ ๋ฒˆ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

      SELECT
          my_java_udf(42),
          my_java_udf(42)
        FROM table1;
      
      Copy

      ๋™์ผ ์ธ์ž๊ฐ€ ์ „๋‹ฌ๋œ ๊ฒฝ์šฐ์—๋„ ์—ฌ๋Ÿฌ ํ˜ธ์ถœ์ด ๋…๋ฆฝ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ํ•จ์ˆ˜ VOLATILE์„ ์„ ์–ธํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ์—ฌ๋Ÿฌ ๊ฐœ๋ณ„ UDF๋ฅผ ๋™์ผ ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ์— ๋ฐ”์ธ๋”ฉํ•˜์‹ญ์‹œ์˜ค. ์˜ˆ:

      1. ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ @java_udf_stage/rand.jar ์ด๋ผ๋Š” JAR ํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

        class MyClass {
        
          private double x;
        
          // Constructor
          public MyClass()  {
            x = Math.random();
          }
        
          // Handler
          public double myHandler() {
            return x;
          }
        }
        
        Copy
      2. ์•„๋ž˜์™€ ๊ฐ™์ด Java UDF๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ UDF๋Š” ์ด๋ฆ„์ด ๋‹ค๋ฅด์ง€๋งŒ, ๋™์ผ JAR ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ํ•ด๋‹น JAR ํŒŒ์ผ ๋‚ด์—์„œ ๋™์ผ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

        CREATE FUNCTION my_java_udf_1()
          RETURNS DOUBLE
          LANGUAGE JAVA
          IMPORTS = ('@java_udf_stage/rand.jar')
          HANDLER = 'MyClass.myHandler';
        
        CREATE FUNCTION my_java_udf_2()
          RETURNS DOUBLE
          LANGUAGE JAVA
          IMPORTS = ('@java_udf_stage/rand.jar')
          HANDLER = 'MyClass.myHandler';
        
        Copy
      3. ๋‹ค์Œ ์ฝ”๋“œ๋Š” ๋‘ UDF๋ฅผ ๋ชจ๋‘ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. UDF๋Š” ๋™์ผํ•œ JAR ํŒŒ์ผ ๋ฐ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ˜ธ์ถœ์€ ๋™์ผํ•œ ํด๋ž˜์Šค์˜ ๋‘ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ฐ ์ธ์Šคํ„ด์Šค๋Š” ๋…๋ฆฝ์ ์ธ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์•„๋ž˜ ์˜ˆ์—์„œ๋Š” ๋™์ผ ๊ฐ’์„ ๋‘ ๋ฒˆ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋Œ€์‹  ๋‘ ๊ฐœ์˜ ๋…๋ฆฝ์ ์ธ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

        SELECT
            my_java_udf_1(),
            my_java_udf_2()
          FROM table1;
        
        Copy

JVM ์ƒํƒœ ์ •๋ณด ์ €์žฅํ•˜๊ธฐยถ

๋™์  ๊ณต์œ  ์ƒํƒœ์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ํ•œ ๊ฐ€์ง€ ์ด์œ ๋Š” ํ–‰์ด ๋ฐ˜๋“œ์‹œ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์ˆœ์„œ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. SQL ๋ฌธ์ด ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค Snowflake๋Š” ๋ฐฐ์น˜ ์ˆ˜, ๋ฐฐ์น˜๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋Š” ์ˆœ์„œ, ๋ฐฐ์น˜ ๋‚ด์˜ ํ–‰ ์ˆœ์„œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ํ–‰์ด ํ›„์† ํ–‰์˜ ๋ฐ˜ํ™˜ ๊ฐ’์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋„๋ก ์Šค์นผ๋ผ UDF๊ฐ€ ์„ค๊ณ„๋œ ๊ฒฝ์šฐ, UDF๋Š” UDF๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋ฅ˜ ์ฒ˜๋ฆฌยถ

UDF๋กœ ์‚ฌ์šฉ๋˜๋Š” Java ๋ฉ”์„œ๋“œ๋Š” ์ผ๋ฐ˜ Java ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์˜ค๋ฅ˜๋ฅผ ํฌ์ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์ด ์˜ˆ์™ธ๊ฐ€ ๋ฉ”์„œ๋“œ์—์„œ ํฌ์ฐฉ๋˜์ง€ ์•Š์œผ๋ฉด Snowflake๋Š” ์˜ˆ์™ธ์— ๋Œ€ํ•œ ์Šคํƒ ์ถ”์ ์„ ํฌํ•จํ•˜๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์˜ˆ์™ธ ๋กœ๊น… ์ด ํ™œ์„ฑํ™”๋˜๋ฉด Snowflake๋Š” ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”์— ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์˜ˆ์™ธ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

์ฟผ๋ฆฌ๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  SQL ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์™ธ๋ฅผ ํฌ์ฐฉํ•˜์ง€ ์•Š๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ:

if (x < 0) {
  throw new IllegalArgumentException("x must be non-negative.");
}
Copy

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

๋ชจ๋ฒ” ์‚ฌ๋ก€ ๋”ฐ๋ฅด๊ธฐยถ

  • ํ”Œ๋žซํผ ๋…๋ฆฝ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์‹ญ์‹œ์˜ค.

    • ํŠน์ • CPU ์•„ํ‚คํ…์ฒ˜(์˜ˆ: x86)๋ฅผ ๊ฐ€์ •ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ํ”ผํ•˜์‹ญ์‹œ์˜ค.

    • ํŠน์ • ์šด์˜ ์ฒด์ œ๋ฅผ ๊ฐ€์ •ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ํ”ผํ•˜์‹ญ์‹œ์˜ค.

  • ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•˜์ง€๋งŒ, ํ˜ธ์ถœํ•˜๋Š” ๋ฉ”์„œ๋“œ์— ์ด๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ์ •์  ์ดˆ๊ธฐํ™” ๋ธ”๋ก์— ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ธ๋ผ์ธ ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ€๋Šฅํ•˜๋ฉด CREATE FUNCTION ๋˜๋Š” CREATE PROCEDURE TARGET_PATH ๋งค๊ฐœ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ง€์ •ํ•˜์‹ญ์‹œ์˜ค. ๊ทธ๋Ÿฌ๋ฉด ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ์ปดํŒŒ์ผํ•˜๋Š” ๋Œ€์‹  ์ด์ „์— ์ƒ์„ฑ๋œ ์ฒ˜๋ฆฌ๊ธฐ ์ฝ”๋“œ ์ถœ๋ ฅ์„ ์žฌ์‚ฌ์šฉํ•˜๋„๋ก Snowflake์— ์•Œ๋ ค์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ธ๋ผ์ธ ์ฒ˜๋ฆฌ๊ธฐ ์‚ฌ์šฉํ•˜๊ธฐ ์„น์…˜์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์ฐธ๊ณ  ํ•ญ๋ชฉ:

์šฐ์ˆ˜ํ•œ ๋ณด์•ˆ ๊ด€ํ–‰ ๋”ฐ๋ฅด๊ธฐยถ

์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ์•ˆ์ „ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•˜๋„๋ก ๋ณด์žฅํ•˜๋ ค๋ฉด UDF ๋ฐ ํ”„๋กœ์‹œ์ €์˜ ๋ณด์•ˆ ๋ชจ๋ฒ” ์‚ฌ๋ก€ ์— ์„ค๋ช…๋œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.