1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

MDEV-11952 Oracle-style packages: stage#5

- CREATE PACKAGE [BODY] statements are now
  entirely written to mysql.proc with type='PACKAGE' and type='PACKAGE BODY'.
- CREATE PACKAGE BODY now supports IF NOT EXISTS
- DROP PACKAGE BODY now supports IF EXISTS
- CREATE OR REPLACE PACKAGE [BODY] is now supported
- CREATE PACKAGE [BODY] now support the DEFINER clause:

    CREATE DEFINER user@host PACKAGE pkg ... END;
    CREATE DEFINER user@host PACKAGE BODY pkg ... END;

- CREATE PACKAGE [BODY] now supports SQL SECURITY and COMMENT clauses, e.g.:

    CREATE PACKAGE p1 SQL SECURITY INVOKER COMMENT "comment" AS ... END;

- Package routines are now created from the package CREATE PACKAGE BODY
  statement and don't produce individual records in mysql.proc.

- CREATE PACKAGE BODY now supports package-wide variables.
  Package variables can be read and set inside package routines.
  Package variables are stored in a separate sp_rcontext,
  which is cached in THD on the first packate routine call.

- CREATE PACKAGE BODY now supports the initialization section.

- All public routines (i.e. declared in CREATE PACKAGE)
  must have implementations in CREATE PACKAGE BODY

- Only public package routines are available outside of the package

- {CREATE|DROP} PACKAGE [BODY] now respects CREATE ROUTINE and ALTER ROUTINE
  privileges

- "GRANT EXECUTE ON PACKAGE BODY pkg" is now supported

- SHOW CREATE PACKAGE [BODY] is now supported

- SHOW PACKAGE [BODY] STATUS is now supported

- CREATE and DROP for PACKAGE [BODY] now works for non-current databases

- mysqldump now supports packages

- "SHOW {PROCEDURE|FUNCTION) CODE pkg.routine" now works for package routines

- "SHOW PACKAGE BODY CODE pkg" now works (the package initialization section)

- A new package body level MDL was added

- Recursive calls for package procedures are now possible

- Routine forward declarations in CREATE PACKATE BODY are now supported.

- Package body variables now work as SP OUT parameters

- Package body variables now work as SELECT INTO targets

- Package body variables now support ROW, %ROWTYPE, %TYPE
This commit is contained in:
Alexander Barkov
2017-08-18 23:36:42 +04:00
parent 83ea839fb1
commit 583eb96c24
86 changed files with 11064 additions and 278 deletions

View File

@ -607,6 +607,7 @@ static MEM_ROOT acl_memroot, grant_memroot;
static bool initialized=0;
static bool allow_all_hosts=1;
static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash;
static HASH package_spec_priv_hash, package_body_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts;
static Hash_filo<acl_entry> *acl_cache;
static uint grant_version=0; /* Version of priv tables. incremented by acl_load */
@ -650,6 +651,18 @@ HASH *Sp_handler_function::get_priv_hash() const
}
HASH *Sp_handler_package_spec::get_priv_hash() const
{
return &package_spec_priv_hash;
}
HASH *Sp_handler_package_body::get_priv_hash() const
{
return &package_body_priv_hash;
}
/*
Enumeration of ACL/GRANT tables in the mysql database
*/
@ -1312,6 +1325,8 @@ enum enum_acl_lists
COLUMN_PRIVILEGES_HASH,
PROC_PRIVILEGES_HASH,
FUNC_PRIVILEGES_HASH,
PACKAGE_SPEC_PRIVILEGES_HASH,
PACKAGE_BODY_PRIVILEGES_HASH,
PROXY_USERS_ACL,
ROLES_MAPPINGS_HASH
};
@ -5401,7 +5416,10 @@ table_error:
******************************************************************/
struct PRIVS_TO_MERGE
{
enum what { ALL, GLOBAL, DB, TABLE_COLUMN, PROC, FUNC } what;
enum what
{
ALL, GLOBAL, DB, TABLE_COLUMN, PROC, FUNC, PACKAGE_SPEC, PACKAGE_BODY
} what;
const char *db, *name;
};
@ -5413,6 +5431,10 @@ static enum PRIVS_TO_MERGE::what sp_privs_to_merge(stored_procedure_type type)
return PRIVS_TO_MERGE::FUNC;
case TYPE_ENUM_PROCEDURE:
return PRIVS_TO_MERGE::PROC;
case TYPE_ENUM_PACKAGE:
return PRIVS_TO_MERGE::PACKAGE_SPEC;
case TYPE_ENUM_PACKAGE_BODY:
return PRIVS_TO_MERGE::PACKAGE_BODY;
case TYPE_ENUM_TRIGGER:
case TYPE_ENUM_PROXY:
break;
@ -6231,7 +6253,14 @@ static int merge_role_privileges(ACL_ROLE *role __attribute__((unused)),
if (all || data->what == PRIVS_TO_MERGE::FUNC)
changed|= merge_role_routine_grant_privileges(grantee,
data->db, data->name, &role_hash, &func_priv_hash);
if (all || data->what == PRIVS_TO_MERGE::PACKAGE_SPEC)
changed|= merge_role_routine_grant_privileges(grantee,
data->db, data->name, &role_hash,
&package_spec_priv_hash);
if (all || data->what == PRIVS_TO_MERGE::PACKAGE_BODY)
changed|= merge_role_routine_grant_privileges(grantee,
data->db, data->name, &role_hash,
&package_body_priv_hash);
return !changed; // don't recurse into the subgraph if privs didn't change
}
@ -7116,6 +7145,8 @@ void grant_free(void)
my_hash_free(&column_priv_hash);
my_hash_free(&proc_priv_hash);
my_hash_free(&func_priv_hash);
my_hash_free(&package_spec_priv_hash);
my_hash_free(&package_body_priv_hash);
free_root(&grant_memroot,MYF(0));
DBUG_VOID_RETURN;
}
@ -7182,6 +7213,10 @@ static bool grant_load(THD *thd,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
(void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
(void) my_hash_init(&package_spec_priv_hash, &my_charset_utf8_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
(void) my_hash_init(&package_body_priv_hash, &my_charset_utf8_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
init_sql_alloc(&grant_memroot, "GRANT", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
t_table= tables_priv.table();
@ -7331,6 +7366,7 @@ static my_bool propagate_role_grants_action(void *role_ptr,
bool grant_reload(THD *thd)
{
HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash;
HASH old_package_spec_priv_hash, old_package_body_priv_hash;
MEM_ROOT old_mem;
int result;
DBUG_ENTER("grant_reload");
@ -7350,6 +7386,8 @@ bool grant_reload(THD *thd)
old_column_priv_hash= column_priv_hash;
old_proc_priv_hash= proc_priv_hash;
old_func_priv_hash= func_priv_hash;
old_package_spec_priv_hash= package_spec_priv_hash;
old_package_body_priv_hash= package_body_priv_hash;
/*
Create a new memory pool but save the current memory pool to make an undo
@ -7367,6 +7405,8 @@ bool grant_reload(THD *thd)
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
proc_priv_hash= old_proc_priv_hash;
func_priv_hash= old_func_priv_hash;
package_spec_priv_hash= old_package_spec_priv_hash;
package_body_priv_hash= old_package_body_priv_hash;
grant_memroot= old_mem; /* purecov: deadcode */
}
else
@ -7374,6 +7414,8 @@ bool grant_reload(THD *thd)
my_hash_free(&old_column_priv_hash);
my_hash_free(&old_proc_priv_hash);
my_hash_free(&old_func_priv_hash);
my_hash_free(&old_package_spec_priv_hash);
my_hash_free(&old_package_body_priv_hash);
free_root(&old_mem,MYF(0));
}
@ -8002,7 +8044,9 @@ bool check_grant_db(THD *thd, const char *db)
if (error)
error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
check_grant_db_routine(thd, db, &func_priv_hash);
check_grant_db_routine(thd, db, &func_priv_hash) &&
check_grant_db_routine(thd, db, &package_spec_priv_hash) &&
check_grant_db_routine(thd, db, &package_body_priv_hash);
mysql_rwlock_unlock(&LOCK_grant);
@ -8399,6 +8443,14 @@ static bool print_grants_for_role(THD *thd, ACL_ROLE * role)
buff, sizeof(buff)))
return TRUE;
if (show_routine_grants(thd, role->user.str, "", &sp_handler_package_spec,
buff, sizeof(buff)))
return TRUE;
if (show_routine_grants(thd, role->user.str, "", &sp_handler_package_body,
buff, sizeof(buff)))
return TRUE;
return FALSE;
}
@ -8624,6 +8676,14 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user)
buff, sizeof(buff)))
goto end;
if (show_routine_grants(thd, username, hostname, &sp_handler_package_spec,
buff, sizeof(buff)))
goto end;
if (show_routine_grants(thd, username, hostname, &sp_handler_package_body,
buff, sizeof(buff)))
goto end;
if (show_proxy_grants(thd, username, hostname, buff, sizeof(buff)))
goto end;
}
@ -9559,6 +9619,14 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
grant_name_hash= &func_priv_hash;
elements= grant_name_hash->records;
break;
case PACKAGE_SPEC_PRIVILEGES_HASH:
grant_name_hash= &package_spec_priv_hash;
elements= grant_name_hash->records;
break;
case PACKAGE_BODY_PRIVILEGES_HASH:
grant_name_hash= &package_body_priv_hash;
elements= grant_name_hash->records;
break;
case PROXY_USERS_ACL:
elements= acl_proxy_users.elements;
break;
@ -9597,6 +9665,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx);
user= grant_name->user;
host= grant_name->host.hostname;
@ -9679,6 +9749,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
my_hash_delete(grant_name_hash, (uchar*) grant_name);
/*
In our HASH implementation on deletion one elements
@ -9724,6 +9796,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
{
/*
Save old hash key and its length to be able to properly update
@ -9906,6 +9980,26 @@ static int handle_grant_data(THD *thd, Grant_tables& tables, bool drop,
if (search_only)
goto end;
}
/* Handle package spec array. */
if ((handle_grant_struct(PACKAGE_SPEC_PRIVILEGES_HASH,
drop, user_from, user_to) || found)
&& ! result)
{
result= 1; /* At least one record/element found. */
/* If search is requested, we do not need to search further. */
if (search_only)
goto end;
}
/* Handle package body array. */
if ((handle_grant_struct(PACKAGE_BODY_PRIVILEGES_HASH,
drop, user_from, user_to) || found)
&& ! result)
{
result= 1; /* At least one record/element found. */
/* If search is requested, we do not need to search further. */
if (search_only)
goto end;
}
}
/* Handle tables table. */
@ -10632,7 +10726,9 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
/* Remove procedure access */
if (mysql_revoke_sp_privs(thd, &tables, &sp_handler_function, lex_user) ||
mysql_revoke_sp_privs(thd, &tables, &sp_handler_procedure, lex_user))
mysql_revoke_sp_privs(thd, &tables, &sp_handler_procedure, lex_user) ||
mysql_revoke_sp_privs(thd, &tables, &sp_handler_package_spec, lex_user) ||
mysql_revoke_sp_privs(thd, &tables, &sp_handler_package_body, lex_user))
result= -1;
ACL_USER_BASE *user_or_role;
@ -11177,6 +11273,8 @@ SHOW_VAR acl_statistics[] = {
{"database_grants", (char*)&acl_dbs.elements, SHOW_UINT},
{"function_grants", (char*)&func_priv_hash.records, SHOW_ULONG},
{"procedure_grants", (char*)&proc_priv_hash.records, SHOW_ULONG},
{"package_spec_grants", (char*)&package_spec_priv_hash.records, SHOW_ULONG},
{"package_body_grants", (char*)&package_body_priv_hash.records, SHOW_ULONG},
{"proxy_users", (char*)&acl_proxy_users.elements, SHOW_UINT},
{"role_grants", (char*)&acl_roles_mappings.records, SHOW_ULONG},
{"roles", (char*)&acl_roles.records, SHOW_ULONG},