Slide 1

Slide 1 text

Frédéric Descamps Community Manager Oracle MySQL MySQL Tech Tour Italia - O obre 2024 MySQL and GraalVM Support for JavaScript Functions and Stored Procedures in MySQL Enterprise Edition

Slide 2

Slide 2 text

Who am I ? about.me/lefred Copyright @ 2024 Oracle and/or its affiliates. | 2

Slide 3

Slide 3 text

@lefred MySQL Evangelist using MySQL since version 3.20 devops believer living in h ps://lefred.be Frédéric Descamps Copyright @ 2024 Oracle and/or its affiliates. 3

Slide 4

Slide 4 text

GraalVM & Polyglot What is GraalVM ? Copyright @ 2024 Oracle and/or its affiliates. 4

Slide 5

Slide 5 text

GraalVM is a high-performance, polyglot virtual machine Supports multiple languages: JavaScript, Python, Ruby, R and more Enhances performance and enables interoperability between languages What is GraalVM? Copyright @ 2024 Oracle and/or its affiliates. 5

Slide 6

Slide 6 text

GraalVM allows us to execute multiple programming languages e ciently on a single runtime. In database contexts, it allows to expand the scope of how we can execute logic beyond SQL. What is GraalVM? (2) Copyright @ 2024 Oracle and/or its affiliates. 6

Slide 7

Slide 7 text

GraalVM allows us to execute multiple programming languages e ciently on a single runtime. In database contexts, it allows to expand the scope of how we can execute logic beyond SQL. For MySQL Enterprise, GraalVM's integration allows JavaScript to be executed natively, o ering developers exibility in de ning stored procedures. What is GraalVM? (2) Copyright @ 2024 Oracle and/or its affiliates. 7

Slide 8

Slide 8 text

Why JavaScript? JavaScript is the rst external language supported in MySQL, why ? Copyright @ 2024 Oracle and/or its affiliates. 8

Slide 9

Slide 9 text

most used languages by developers more than 98% of all web pages use JavaScript it has a huge development eco-system Why JavaScript? JavaScript is the rst external language supported in MySQL, why ? Copyright @ 2024 Oracle and/or its affiliates. 8

Slide 10

Slide 10 text

Why GraalVM in MySQL Enterprise? Copyright @ 2024 Oracle and/or its affiliates. 9

Slide 11

Slide 11 text

Why GraalVM in MySQL Enterprise? Native support for JavaScript as a stored procedure language Enables more complex logic directly in the database Enhanced performance over traditional interpreted approaches No need to retrieve sensitive data from the database for processing Polyglot capabilities (use other languages inside MySQL) traditional MySQL stored procedures language is very limited faster JavaScript execution Copyright @ 2024 Oracle and/or its affiliates. 10

Slide 12

Slide 12 text

validate data process and format JSON & strings operate Data Cleansing / Transformation Why GraalVM in MySQL Enterprise? (2) JavaScript can be used inside MySQL to By processing directly within the server developers can minimize data movement between server and clients, improving performance and reducing network overhead, reducing latency within applications, and improving data security. Copyright @ 2024 Oracle and/or its affiliates. 11

Slide 13

Slide 13 text

Let's start MySQL EE & MLE / ɛm ɛl i/ Copyright @ 2024 Oracle and/or its affiliates. 12

Slide 14

Slide 14 text

Starting with MySQL EE & MLE If you are a MySQL customer, you get JavaScript support since MySQL 9.0. As a developer, you can get free access to MySQL Enterprise from Oracle Technology Network (OTN): h ps://www.oracle.com/mysql/technologies/mysql-enterprise-edition- downloads.html Copyright @ 2024 Oracle and/or its affiliates. 13

Slide 15

Slide 15 text

Starting with MySQL EE & MLE If you are a MySQL customer, you get JavaScript support since MySQL 9.0. As a developer, you can get free access to MySQL Enterprise from Oracle Technology Network (OTN): h ps://www.oracle.com/mysql/technologies/mysql-enterprise-edition- downloads.html To use JavaScript in MySQL, we use the Multilingual Engine Component (MLE). MLE is composed of two les: libpolyglot.so (161M on OL8 x64) component_mle.so (+/- 556K) Copyright @ 2024 Oracle and/or its affiliates. 13

Slide 16

Slide 16 text

Loading MLE We need to load the component if not yet loaded: SQL SQL > > install component install component 'file://component_mle' 'file://component_mle'; ; Query OK Query OK, , 0 0 rows rows affected affected ( (0.0928 0.0928 sec sec) ) SQL SQL > > select select * * from from mysql mysql. .component component where where component_urn component_urn like like '%mle' '%mle'; ; + +--------------+--------------------+----------------------+ --------------+--------------------+----------------------+ | | component_id component_id | | component_group_id component_group_id | | component_urn component_urn | | + +--------------+--------------------+----------------------+ --------------+--------------------+----------------------+ | | 34 34 | | 20 20 | | file file: ://component_mle | //component_mle | + +--------------+--------------------+----------------------+ --------------+--------------------+----------------------+ 1 1 row row in in set set ( (0.0003 0.0003 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 14

Slide 17

Slide 17 text

Loading MLE - Error log We can also parse the error log for information related to MLE: SQL SQL > > select select * * from from performance_schema performance_schema. .error_log error_log where where SUBSYSTEM SUBSYSTEM= ='MLE' 'MLE'; ; + +----------------------------+-----------+------+------------+-----------+-------------------------------------------+ ----------------------------+-----------+------+------------+-----------+-------------------------------------------+ | | LOGGED LOGGED | | THREAD_ID THREAD_ID | | PRIO PRIO | | ERROR_CODE ERROR_CODE | | SUBSYSTEM SUBSYSTEM | | DATA DATA | | + +----------------------------+-----------+------+------------+-----------+-------------------------------------------+ ----------------------------+-----------+------+------------+-----------+-------------------------------------------+ | | 2024 2024- -09 09- -24 24 21 21: :28 28: :26.146678 26.146678 | | 10 10 | | Note Note | | MY MY- -015000 015000 | | MLE MLE | | Component Component starting starting. .. .. . | | | | 2024 2024- -09 09- -24 24 21 21: :28 28: :26.174638 26.174638 | | 10 10 | | Note Note | | MY MY- -015000 015000 | | MLE MLE | | Component state: INACTIVE Component state: INACTIVE | | | | 2024 2024- -09 09- -24 24 21 21: :33 33: :01.296445 01.296445 | | 10 10 | | Note Note | | MY MY- -015000 015000 | | MLE MLE | | Component state: ACTIVE Component state: ACTIVE | | | | 2024 2024- -09 09- -24 24 21 21: :33 33: :01.296475 01.296475 | | 10 10 | | Note Note | | MY MY- -015000 015000 | | MLE MLE | | Max memory Max memory 1363148800 1363148800 produces produces - -Xmx Xmx= =525 525MB MB | | + +----------------------------+-----------+------+------------+-----------+-------------------------------------------+ ----------------------------+-----------+------+------------+-----------+-------------------------------------------+ 4 4 rows rows in in set set ( (0.0023 0.0023 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 15

Slide 18

Slide 18 text

MLE - Status Variables + +------------------------------+------------+ ------------------------------+------------+ | | Variable_name Variable_name | | Value Value | | + +------------------------------+------------+ ------------------------------+------------+ | | mle_heap_status mle_heap_status | | Allocated Allocated | | | | mle_languages_supported mle_languages_supported | | JavaScript JavaScript | | | | mle_memory_used mle_memory_used | | 23 23 | | | | mle_oom_errors mle_oom_errors | | 0 0 | | | | mle_session_resets mle_session_resets | | 0 0 | | | | mle_sessions mle_sessions | | 1 1 | | | | mle_sessions_max mle_sessions_max | | 1 1 | | | | mle_status mle_status | | Active Active | | | | mle_stored_functions mle_stored_functions | | 1 1 | | | | mle_stored_procedures mle_stored_procedures | | 0 0 | | | | mle_stored_program_bytes_max mle_stored_program_bytes_max | | 33 33 | | | | mle_stored_program_sql_max mle_stored_program_sql_max | | 0 0 | | | | mle_stored_programs mle_stored_programs | | 1 1 | | | | mle_threads mle_threads | | 1 1 | | | | mle_threads_max mle_threads_max | | 1 1 | | + +------------------------------+------------+ ------------------------------+------------+ MLE - Variable + +----------------+------------+ ----------------+------------+ | | Variable_name Variable_name | | Value Value | | + +----------------+------------+ ----------------+------------+ | | mle mle. .memory_max memory_max | | 1363148800 1363148800 | | + +----------------+------------+ ----------------+------------+ SQL SQL > > select select format_bytes format_bytes( (@ @@mle.memory_max @mle.memory_max) ); ; + +--------------------------------+ --------------------------------+ | | format_bytes format_bytes( (@ @@mle.memory_max @mle.memory_max) ) | | + +--------------------------------+ --------------------------------+ | | 1.27 1.27 GiB GiB | | + +--------------------------------+ --------------------------------+ Copyright @ 2024 Oracle and/or its affiliates. 16

Slide 19

Slide 19 text

MLE - UDFs SQL SQL > > select select * * from from performance_schema performance_schema. .user_defined_functions user_defined_functions where where udf_name udf_name like like 'mle%' 'mle%'; ; + +-----------------------+-----------------+----------+-------------+-----------------+ -----------------------+-----------------+----------+-------------+-----------------+ | | UDF_NAME UDF_NAME | | UDF_RETURN_TYPE UDF_RETURN_TYPE | | UDF_TYPE UDF_TYPE | | UDF_LIBRARY UDF_LIBRARY | | UDF_USAGE_COUNT UDF_USAGE_COUNT | | + +-----------------------+-----------------+----------+-------------+-----------------+ -----------------------+-----------------+----------+-------------+-----------------+ | | mle_session_reset mle_session_reset | | char char | | function function | | NULL NULL | | 1 1 | | | | mle_session_state mle_session_state | | char char | | function function | | NULL NULL | | 1 1 | | | | mle_set_session_state mle_set_session_state | | integer integer | | function function | | NULL NULL | | 1 1 | | + +-----------------------+-----------------+----------+-------------+-----------------+ -----------------------+-----------------+----------+-------------+-----------------+ 3 3 rows rows in in set set ( (0.0004 0.0004 sec sec) ) mle_session_state(): obtain session information about the MLE stored program that was most recently executed. mle_session_set(): determine the rules in e ect during the current session for converting MySQL integer types (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT) to JavaScript values Copyright @ 2024 Oracle and/or its affiliates. 17

Slide 20

Slide 20 text

First JavaScript Function Hello World Copyright @ 2024 Oracle and/or its affiliates. 18

Slide 21

Slide 21 text

SQL SQL > > CREATE CREATE FUNCTION FUNCTION hello_world_js hello_world_js( () ) RETURNS RETURNS CHAR CHAR( (12 12) ) DETERMINISTIC DETERMINISTIC LANGUAGE LANGUAGE JAVASCRIPT JAVASCRIPT AS AS $$ $$ return return ( ("Ciao Italia!" "Ciao Italia!") ); ; $$ $$ ; ; Hello World Let's create our rst JavaScript function inside MySQL: Copyright @ 2024 Oracle and/or its affiliates. 19

Slide 22

Slide 22 text

SQL SQL > > CREATE CREATE FUNCTION FUNCTION hello_world_js hello_world_js( () ) RETURNS RETURNS CHAR CHAR( (12 12) ) DETERMINISTIC DETERMINISTIC LANGUAGE LANGUAGE JAVASCRIPT JAVASCRIPT AS AS $$ $$ return return ( ("Ciao Italia!" "Ciao Italia!") ); ; $$ $$ ; ; SQL SQL > > select select hello_world_js hello_world_js( () ); ; + +------------------+ ------------------+ | | hello_world_js hello_world_js( () ) | | + +------------------+ ------------------+ | | Ciao Italia Ciao Italia! ! | | + +------------------+ ------------------+ 1 1 row row in in set set ( (0.0007 0.0007 sec sec) ) Hello World Let's create our rst JavaScript function inside MySQL: Copyright @ 2024 Oracle and/or its affiliates. 19

Slide 23

Slide 23 text

Data - Cleansing and Transformation the Global Intl JavaScript Object Copyright @ 2024 Oracle and/or its affiliates. 20

Slide 24

Slide 24 text

Cleansing Data Stored Programs can be used to clean data in MySQL. Let's see an example for cleaning phone numbers: SQL SQL > > select select * * from from users users; ; + +----+-------+-------------------+ ----+-------+-------------------+ | | id id | | name name | | phone phone | | + +----+-------+-------------------+ ----+-------+-------------------+ | | 1 1 | | Andra Andra | | + +49 49 ( (234 234) ) 567 567- -890 890 | | | | 2 2 | | Luca Luca | | 0049.458 0049.458.696 .696 | | | | 3 3 | | Marco Marco | | boh? boh? | | + +----+-------+-------------------+ ----+-------+-------------------+ 3 3 rows rows in in set set ( (0.0007 0.0007 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 21

Slide 25

Slide 25 text

Cleansing Data - SQL DELIMITER DELIMITER $$ $$ CREATE CREATE FUNCTION FUNCTION CleanPhoneNumbers_sql CleanPhoneNumbers_sql( (phone_in phone_in VARCHAR VARCHAR( (50 50) )) ) RETURNS RETURNS CHAR CHAR( (13 13) ) DETERMINISTIC DETERMINISTIC BEGIN BEGIN DECLARE DECLARE cleaned cleaned VARCHAR VARCHAR( (50 50) ); ; -- Replace the leading '+' with '00' -- Replace the leading '+' with '00' SET SET cleaned cleaned = = IF IF( (LEFT LEFT( (phone_in phone_in, , 1 1) ) = = '+' '+', , CONCAT CONCAT( ('00' '00', , SUBSTRING SUBSTRING( (phone_in phone_in, , 2 2) )) ), , phone_in phone_in) ); ; -- Remove all non-numeric characters -- Remove all non-numeric characters SET SET cleaned cleaned = = REPLACE REPLACE( (REPLACE REPLACE( (REPLACE REPLACE( (REPLACE REPLACE( (REPLACE REPLACE( (REPLACE REPLACE( (REPLACE REPLACE( (REPLACE REPLACE( (REPLACE REPLACE( (REPLACE REPLACE( ( cleaned cleaned, , '-' '-', , '' '') ), , '(' '(', , '' '') ), , ')' ')', , '' '') ), , ' ' ' ', , '' '') ), , '.' '.', , '' '') ), , '+' '+', , '' '') ), , ',' ',', , '' '') ), , '/' '/', , '' '') ), , '\\' '\\', , '' '') ), , ':' ':', , '' '') ); ; -- Return the cleaned phone number if it's 10 or 13 digits, otherwise return NULL -- Return the cleaned phone number if it's 10 or 13 digits, otherwise return NULL IF IF LENGTH LENGTH( (cleaned cleaned) ) = = 10 10 OR OR LENGTH LENGTH( (cleaned cleaned) ) = = 13 13 THEN THEN RETURN RETURN cleaned cleaned; ; ELSE ELSE RETURN RETURN NULL NULL; ; END END IF IF; ; END END $$ $$ DELIMITER DELIMITER ; ; Copyright @ 2024 Oracle and/or its affiliates. 22

Slide 26

Slide 26 text

Cleansing Data - SQL (2) SQL SQL > > update update users users set set phone phone= =CleanPhoneNumbers_sql CleanPhoneNumbers_sql( (phone phone) ); ; Query OK Query OK, , 3 3 rows rows affected affected ( (0.0059 0.0059 sec sec) ) Rows Rows matched matched: : 3 3 Changed: Changed: 3 3 Warnings Warnings: : 0 0 SQL SQL > > select select * * from from users users; ; + +----+-------+---------------+ ----+-------+---------------+ | | id id | | name name | | phone phone | | + +----+-------+---------------+ ----+-------+---------------+ | | 1 1 | | Andra Andra | | 0049234567890 0049234567890 | | | | 2 2 | | Luca Luca | | 0049458696 0049458696 | | | | 3 3 | | Marco Marco | | NULL NULL | | + +----+-------+---------------+ ----+-------+---------------+ 3 3 rows rows in in set set ( (0.0006 0.0006 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 23

Slide 27

Slide 27 text

Cleansing Data - JavaScript CREATE CREATE FUNCTION FUNCTION CleanPhoneNumbers_js CleanPhoneNumbers_js( (phone_in phone_in varchar varchar( (50 50) )) ) returns returns char char( (13 13) ) DETERMINISTIC DETERMINISTIC language language javascript javascript as as $$ $$ let cleaned let cleaned = = phone_in phone_in. .replace replace( (/ /^ ^\ \+ +/ /, ,'00' '00') ); ; cleaned cleaned = = cleaned cleaned. .replace replace( (/ /\D \D/ /g g, , '' '') ); ; return return ( (cleaned cleaned. .length length = == == = 10 10 || || cleaned cleaned. .length length = == == = 13 13) ) ? cleaned : ? cleaned : null null; ; $$ $$ ; ; Copyright @ 2024 Oracle and/or its affiliates. 24

Slide 28

Slide 28 text

Cleansing Data - JavaScript (2) SQL SQL > > update update users users set set phone phone= =CleanPhoneNumbers_js CleanPhoneNumbers_js( (phone phone) ); ; Query OK Query OK, , 3 3 rows rows affected affected ( (0.0037 0.0037 sec sec) ) Rows Rows matched matched: : 3 3 Changed: Changed: 3 3 Warnings Warnings: : 0 0 SQL SQL > > select select * * from from users users; ; + +----+-------+---------------+ ----+-------+---------------+ | | id id | | name name | | phone phone | | + +----+-------+---------------+ ----+-------+---------------+ | | 1 1 | | Andra Andra | | 0049234567890 0049234567890 | | | | 2 2 | | Luca Luca | | 0049458696 0049458696 | | | | 3 3 | | Marco Marco | | NULL NULL | | + +----+-------+---------------+ ----+-------+---------------+ 3 3 rows rows in in set set ( (0.0006 0.0006 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 25

Slide 29

Slide 29 text

Transforming Data - the Intl Javascript Object This JavaScript Object is used to handle a variety of internationalization constructors and other language sensitive functions. Let's have a look at this table: SQL SQL > > select select * * from from users users; ; + +----+-------+---------------+---------+ ----+-------+---------------+---------+ | | id id | | name name | | phone phone | | sales sales | | + +----+-------+---------------+---------+ ----+-------+---------------+---------+ | | 1 1 | | Andra Andra | | 0049234567890 0049234567890 | | 310000 310000 | | | | 2 2 | | Luca Luca | | 0049458696 0049458696 | | 9800000 9800000 | | | | 3 3 | | Marco Marco | | NULL NULL | | 2500 2500 | | + +----+-------+---------------+---------+ ----+-------+---------------+---------+ 3 3 rows rows in in set set ( (0.0007 0.0007 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 26

Slide 30

Slide 30 text

Transformation - Intl Let's create a function to display the amount in the sales column to something easier to read: DROP DROP FUNCTION FUNCTION IF IF EXISTS EXISTS format_sales_js format_sales_js; ; CREATE CREATE FUNCTION FUNCTION format_sales_js format_sales_js( (sales_in sales_in int int) ) returns returns varchar varchar( (30 30) ) DETERMINISTIC DETERMINISTIC language language javascript javascript as as $$ $$ return return new Intl new Intl. .NumberFormat NumberFormat( ('en-US' 'en-US', , { { notation: notation:'compact' 'compact', , maximumSignificantDigits: maximumSignificantDigits: 3 3 } }) ). .format format( (sales_in sales_in) ) $$ $$ ; ; Copyright @ 2024 Oracle and/or its affiliates. 27

Slide 31

Slide 31 text

Transformation - Intl (2) SQL SQL > > select select * *, , format_sales_js format_sales_js( (sales sales) ) from from users users; ; + +----+-------+---------------+---------+------------------------+ ----+-------+---------------+---------+------------------------+ | | id id | | name name | | phone phone | | sales sales | | format_sales_js format_sales_js( (sales sales) ) | | + +----+-------+---------------+---------+------------------------+ ----+-------+---------------+---------+------------------------+ | | 1 1 | | Andra Andra | | 0049234567890 0049234567890 | | 310000 310000 | | 310 310K K | | | | 2 2 | | Luca Luca | | 0049458696 0049458696 | | 9800000 9800000 | | 9.8 9.8M M | | | | 3 3 | | Marco Marco | | NULL NULL | | 2500 2500 | | 2.5 2.5K K | | + +----+-------+---------------+---------+------------------------+ ----+-------+---------------+---------+------------------------+ 3 3 rows rows in in set set ( (0.0070 0.0070 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 28

Slide 32

Slide 32 text

Transformation - Intl (3) But it would be nice to have the possibility to concatenate the currency too: DROP DROP FUNCTION FUNCTION format_sales_js format_sales_js; ; CREATE CREATE FUNCTION FUNCTION format_sales_js format_sales_js( (sales_in sales_in int int) ) returns returns varchar varchar( (30 30) ) DETERMINISTIC DETERMINISTIC language language javascript javascript as as $$ $$ return return new Intl new Intl. .NumberFormat NumberFormat( ('it-IT' 'it-IT', , { { style: style: 'currency' 'currency', , currency: currency: 'EUR' 'EUR', , notation: notation:'compact' 'compact', , maximumSignificantDigits: maximumSignificantDigits: 3 3 } }) ). .format format( (sales_in sales_in) ) $$ $$ ; ; Copyright @ 2024 Oracle and/or its affiliates. 29

Slide 33

Slide 33 text

Transformation - Intl (4) SQL SQL > > select select * *, , format_sales_js format_sales_js( (sales sales) ) from from users users; ; + +----+-------+---------------+---------+------------------------+ ----+-------+---------------+---------+------------------------+ | | id id | | name name | | phone phone | | sales sales | | format_sales_js format_sales_js( (sales sales) ) | | + +----+-------+---------------+---------+------------------------+ ----+-------+---------------+---------+------------------------+ | | 1 1 | | Andra Andra | | 0049234567890 0049234567890 | | 310000 310000 | | 310.000 310.000 € € | | | | 2 2 | | Luca Luca | | 0049458696 0049458696 | | 9800000 9800000 | | 9 9, ,8 8 Mio € Mio € | | | | 3 3 | | Marco Marco | | NULL NULL | | 2500 2500 | | 2500 2500 € € | | + +----+-------+---------------+---------+------------------------+ ----+-------+---------------+---------+------------------------+ 3 3 rows rows in in set set ( (0.0063 0.0063 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 30

Slide 34

Slide 34 text

Transformation - Int: example SQL SQL > > select select * *, , format_sales_js format_sales_js( (sales sales, , 'USD' 'USD', , 'fr-FR' 'fr-FR') ) sales sales from from users users; ; + +----+-------+---------------+---------+---------------+ ----+-------+---------------+---------+---------------+ | | id id | | name name | | phone phone | | sales sales | | sales sales | | + +----+-------+---------------+---------+---------------+ ----+-------+---------------+---------+---------------+ | | 1 1 | | Andra Andra | | 0049234567890 0049234567890 | | 310000 310000 | | 310 310 000 000 $US $US | | | | 2 2 | | Luca Luca | | 0049458696 0049458696 | | 9800000 9800000 | | 9 9 800 800 000 000 $US $US | | | | 3 3 | | Marco Marco | | NULL NULL | | 2500 2500 | | 2 2 500 500 $US $US | | + +----+-------+---------------+---------+---------------+ ----+-------+---------------+---------+---------------+ 3 3 rows rows in in set set ( (0.0019 0.0019 sec sec) ) SQL SQL > > select select * *, , format_sales_js format_sales_js( (sales sales, , 'USD' 'USD', , 'en-US' 'en-US') ) sales sales from from users users; ; + +----+-------+---------------+---------+------------+ ----+-------+---------------+---------+------------+ | | id id | | name name | | phone phone | | sales sales | | sales sales | | + +----+-------+---------------+---------+------------+ ----+-------+---------------+---------+------------+ | | 1 1 | | Andra Andra | | 0049234567890 0049234567890 | | 310000 310000 | | $ $310 310, ,000 000 | | | | 2 2 | | Luca Luca | | 0049458696 0049458696 | | 9800000 9800000 | | $ $9 9, ,800 800, ,000 000 | | | | 3 3 | | Marco Marco | | NULL NULL | | 2500 2500 | | $ $2 2, ,500 500 | | + +----+-------+---------------+---------+------------+ ----+-------+---------------+---------+------------+ 3 3 rows rows in in set set ( (0.0022 0.0022 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 31

Slide 35

Slide 35 text

Datatypes Playing with JSON, Arrays and Vectors Copyright @ 2024 Oracle and/or its affiliates. 32

Slide 36

Slide 36 text

JavaScript and datatypes - JSON Of course JS works perfectly with JSON. We can parse, sort, and play with JSON inside any MLE function created in JavaScript. Let's have a look a the following table: SQL SQL > > select select * * from from italia italia; ; + +----+-----------------------------------------------+ ----+-----------------------------------------------+ | | id id | | user user | | + +----+-----------------------------------------------+ ----+-----------------------------------------------+ | | 1 1 | | { {"city" "city": : "Fara Gera d Adda" "Fara Gera d Adda", , "name" "name": : "Marco" "Marco"} } | | | | 2 2 | | { {"city" "city": : "Milano" "Milano", , "name" "name": : "Andra" "Andra"} } | | | | 3 3 | | { {"city" "city": : "Palermo" "Palermo", , "name" "name": : "Luca" "Luca"} } | | + +----+-----------------------------------------------+ ----+-----------------------------------------------+ 3 3 rows rows in in set set ( (0.0002 0.0002 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 33

Slide 37

Slide 37 text

JavaScript and datatypes - JSON (2) drop drop function function if if exists exists sortArrayByProperty sortArrayByProperty; ; create create function function sortArrayByProperty sortArrayByProperty( (items items varchar varchar( (10000 10000) ), , prop prop varchar varchar( (100 100) )) ) returns returns varchar varchar( (10000 10000) ) DETERMINISTIC DETERMINISTIC language language javascript javascript as as $$ $$ const arr const arr = = JSON JSON. .parse parse( (items items) ) function function compare compare( (a a, ,b b) ){ { if if( (a a[ [prop prop] ] < < b b[ [prop prop] ]) ) return return - -1 1 else else if if ( (a a[ [prop prop] ] > > b b[ [prop prop] ]) ) return return 1 1 return return 0 0 } } return return JSON JSON. .stringify stringify( (arr arr. .sort sort( (compare compare) )) ) $$ $$; ; See h ps://blogs.oracle.com/mysql/post/sorting-json-arrays-in-mysql-with-javascript Copyright @ 2024 Oracle and/or its affiliates. 34

Slide 38

Slide 38 text

JavaScript and datatypes - JSON (3) SQL SQL > > select select json_pretty json_pretty( (sortArrayByProperty sortArrayByProperty( (arr arr, , 'name' 'name') )) ) from from ( (select select JSON_ARRAYAGG JSON_ARRAYAGG( (user user) ) arr arr from from ( (select select user user from from italia italia) ) a a) )b\G b\G * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * 1. 1. row row * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * json_pretty json_pretty( (sortArrayByProperty sortArrayByProperty( (arr arr, , 'name' 'name') )) ): : [ [ { { "city" "city": : "Milano" "Milano", , "name" "name": : "Andra" "Andra" } }, , { { "city" "city": : "Palermo" "Palermo", , "name" "name": : "Luca" "Luca" } }, , { { "city" "city": : "Fara Gera d Adda" "Fara Gera d Adda", , "name" "name": : "Marco" "Marco" } } ] ] 1 1 row row in in set set ( (0.0015 0.0015 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 35

Slide 39

Slide 39 text

JavaScript and datatypes - UUIDs We can also create functions to parse MySQL's UUIDs (v1): SQL SQL > > select select now now( () ), , uuid uuid( () ), , from_unixtime from_unixtime( (uuid_to_unixtime_js uuid_to_unixtime_js( (uuid uuid( () )) )) ) uuid_ts uuid_ts; ; + +---------------------+--------------------------------------+----------------------------+ ---------------------+--------------------------------------+----------------------------+ | | now now( () ) | | uuid uuid( () ) | | uuid_ts uuid_ts | | + +---------------------+--------------------------------------+----------------------------+ ---------------------+--------------------------------------+----------------------------+ | | 2024 2024- -09 09- -25 25 15 15: :06 06: :44 44 | | 03 03c07e0e c07e0e- -7 7b3f b3f- -11 11ef ef- -8434 8434- -5 5e1b9081e705 e1b9081e705 | | 2024 2024- -09 09- -25 25 15 15: :06 06: :44.787000 44.787000 | | + +---------------------+--------------------------------------+----------------------------+ ---------------------+--------------------------------------+----------------------------+ 1 1 row row in in set set ( (0.0010 0.0010 sec sec) ) see h ps://github.com/lefred/mysql-graalvm-examples Copyright @ 2024 Oracle and/or its affiliates. 36

Slide 40

Slide 40 text

JavaScript and datatypes - UUIDs (2) Or generate any type of UUIDs: SQL SQL > > select select js_uuidv7 js_uuidv7( () ); ; + +--------------------------------------+ --------------------------------------+ | | js_uuidv7 js_uuidv7( () ) | | + +--------------------------------------+ --------------------------------------+ | | 0192294 0192294d d- -1848 1848- -771 771b b- -3 3aa0 aa0- -2 2a612dc3932e a612dc3932e | | + +--------------------------------------+ --------------------------------------+ 1 1 row row in in set set ( (0.0034 0.0034 sec sec) ) SQL SQL > > select select js_uuidv7 js_uuidv7( () ); ; + +--------------------------------------+ --------------------------------------+ | | js_uuidv7 js_uuidv7( () ) | | + +--------------------------------------+ --------------------------------------+ | | 0192294 0192294d d- -25 25f6 f6- -71 71bc bc- -0113 0113- -a8a8b2cee175 a8a8b2cee175 | | + +--------------------------------------+ --------------------------------------+ 1 1 row row in in set set ( (0.0009 0.0009 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 37

Slide 41

Slide 41 text

JavaScript and datatypes - VECTOR Since MySQL 9.0, the new VECTOR datatype is supported in MySQL. It's again very easy to deal with this new datatype in JavaScript. Let's see how to addition two vectors. Copyright @ 2024 Oracle and/or its affiliates. 38

Slide 42

Slide 42 text

JavaScript and datatypes - VECTOR (2) create create function function vector_addition_js vector_addition_js( (a a varchar varchar( (15000 15000) ), , b b varchar varchar( (15000 15000) )) ) returns returns varchar varchar( (15000 15000) ) deterministic deterministic language language javascript javascript as as $$ $$ const vec1 const vec1 = = JSON JSON. .parse parse( (a a) ) const vec2 const vec2 = = JSON JSON. .parse parse( (b b) ) if if ( (vec1 vec1. .length length != !== = vec2 vec2. .length length) ) { { throw new Error throw new Error( ("Vectors must have the same dimension" "Vectors must have the same dimension") ) } } const result const result = = [ [] ] let i let i = = 0 0 while while ( (i i < < vec1 vec1. .length length) ) { { result result. .push push( (vec1 vec1[ [i i] ] + + vec2 vec2[ [i i] ]) ) i i+ ++ + } } const resultStr const resultStr = = JSON JSON. .stringify stringify( (result result) ) try { try { const parsedResult const parsedResult = = JSON JSON. .parse parse( (resultStr resultStr) ) return return resultStr resultStr } catch } catch ( (error error) ) { { throw new Error throw new Error( ("Invalid vector conversion" "Invalid vector conversion") ) } } $$ $$; ; Copyright @ 2024 Oracle and/or its affiliates. 39

Slide 43

Slide 43 text

JavaScript and datatypes - VECTOR (3) SQL SQL > > select select vector_addition_js vector_addition_js( ('[1,2,3]' '[1,2,3]', ,'[4,5,6]' '[4,5,6]') ); ; + +-----------------------------------------+ -----------------------------------------+ | | vector_addition_js vector_addition_js( ('[1,2,3]' '[1,2,3]', ,'[4,5,6]' '[4,5,6]') ) | | + +-----------------------------------------+ -----------------------------------------+ | | [ [5 5, ,7 7, ,9 9] ] | | + +-----------------------------------------+ -----------------------------------------+ 1 1 row row in in set set ( (0.0053 0.0053 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 40

Slide 44

Slide 44 text

JavaScript and datatypes - VECTOR (3) SQL SQL > > select select vector_addition_js vector_addition_js( ('[1,2,3]' '[1,2,3]', ,'[4,5,6]' '[4,5,6]') ); ; + +-----------------------------------------+ -----------------------------------------+ | | vector_addition_js vector_addition_js( ('[1,2,3]' '[1,2,3]', ,'[4,5,6]' '[4,5,6]') ) | | + +-----------------------------------------+ -----------------------------------------+ | | [ [5 5, ,7 7, ,9 9] ] | | + +-----------------------------------------+ -----------------------------------------+ 1 1 row row in in set set ( (0.0053 0.0053 sec sec) ) Imagination is the only limit ! Copyright @ 2024 Oracle and/or its affiliates. 40

Slide 45

Slide 45 text

DEBUG How to debug JavaScript Stored Functions Copyright @ 2024 Oracle and/or its affiliates. 41

Slide 46

Slide 46 text

MLE JavaScript - debug To debug we use the MLE UDFs we encountered earlier and we add some output to the console in the code like this: SQL SQL > > CREATE CREATE FUNCTION FUNCTION hello_world_js hello_world_js( () ) RETURNS RETURNS CHAR CHAR( (12 12) ) DETERMINISTIC DETERMINISTIC LANGUAGE LANGUAGE JAVASCRIPT JAVASCRIPT AS AS $$ $$ console console. .log log( ('DEBUG: This is a message' 'DEBUG: This is a message') ) console console. .error error( ('ERROR: This is an error' 'ERROR: This is an error') ) return return ( ("Ciao Italia!" "Ciao Italia!") ); ; $$ $$; ; Copyright @ 2024 Oracle and/or its affiliates. 42

Slide 47

Slide 47 text

MLE JavaScript - debug (2) Let's call this JavaScript function again: SQL SQL > > select select hello_world_js hello_world_js( () ); ; + +------------------+ ------------------+ | | hello_world_js hello_world_js( () ) | | + +------------------+ ------------------+ | | Ciao Italia Ciao Italia! ! | | + +------------------+ ------------------+ 1 1 row row in in set set ( (0.0051 0.0051 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 43

Slide 48

Slide 48 text

MLE JavaScript - debug (3) And now we can use mle_session_state() to retrieve the info: SQL SQL > > select select mle_session_state mle_session_state( ('stdout' 'stdout') )\G \G * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * 1. 1. row row * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * mle_session_state mle_session_state( ('stdout' 'stdout') ): DEBUG: This : DEBUG: This is is a message a message 1 1 row row in in set set ( (0.0005 0.0005 sec sec) ) SQL SQL > > select select mle_session_state mle_session_state( ('stderr' 'stderr') )\G \G * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * 1. 1. row row * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * mle_session_state mle_session_state( ('stderr' 'stderr') ): ERROR: This : ERROR: This is is an error an error 1 1 row row in in set set ( (0.0005 0.0005 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 44

Slide 49

Slide 49 text

MLE JavaScript - debug (4) To clear the history, we just need to use mle_session_reset(): SQL SQL > > select select mle_session_state mle_session_state( ('stdout' 'stdout') )\G \G * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * 1. 1. row row * ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** * mle_session_state mle_session_state( ('stdout' 'stdout') ): DEBUG: This : DEBUG: This is is a message a message DEBUG: This DEBUG: This is is a message a message DEBUG: This DEBUG: This is is a message a message SQL SQL > > select select mle_session_reset mle_session_reset( () ); ; + +------------------------------------------+ ------------------------------------------+ | | mle_session_reset mle_session_reset( () ) | | + +------------------------------------------+ ------------------------------------------+ | | The The session session state state is is successfully reset successfully reset. . | | + +------------------------------------------+ ------------------------------------------+ 1 1 row row in in set set ( (0.0003 0.0003 sec sec) ) Copyright @ 2024 Oracle and/or its affiliates. 45

Slide 50

Slide 50 text

Resources h ps://github.com/lefred/mysql-graalvm-examples h ps://blogs.oracle.com/mysql/post/mysql-vector-datatype-create-your-operations-part-1 h ps://blogs.oracle.com/mysql/post/a-quick-introduction-to-javascript-stored-programs-in-mysql h ps://blogs.oracle.com/mysql/post/javascript-support-in-mysql-the-uuid-example h ps://blogs.oracle.com/mysql/post/introducing-javascript-support-in-mysql h ps://blogs.oracle.com/mysql/post/debugging-javascript-stored-functions-in-mysql h ps://blogs.oracle.com/mysql/post/sorting-json-arrays-in-mysql-with-javascript h ps://blogs.oracle.com/mysql/post/more-javascript-in-mysql h ps://blogs.oracle.com/mysql/post/using-the-global-intl-javascript-object-in-mysql h ps://blogs.oracle.com/mysql/post/ ltering-json-arrays-with-javascript-in-mysql Copyright @ 2024 Oracle and/or its affiliates. 46

Slide 51

Slide 51 text

Share your ❤ to MySQL #mysql Join our slack channel! bit.ly/mysql-slack Copyright @ 2024 Oracle and/or its affiliates. 47

Slide 52

Slide 52 text

Questions ? Copyright @ 2024 Oracle and/or its affiliates. 48