Shannon-Data / ShannonBase

A MySQL HTAP Database, Open Source version of MySQL Heatwave, Powered by AI.
https://www.shannonbase.org
Other
16 stars 6 forks source link

feat(SQL): to support Javascript #201

Closed ShannonBase closed 3 months ago

ShannonBase commented 4 months ago

To support javascript

mysql> CREATE FUNCTION gcd_js (a INT, b INT) RETURNS INT 
    -> LANGUAGE JAVASCRIPT AS $$
    $> 
    $>   let [x, y] = [Math.abs(a), Math.abs(b)];
    $>   while(y) [x, y] = [y, x % y];
    $>   return x;
    $> 
    $> $$;

To support Javascript in mysql by using google v8 engine.

Choose an appropriate JavaScript engine, such as Google's V8 engine. V8 is an open-source, high-performance JavaScript and WebAssembly engine.

example: 1: init v8 engine

#include <v8.h>

//Intia V8 engine.
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();

2: setup running env.

// build up an Isolate instance
v8::Isolate::CreateParams create_params;
v8::Isolate* isolate = v8::Isolate::New(create_params);

// build up an context
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);

3: execute script

const char* js_code = "function add(num1, num2) { return num1 + num2; }";
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, js_code, v8::NewStringType::kNormal).ToLocalChecked();
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

ref: https://github.com/v8/v8

Now, due to the size of v8 is too large not suit for ShannonBase now, jerryscript, a light javascript engine is employed into ShannonBase.

ShannonBase commented 4 months ago
struct st_sp_chistics {
  LEX_CSTRING comment;
  enum enum_sp_suid_behaviour suid;
  bool detistic;
  enum enum_sp_data_access daccess;
  LEX_CSTRING language;  ///< CREATE|ALTER ... LANGUAGE <language>
};

in sql_yacc.yy

/**************************************************************************

 CREATE FUNCTION | PROCEDURE statements parts.

**************************************************************************/

udf_tail:
          AGGREGATE_SYM         /* $1 */
          FUNCTION_SYM          /* $2 */
          opt_if_not_exists     /* $3 */
          ident                 /* $4 */
          RETURNS_SYM           /* $5 */
          udf_type              /* $6 */
          SONAME_SYM            /* $7 */
          TEXT_STRING_sys       /* $8 */
          {                     /* $9 */
            THD *thd= YYTHD;
            LEX *lex= thd->lex;

            if (is_native_function($4))
            {
              if($3)
              {
                /*
                  IF NOT EXISTS clause is unsupported when creating a UDF with
                  the same name as a native function
                */
                my_error(ER_IF_NOT_EXISTS_UNSUPPORTED_UDF_NATIVE_FCT_NAME_COLLISION, MYF(0), $4.str);
              }
              else
                my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), $4.str);
              MYSQL_YYABORT;
            }
            lex->sql_command = SQLCOM_CREATE_FUNCTION;
            lex->udf.type= UDFTYPE_AGGREGATE;
            lex->stmt_definition_begin= @2.cpp.start;
            lex->create_info->options= $3 ? HA_LEX_CREATE_IF_NOT_EXISTS : 0;
            lex->udf.name = $4;
            lex->udf.returns=(Item_result) $6;
            lex->udf.dl=$8.str;
          }
        | FUNCTION_SYM          /* $1 */
          opt_if_not_exists     /* $2 */
          ident                 /* $3 */
          RETURNS_SYM           /* $4 */
          udf_type              /* $5 */
          SONAME_SYM            /* $6 */
          TEXT_STRING_sys       /* $7 */
          {

...
/* Characteristics for both create and alter */
sp_chistic:
          COMMENT_SYM TEXT_STRING_sys
          { Lex->sp_chistics.comment= to_lex_cstring($2); }
        | LANGUAGE_SYM SQL_SYM
          { Lex->sp_chistics.language= {"SQL",3}; }
        | LANGUAGE_SYM ident
          { Lex->sp_chistics.language= to_lex_cstring($2); }
        | NO_SYM SQL_SYM
          { Lex->sp_chistics.daccess= SP_NO_SQL; }
        | CONTAINS_SYM SQL_SYM
          { Lex->sp_chistics.daccess= SP_CONTAINS_SQL; }
        | READS_SYM SQL_SYM DATA_SYM
          { Lex->sp_chistics.daccess= SP_READS_SQL_DATA; }
        | MODIFIES_SYM SQL_SYM DATA_SYM
          { Lex->sp_chistics.daccess= SP_MODIFIES_SQL_DATA; }
        | sp_suid
          {}
        ;
****

in mysql_execute_command

    case SQLCOM_CREATE_FUNCTION:  // UDF function
    {
      if (check_access(thd, INSERT_ACL, "mysql", nullptr, nullptr, true, false))
        break;
      if (!(res = mysql_create_function(
                thd, &lex->udf,
                lex->create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)))
        my_ok(thd);
      break;
    }

and sql_udf.xx

ShannonBase commented 3 months ago

Introduction to jerryscript at here below: https://github.com/jerryscript-project/jerryscript/tree/master

RingsC commented 3 months ago

CREATE FUNCTION IS_EVEN (VAL INT) RETURNS INT LANGUAGE JAVASCRIPT AS $$ function isEven(num) { return num % 2 == 0; } return isEven(VAL); $$ An example of javascript stored procedure in MySQL.