File jsp_cl.cpp¶
File List > cubrid > src > sp > jsp_cl.cpp
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* jsp_cl.cpp - Java Stored Procedure Client Module Source
*/
#ident "$Id$"
#include "config.h"
#include <assert.h>
#if !defined(WINDOWS)
#include <sys/socket.h>
#else /* not WINDOWS */
#include <winsock2.h>
#endif /* not WINDOWS */
#include <vector>
#include <functional>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>
#include "authenticate.h"
#include "error_manager.h"
#include "memory_alloc.h"
#include "dbtype.h"
#include "parser.h"
#include "parser_message.h"
#include "object_domain.h"
#include "object_primitive.h"
#include "object_representation.h"
#include "db.h"
#include "object_accessor.h"
#include "set_object.h"
#include "locator_cl.h"
#include "transaction_cl.h"
#include "schema_manager.h"
#include "numeric_opfunc.h"
#include "jsp_cl.h"
#include "system_parameter.h"
#include "network_interface_cl.h"
#include "unicode_support.h"
#include "dbtype.h"
#include "pl_comm.h"
#include "pl_struct_compile.hpp"
#include "sp_catalog.hpp"
#include "authenticate_access_auth.hpp"
#include "pl_signature.hpp"
#include "oid.h"
#include "string_buffer.hpp"
#include "db_value_printer.hpp"
#include "execute_statement.h"
#define PT_NODE_SP_NAME(node) \
(((node)->info.sp.name == NULL) ? "" : \
(node)->info.sp.name->info.name.original)
#define PT_NODE_SP_TYPE(node) \
((node)->info.sp.type)
#define PT_NODE_SP_RETURN_TYPE(node) \
((node)->info.sp.ret_type->info.name.original)
#define PT_NODE_SP_BODY(node) \
((node)->info.sp.body)
#define PT_NODE_SP_LANG(node) \
((node)->info.sp.body->info.sp_body.lang)
#define PT_NODE_SP_ARGS(node) \
((node)->info.sp.param_list)
#define PT_NODE_SP_IMPL(node) \
((node)->info.sp.body->info.sp_body.impl->info.value.data_value.str->bytes)
#define PT_NODE_SP_JAVA_METHOD(node) \
((node)->info.sp.body->info.sp_body.decl->info.value.data_value.str->bytes)
#define PT_NODE_SP_AUTHID(node) \
((node)->info.sp.auth_id)
#define PT_NODE_SP_DETERMINISTIC_TYPE(node) \
((node)->info.sp.dtrm_type)
#define PT_NODE_SP_COMMENT(node) \
(((node)->info.sp.comment == NULL) ? "" : \
(char *) (node)->info.sp.comment->info.value.data_value.str->bytes)
#define PT_NODE_SP_ARG_NAME(node) \
(((node)->info.sp_param.name == NULL) ? "" : \
(node)->info.sp_param.name->info.name.original)
#define PT_NODE_SP_ARG_COMMENT(node) \
(((node)->info.sp_param.comment == NULL) ? "" : \
(char *) (node)->info.sp_param.comment->info.value.data_value.str->bytes)
#define MAX_CALL_COUNT 16
#define MAX_ARG_COUNT 64
static int server_port = -1;
static int call_cnt = 0;
static bool is_prepare_call[MAX_CALL_COUNT] = { false, };
static SP_TYPE_ENUM jsp_map_pt_misc_to_sp_type (PT_MISC_TYPE pt_enum);
static SP_MODE_ENUM jsp_map_pt_misc_to_sp_mode (PT_MISC_TYPE pt_enum);
static PT_MISC_TYPE jsp_map_sp_type_to_pt_misc (SP_TYPE_ENUM sp_type);
static SP_DIRECTIVE_ENUM jsp_map_pt_to_sp_authid (PT_MISC_TYPE pt_authid);
static SP_DIRECTIVE_ENUM jsp_map_pt_to_sp_dtrm_type (PT_MISC_TYPE pt_dtrm_type, SP_DIRECTIVE_ENUM directive);
static char *jsp_check_stored_procedure_name (const char *str);
static int jsp_check_overflow_args (PARSER_CONTEXT *parser, PT_NODE *node, int num_params, int num_args);
static int jsp_check_out_param_in_query (PARSER_CONTEXT *parser, PT_NODE *node, int arg_mode);
static int jsp_check_param_type_supported (DB_TYPE type, int mode);
static int drop_stored_procedure (const char *name, SP_TYPE_ENUM expected_type);
static int drop_stored_procedure_code (const char *name);
static int jsp_default_value_string (PARSER_CONTEXT *parser, PT_NODE *node, std::string &out);
static int check_execute_authorization (const MOP sp_obj, const DB_AUTH au_type);
extern bool ssl_client;
/*
* jsp_is_exist_stored_procedure
* return: name is exist then return true
* else return false
* name(in): find java stored procedure name
*
* Note:
*/
int
jsp_is_exist_stored_procedure (const char *name)
{
MOP mop = NULL;
mop = jsp_find_stored_procedure (name, DB_AUTH_NONE);
er_clear ();
return mop != NULL;
}
/*
* jsp_find_stored_procedure
* return: MOP
* name(in): find java stored procedure name
* purpose(in): DB_AUTH_NONE or DB_AUTH_SELECT
*
* Note:
*/
MOP
jsp_find_stored_procedure (const char *name, DB_AUTH purpose)
{
MOP mop = NULL;
DB_VALUE value;
int save, err = NO_ERROR;
char *checked_name;
if (!name)
{
return NULL;
}
AU_DISABLE (save);
checked_name = jsp_check_stored_procedure_name (name);
db_make_string (&value, checked_name);
mop = db_find_unique (db_find_class (SP_CLASS_NAME), SP_ATTR_UNIQUE_NAME, &value);
if (er_errid () == ER_OBJ_OBJECT_NOT_FOUND)
{
er_clear ();
/* This is the case when the loaddb utility is executed with the --no-user-specified-name option as the dba user. */
if (db_client_type_is_loaddb_compat () /*latest compat client type */ )
{
err = jsp_find_sp_of_another_owner (checked_name, &mop);
}
else
{
err = ER_SP_NOT_EXIST;
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, err, 1, checked_name);
}
}
if (mop)
{
err = check_execute_authorization (mop, purpose);
}
if (err != NO_ERROR)
{
mop = NULL;
}
free_and_init (checked_name);
AU_ENABLE (save);
return mop;
}
/*
* jsp_find_stored_procedure_code
* return: MOP
* name(in): find java stored procedure name
*
* Note:
*/
MOP
jsp_find_stored_procedure_code (const char *name)
{
MOP mop = NULL;
DB_VALUE value;
int save;
if (!name)
{
return NULL;
}
AU_DISABLE (save);
db_make_string (&value, name);
mop = db_find_unique (db_find_class (SP_CODE_CLASS_NAME), SP_CODE_ATTR_NAME, &value);
if (er_errid () == ER_OBJ_OBJECT_NOT_FOUND)
{
er_clear ();
}
AU_ENABLE (save);
return mop;
}
/*
* jsp_find_sp_of_another_owner
* return: if fail return error code
* name(in): find java stored procedure name
* return_mop(in): retrieves the name of a java stored procedure and returns its MOP value.
*
* Note: This is a function for finding the unique_name of an SP when running the loaddb utility with the --no-user-specified-name option as a dba user.
*/
int
jsp_find_sp_of_another_owner (const char *name, MOP *return_mop)
{
int error = NO_ERROR;
DB_VALUE value;
char other_class_name[DB_MAX_IDENTIFIER_LENGTH];
other_class_name[0] = '\0';
*return_mop = NULL;
error = do_find_stored_procedure_by_query (name, other_class_name, DB_MAX_IDENTIFIER_LENGTH);
if (other_class_name[0] != '\0')
{
if (db_get_client_statement_type () == CUBRID_STMT_CREATE_STORED_PROCEDURE)
{
/* maybe unloaded from version 11.4+ or later */
db_set_client_type (DB_CLIENT_TYPE_LOADDB_UTILITY);
error = ER_SP_NOT_EXIST;
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, name);
return error;
}
db_make_string (&value, other_class_name);
*return_mop = db_find_unique (db_find_class (SP_CLASS_NAME), SP_ATTR_UNIQUE_NAME, &value);
if (er_errid () == ER_OBJ_OBJECT_NOT_FOUND)
{
error = ER_SP_NOT_EXIST;
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, other_class_name);
}
}
return error;
}
/*
* jsp_check_out_param_in_query
*
* Note:
*/
static int
jsp_check_out_param_in_query (PARSER_CONTEXT *parser, PT_NODE *node, int arg_mode)
{
int error = NO_ERROR;
assert ((node) && (node)->node_type == PT_METHOD_CALL);
if (node->info.method_call.call_or_expr != PT_IS_CALL_STMT)
{
// check out parameters
if (arg_mode != SP_MODE_IN)
{
PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_SP_OUT_ARGS_EXISTS_IN_QUERY,
node->info.method_call.method_name->info.name.original);
error = ER_PT_SEMANTIC;
}
}
return error;
}
/*
* jsp_check_param_type_supported
*
* Note:
*/
static int
jsp_check_param_type_supported (DB_TYPE type, int mode)
{
switch (type)
{
case DB_TYPE_INTEGER:
case DB_TYPE_FLOAT:
case DB_TYPE_DOUBLE:
case DB_TYPE_STRING:
case DB_TYPE_OBJECT:
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
case DB_TYPE_TIME:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_DATE:
case DB_TYPE_MONETARY:
case DB_TYPE_SHORT:
case DB_TYPE_NUMERIC:
case DB_TYPE_CHAR:
case DB_TYPE_BIGINT:
case DB_TYPE_DATETIME:
return NO_ERROR;
break;
case DB_TYPE_RESULTSET:
if (mode != SP_MODE_OUT)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_INPUT_RESULTSET, 0);
}
else if (!jsp_is_prepare_call ())
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_RETURN_RESULTSET, 0);
}
else
{
return NO_ERROR;
}
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_ARG_TYPE, 1, pr_type_name (type));
break;
}
return er_errid ();
}
/*
* jsp_check_return_type_supported
*
* Note:
*/
int
jsp_check_return_type_supported (DB_TYPE type)
{
switch (type)
{
case DB_TYPE_NULL:
case DB_TYPE_INTEGER:
case DB_TYPE_FLOAT:
case DB_TYPE_DOUBLE:
case DB_TYPE_STRING:
case DB_TYPE_OBJECT:
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE:
case DB_TYPE_TIME:
case DB_TYPE_TIMESTAMP:
case DB_TYPE_DATE:
case DB_TYPE_MONETARY:
case DB_TYPE_SHORT:
case DB_TYPE_NUMERIC:
case DB_TYPE_CHAR:
case DB_TYPE_BIGINT:
case DB_TYPE_DATETIME:
return NO_ERROR;
case DB_TYPE_RESULTSET:
if (!jsp_is_prepare_call ())
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_RETURN_RESULTSET, 0);
}
break;
default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_RETURN_TYPE, 1, pr_type_name (type));
break;
}
return er_errid ();
}
/*
* jsp_get_return_type - Return Java Stored Procedure Type
* return: if fail return error code
* else return Java Stored Procedure Type
* name(in): java stored procedure name
*
* Note:
*/
int
jsp_get_return_type (const char *name)
{
DB_OBJECT *mop_p;
DB_VALUE return_type;
int err;
int save;
AU_DISABLE (save);
mop_p = jsp_find_stored_procedure (name, DB_AUTH_NONE);
if (mop_p == NULL)
{
AU_ENABLE (save);
assert (er_errid () != NO_ERROR);
return er_errid ();
}
err = db_get (mop_p, SP_ATTR_RETURN_TYPE, &return_type);
if (err != NO_ERROR)
{
AU_ENABLE (save);
return err;
}
AU_ENABLE (save);
return db_get_int (&return_type);
}
/*
* jsp_get_sp_type - Return Java Stored Procedure Type
* return: if fail return error code
* else return Java Stored Procedure Type
* name(in): java stored procedure name
*
* Note:
*/
int
jsp_get_sp_type (const char *name)
{
DB_OBJECT *mop_p;
DB_VALUE sp_type_val;
int err;
int save;
AU_DISABLE (save);
mop_p = jsp_find_stored_procedure (name, DB_AUTH_NONE);
if (mop_p == NULL)
{
AU_ENABLE (save);
assert (er_errid () != NO_ERROR);
return er_errid ();
}
/* check type */
err = db_get (mop_p, SP_ATTR_SP_TYPE, &sp_type_val);
if (err != NO_ERROR)
{
AU_ENABLE (save);
return err;
}
AU_ENABLE (save);
return jsp_map_sp_type_to_pt_misc ((SP_TYPE_ENUM) db_get_int (&sp_type_val));
}
MOP
jsp_get_owner (MOP mop_p)
{
int save;
DB_VALUE value;
AU_DISABLE (save);
/* check type */
int err = db_get (mop_p, SP_ATTR_OWNER, &value);
if (err != NO_ERROR)
{
AU_ENABLE (save);
return NULL;
}
MOP owner = db_get_object (&value);
AU_ENABLE (save);
return owner;
}
char *
jsp_get_name (MOP mop_p)
{
int save;
DB_VALUE value;
char *res = NULL;
AU_DISABLE (save);
/* check type */
int err = db_get (mop_p, SP_ATTR_SP_NAME, &value);
if (err != NO_ERROR)
{
AU_ENABLE (save);
return NULL;
}
res = ws_copy_string (db_get_string (&value));
pr_clear_value (&value);
AU_ENABLE (save);
return res;
}
char *
jsp_get_unique_name (MOP mop_p, char *buf, int buf_size)
{
int save;
DB_VALUE value;
int err = NO_ERROR;
assert (buf != NULL);
assert (buf_size > 0);
if (mop_p == NULL)
{
ERROR_SET_WARNING (err, ER_SM_INVALID_ARGUMENTS);
buf[0] = '\0';
return NULL;
}
AU_DISABLE (save);
/* check type */
err = db_get (mop_p, SP_ATTR_UNIQUE_NAME, &value);
if (err != NO_ERROR)
{
AU_ENABLE (save);
return NULL;
}
strncpy (buf, db_get_string (&value), buf_size);
pr_clear_value (&value);
AU_ENABLE (save);
return buf;
}
/*
* jsp_get_owner_name - Return Java Stored Procedure'S Owner nmae
* return: if fail return MULL
* else return Java Stored Procedure Type
* name(in): java stored procedure name
*
* Note:
*/
char *
jsp_get_owner_name (const char *name, char *buf, int buf_size)
{
DB_OBJECT *mop_p;
DB_VALUE value;
int err;
int save;
assert (buf != NULL);
assert (buf_size > 0);
if (name == NULL || name[0] == '\0')
{
ERROR_SET_WARNING (err, ER_SM_INVALID_ARGUMENTS);
buf[0] = '\0';
return NULL;
}
AU_DISABLE (save);
mop_p = jsp_find_stored_procedure (name, DB_AUTH_NONE);
if (mop_p == NULL)
{
AU_ENABLE (save);
assert (er_errid () != NO_ERROR);
return NULL;
}
/* check type */
err = db_get (mop_p, SP_ATTR_OWNER, &value);
if (err != NO_ERROR)
{
AU_ENABLE (save);
return NULL;
}
MOP owner = db_get_object (&value);
if (owner != NULL)
{
DB_VALUE value2;
err = db_get (owner, "name", &value2);
if (err == NO_ERROR)
{
strncpy (buf, db_get_string (&value2), buf_size);
}
pr_clear_value (&value2);
}
pr_clear_value (&value);
AU_ENABLE (save);
return buf;
}
static PT_MISC_TYPE
jsp_map_sp_type_to_pt_misc (SP_TYPE_ENUM sp_type)
{
if (sp_type == SP_TYPE_PROCEDURE)
{
return PT_SP_PROCEDURE;
}
else
{
return PT_SP_FUNCTION;
}
}
static int
jsp_evaluate_arguments (PARSER_CONTEXT *parser, PT_NODE *statement,
std::vector <std::reference_wrapper <DB_VALUE>> &args)
{
assert (statement);
assert (statement->node_type == PT_METHOD_CALL);
PT_NODE *vc = statement->info.method_call.arg_list;
while (vc)
{
DB_VALUE *db_value;
/*
* Don't clone host vars; they may actually be acting as output variables (e.g., a character array that is
* intended to receive bytes from the method), and cloning will ensure that the results never make it to the
* expected area. Since pt_evaluate_tree() always clones its db_values we must not use pt_evaluate_tree() to
* extract the db_value from a host variable; instead extract it ourselves. */
if (PT_IS_CONST (vc))
{
db_value = pt_value_to_db (parser, vc);
}
else
{
db_value = (DB_VALUE *) malloc (sizeof (DB_VALUE));
if (db_value == NULL)
{
goto exit_on_error;
}
db_make_null (db_value);
/* must call pt_evaluate_tree */
pt_evaluate_tree_having_serial (parser, vc, db_value, 1);
if (pt_has_error (parser))
{
/* to maintain the list to free all the allocated */
db_value_clear (db_value);
goto exit_on_error;
}
}
args.emplace_back (std::ref (*db_value));
vc = vc->next;
}
return NO_ERROR;
exit_on_error:
for (DB_VALUE &val : args)
{
db_value_clear (&val);
}
args.clear ();
return ER_FAILED;
}
/*
* jsp_call_stored_procedure - call java stored procedure in constant folding
* return: call jsp failed return error code
* parser(in/out): parser environment
* statement(in): a statement node
*
* Note:
*/
int
jsp_call_stored_procedure (PARSER_CONTEXT *parser, PT_NODE *statement)
{
int error = NO_ERROR;
PT_NODE *method;
const char *method_name;
if (!statement || ! (method = statement->info.method_call.method_name) || method->node_type != PT_NAME)
{
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0);
return er_errid ();
}
DB_VALUE ret_value;
db_make_null (&ret_value);
/* call sp */
std::vector <std::reference_wrapper <DB_VALUE>> args;
cubpl::pl_signature sig;
error = jsp_make_pl_signature (parser, statement, NULL, sig);
if (error == NO_ERROR)
{
PT_NODE *default_next_node_list = jsp_get_default_expr_node_list (parser, sig);
if (default_next_node_list != NULL)
{
error = qp_get_server_info (parser, SI_SYS_DATETIME);
}
statement->info.method_call.arg_list = parser_append_node (default_next_node_list,
statement->info.method_call.arg_list);
error = jsp_evaluate_arguments (parser, statement, args);
if (pt_has_error (parser))
{
pt_report_to_ersys (parser, PT_SEMANTIC);
error = er_errid ();
}
}
if (error == NO_ERROR && locator_get_sig_interrupt () == 0)
{
std::vector <DB_VALUE> out_args;
error = pl_call (sig, args, out_args, ret_value);
if (error == NO_ERROR)
{
for (int i = 0, j = 0; i < sig.arg.arg_size; i++)
{
if (sig.arg.arg_mode[i] == SP_MODE_IN)
{
continue;
}
DB_VALUE &arg = args[i];
DB_VALUE &out_arg = out_args[j++];
db_value_clear (&arg);
db_value_clone (&out_arg, &arg);
db_value_clear (&out_arg);
}
}
}
PT_NODE *vc = statement->info.method_call.arg_list;
for (int i = 0; i < (int) args.size () && vc; i++)
{
if (!PT_IS_CONST (vc))
{
DB_VALUE &arg = args[i];
db_value_clear (&arg);
free (&arg);
}
vc = vc->next;
}
if (error == NO_ERROR)
{
/* Save the method result and its domain */
statement->etc = (void *) db_value_copy (&ret_value);
statement = pt_bind_type_from_dbval (parser, statement, &ret_value);
PT_NODE *into = statement->info.method_call.to_return_var;
const char *into_label;
if (into != NULL && into->node_type == PT_NAME && (into_label = into->info.name.original) != NULL)
{
/* create another DB_VALUE of the new instance for the label_table */
DB_VALUE *ins_value = db_value_copy (&ret_value);
error = pt_associate_label_with_value_check_reference (into_label, ins_value);
}
}
#if defined (CS_MODE)
db_value_clear (&ret_value);
#endif
return error;
}
/*
* jsp_drop_stored_procedure - drop java stored procedure
* return: Error code
* parser(in/out): parser environment
* statement(in): a statement node
*
* Note:
*/
int
jsp_drop_stored_procedure (PARSER_CONTEXT *parser, PT_NODE *statement)
{
const char *name;
PT_MISC_TYPE type;
PT_NODE *name_list, *p;
int i;
int err = NO_ERROR;
CHECK_MODIFICATION_ERROR ();
if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0);
return ER_BLOCK_DDL_STMT;
}
name_list = statement->info.sp.name;
type = PT_NODE_SP_TYPE (statement);
for (p = name_list, i = 0; p != NULL; p = p->next)
{
name = (char *) p->info.name.original;
if (name == NULL || name[0] == '\0')
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_NAME, 0);
return er_errid ();
}
err = drop_stored_procedure (name, jsp_map_pt_misc_to_sp_type (type));
if (err != NO_ERROR)
{
break;
}
}
return err;
}
/*
* jsp_default_value_string
* return:
* parser(in/out): parser environment
* statement(in): a default_value node
*
* Note:
*/
static int
jsp_default_value_string (PARSER_CONTEXT *parser, PT_NODE *node, bool &is_null, std::string &out)
{
int error = NO_ERROR;
is_null = false;
DB_DEFAULT_EXPR default_expr;
pt_get_default_expression_from_data_default_node (parser, node, &default_expr);
out.clear ();
if (default_expr.default_expr_type != DB_DEFAULT_NONE)
{
if (default_expr.default_expr_type == NULL_DEFAULT_EXPRESSION_OPERATOR)
{
DB_VALUE *value = pt_value_to_db (parser, node->info.data_default.default_value);
if (!DB_IS_NULL (value))
{
string_buffer sb;
sb.clear ();
db_sprint_value (value, sb);
out.append (sb.get_buffer ());
}
else
{
// empty out consider as NULL
is_null = true;
}
}
else
{
if (default_expr.default_expr_op == T_TO_CHAR)
{
out.append ("TO_CHAR(");
}
const char *default_value_expr_type_string = db_default_expression_string (default_expr.default_expr_type);
if (default_value_expr_type_string != NULL)
{
out.append (default_value_expr_type_string);
}
else
{
out.append (parser_print_tree (parser, node));
}
if (default_expr.default_expr_op == T_TO_CHAR)
{
if (default_expr.default_expr_format != NULL)
{
out.append (", \'");
out.append (default_expr.default_expr_format);
out.append ("\'");
}
out.append (")");
}
}
}
else
{
PT_NODE *default_value = node->info.data_default.default_value;
DB_VALUE *value = NULL;
// do not use initialized db value
if (default_value->info.value.db_value_is_initialized)
{
default_value->info.value.db_value_is_initialized = false;
}
value = pt_value_to_db (parser, default_value);
if (!DB_IS_NULL (value))
{
if (TP_IS_CHAR_TYPE (db_value_domain_type (value)))
{
if (db_get_string_size (value) > 255)
{
pt_reset_error (parser);
PT_ERRORm (parser, default_value, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_SP_PARAM_DEFAULT_STR_TOO_BIG);
return ER_SP_PARAM_DEFAULT_STR_TOO_BIG;
}
out.append (db_get_string (value));
}
else
{
DB_VALUE tmp_val;
error = db_value_coerce (value, &tmp_val, db_type_to_db_domain (DB_TYPE_VARCHAR));
if (error == NO_ERROR)
{
out.append (db_get_string (&tmp_val));
db_value_clear (&tmp_val);
}
}
}
else
{
// empty out is considered NULL
is_null = true;
}
}
return error;
}
/*
* jsp_create_stored_procedure
* return: if failed return error code else execute jsp_add_stored_procedure
* function
* parser(in/out): parser environment
* statement(in): a statement node
*
* Note:
*/
int
jsp_create_stored_procedure (PARSER_CONTEXT *parser, PT_NODE *statement)
{
const char *decl = NULL, *comment = NULL;
char owner_name[DB_MAX_USER_LENGTH];
owner_name[0] = '\0';
PT_NODE *param_list, *p;
PT_TYPE_ENUM ret_type = PT_TYPE_NONE;
int lang;
int err = NO_ERROR;
bool has_savepoint = false;
PLCSQL_COMPILE_REQUEST compile_request;
PLCSQL_COMPILE_RESPONSE compile_response;
SP_INFO sp_info;
char *temp;
DB_VALUE current_datetime;
CHECK_MODIFICATION_ERROR ();
if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0);
return ER_BLOCK_DDL_STMT;
}
// check PL/CSQL's AUTHID with CURRENT_USER
sp_info.directive = jsp_map_pt_to_sp_authid (PT_NODE_SP_AUTHID (statement));
sp_info.lang = (SP_LANG_ENUM) PT_NODE_SP_LANG (statement);
if (sp_info.directive == SP_DIRECTIVE_RIGHTS_CALLER && sp_info.lang == SP_LANG_PLCSQL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVOKERS_RIGHTS_NOT_SUPPORTED, 0);
return er_errid ();
}
temp = jsp_check_stored_procedure_name (PT_NODE_SP_NAME (statement));
sp_info.unique_name = temp;
free (temp);
if (sp_info.unique_name.empty ())
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_NAME, 0);
return er_errid ();
}
sp_info.sp_name = sm_remove_qualifier_name (sp_info.unique_name.data ());
if (sp_info.sp_name.empty ())
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_NAME, 0);
return er_errid ();
}
sp_info.sp_type = jsp_map_pt_misc_to_sp_type (PT_NODE_SP_TYPE (statement));
if (sp_info.sp_type == SP_TYPE_FUNCTION)
{
sp_info.return_type = pt_type_enum_to_db (statement->info.sp.ret_type);
// check the deterministic_type of function
sp_info.directive = jsp_map_pt_to_sp_dtrm_type (PT_NODE_SP_DETERMINISTIC_TYPE (statement), sp_info.directive);
}
else
{
sp_info.return_type = DB_TYPE_NULL;
}
// set rows for _db_stored_procedure_args
int param_count = 0;
param_list = PT_NODE_SP_ARGS (statement);
for (p = param_list; p != NULL; p = p->next)
{
SP_ARG_INFO arg_info (sp_info.unique_name);
arg_info.index_of = param_count++;
arg_info.arg_name = PT_NODE_SP_ARG_NAME (p);
arg_info.data_type = pt_type_enum_to_db (p->type_enum);
arg_info.mode = jsp_map_pt_misc_to_sp_mode (p->info.sp_param.mode);
// default value
// coerciable is already checked in semantic_check
PT_NODE *default_value = p->info.sp_param.default_value;
if (default_value)
{
bool is_null;
std::string default_value_str;
if (jsp_default_value_string (parser, default_value, is_null, default_value_str) == NO_ERROR)
{
if (!is_null)
{
db_make_string (&arg_info.default_value, ws_copy_string (default_value_str.c_str ()));
}
else
{
db_make_null (&arg_info.default_value);
}
arg_info.is_optional = true;
}
else
{
// MSGCAT_SEMANTIC_PREC_TOO_BIG
goto error_exit;
}
}
else
{
db_make_null (&arg_info.default_value);
arg_info.is_optional = false; // explicitly
}
arg_info.comment = (char *) PT_NODE_SP_ARG_COMMENT (p);
// check # of args constraint
if (param_count > MAX_ARG_COUNT)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_TOO_MANY_ARG_COUNT, 1, sp_info.unique_name.data ());
goto error_exit;
}
sp_info.args.push_back (arg_info);
}
if (sm_qualifier_name (sp_info.unique_name.data (), owner_name, DB_MAX_USER_LENGTH) == NULL)
{
ASSERT_ERROR ();
goto error_exit;
}
sp_info.owner = owner_name[0] == '\0' ? Au_user : db_find_user (owner_name);
if (sp_info.owner == NULL)
{
// for safeguard: it is already checked in pt_check_create_stored_procedure ()
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_INVALID_USER_NAME, 1, owner_name);
goto error_exit;
}
if (sp_info.lang == SP_LANG_PLCSQL)
{
assert (statement->sql_user_text && statement->sql_user_text_len);
compile_request.code.assign (statement->sql_user_text, statement->sql_user_text_len);
compile_request.owner.assign ((owner_name[0] == '\0') ? au_get_current_user_name () : owner_name);
// TODO: Only the owner's rights is supported for PL/CSQL
au_perform_push_user (sp_info.owner);
err = plcsql_transfer_file (compile_request, compile_response);
au_perform_pop_user ();
if (err == NO_ERROR && compile_response.err_code == NO_ERROR)
{
decl = compile_response.java_signature.c_str ();
}
else
{
err = ER_SP_COMPILE_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_COMPILE_ERROR, 1, compile_response.err_msg.c_str ());
pt_record_error (parser, parser->statement_number, compile_response.err_line, compile_response.err_column, er_msg (),
NULL);
goto error_exit;
}
}
else /* SP_LANG_JAVA */
{
decl = (const char *) PT_NODE_SP_JAVA_METHOD (statement);
}
if (decl)
{
std::string target = decl;
sp_split_target_signature (target, sp_info.target_class, sp_info.target_method);
}
sp_info.comment = (char *) PT_NODE_SP_COMMENT (statement);
if (db_sys_datetime (¤t_datetime) != NO_ERROR)
{
goto error_exit;
}
sp_info.created_time = *db_get_datetime (¤t_datetime);
sp_info.updated_time = *db_get_datetime (¤t_datetime);
/* check already exists */
if (jsp_is_exist_stored_procedure (sp_info.unique_name.data ()))
{
if (statement->info.sp.or_replace)
{
/* drop existing stored procedure */
err = tran_system_savepoint (SAVEPOINT_CREATE_STORED_PROC);
if (err != NO_ERROR)
{
return err;
}
has_savepoint = true;
err = drop_stored_procedure (sp_info.unique_name.data (), sp_info.sp_type);
if (err != NO_ERROR)
{
goto error_exit;
}
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_ALREADY_EXIST, 1, sp_info.unique_name.data ());
goto error_exit;
}
}
err = sp_add_stored_procedure (sp_info);
if (err != NO_ERROR)
{
goto error_exit;
}
if (!compile_request.code.empty ())
{
assert (sp_info.lang == SP_LANG_PLCSQL);
SP_CODE_INFO code_info;
auto now = std::chrono::system_clock::now();
auto converted_timep = std::chrono::system_clock::to_time_t (now);
std::stringstream stm;
stm << std::put_time (localtime (&converted_timep), "%Y%m%d%H%M%S");
// CBRD-26513, CBRD-26514: rewrite the user code without the user name and the comment
const char *rewritten_code;
{
int custom_print_saved = parser->custom_print;
parser->custom_print |= PT_PRINT_NO_SPECIFIED_USER_NAME;
parser->flag.is_unloading_plcsql_def = 1;
rewritten_code = parser_print_tree (parser, statement);
parser->flag.is_unloading_plcsql_def = 0;
parser->custom_print = custom_print_saved;
}
code_info.name = sp_info.target_class;
code_info.created_time = stm.str ();
code_info.stype = SPSC_PLCSQL;
code_info.scode.assign (rewritten_code, strlen (rewritten_code));
code_info.otype = compile_response.compiled_type;
code_info.ocode = compile_response.compiled_code;
code_info.owner = sp_info.owner;
err = sp_add_stored_procedure_code (code_info);
if (err != NO_ERROR)
{
goto error_exit;
}
}
return NO_ERROR;
error_exit:
if (has_savepoint)
{
tran_abort_upto_system_savepoint (SAVEPOINT_CREATE_STORED_PROC);
}
return (err == NO_ERROR) ? er_errid () : err;
}
/*
* jsp_alter_stored_procedure
* return: if failed return error code else NO_ERROR
* parser(in/out): parser environment
* statement(in): a statement node
*
* Note:
*/
int
jsp_alter_stored_procedure (PARSER_CONTEXT *parser, PT_NODE *statement)
{
int err = NO_ERROR, sp_recompile, save, lang;
PT_NODE *sp_name = NULL, *sp_owner = NULL, *sp_comment = NULL;
const char *name_str = NULL, *owner_str = NULL, *comment_str = NULL, *target_cls = NULL;
char downcase_owner_name[DB_MAX_USER_LENGTH];
downcase_owner_name[0] = '\0';
PT_MISC_TYPE type;
SP_TYPE_ENUM real_type;
MOP sp_mop = NULL, new_owner_mop = NULL, owner_mop = NULL;
DB_VALUE user_val, sp_type_val, sp_lang_val, target_cls_val;
assert (statement != NULL);
CHECK_MODIFICATION_ERROR ();
if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0);
return ER_BLOCK_DDL_STMT;
}
db_make_null (&user_val);
db_make_null (&sp_type_val);
db_make_null (&sp_lang_val);
db_make_null (&target_cls_val);
type = PT_NODE_SP_TYPE (statement);
sp_name = statement->info.sp.name;
assert (sp_name != NULL);
sp_owner = statement->info.sp.owner;
sp_recompile = statement->info.sp.recompile;
sp_comment = statement->info.sp.comment;
assert (sp_owner != NULL || sp_comment != NULL || sp_recompile);
name_str = sp_name->info.name.original;
assert (name_str != NULL);
if (sp_owner != NULL)
{
owner_str = sp_owner->info.name.original;
assert (owner_str != NULL);
}
comment_str = (char *) PT_NODE_SP_COMMENT (statement);
AU_DISABLE (save);
/* existence of sp */
sp_mop = jsp_find_stored_procedure (name_str, DB_AUTH_SELECT);
if (sp_mop == NULL)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto error;
}
/* check type */
err = db_get (sp_mop, SP_ATTR_SP_TYPE, &sp_type_val);
if (err != NO_ERROR)
{
goto error;
}
real_type = (SP_TYPE_ENUM) db_get_int (&sp_type_val);
if (real_type != jsp_map_pt_misc_to_sp_type (type))
{
err = ER_SP_INVALID_TYPE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 2, name_str,
real_type == SP_TYPE_FUNCTION ? "FUNCTION" : "PROCEDURE");
goto error;
}
/* change the owner */
if (sp_owner != NULL)
{
/* existence of new owner */
new_owner_mop = db_find_user (owner_str);
if (new_owner_mop == NULL)
{
err = ER_OBJ_OBJECT_NOT_FOUND;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, owner_str);
goto error;
}
err = au_change_sp_owner_with_transfer_privileges (parser, sp_mop, new_owner_mop);
if (err != NO_ERROR)
{
goto error;
}
}
/* authentication */
owner_mop = jsp_get_owner (sp_mop);
if (owner_mop == NULL)
{
err = ER_FAILED;
goto error;
}
if (!ws_is_same_object (owner_mop, Au_user) && !au_is_dba_group_member (Au_user))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DDL_NOT_ALLOWED_PRIVILEGES, 1, "alter");
err = er_errid ();
goto error;
}
/* pl/csql compile */
if (sp_recompile)
{
/* check lang */
err = db_get (sp_mop, SP_ATTR_LANG, &sp_lang_val);
if (err != NO_ERROR)
{
goto error;
}
lang = db_get_int (&sp_lang_val);
if (lang == SP_LANG_PLCSQL)
{
err = db_get (sp_mop, SP_ATTR_TARGET_CLASS, &target_cls_val);
if (err != NO_ERROR)
{
goto error;
}
target_cls = db_get_string (&target_cls_val);
owner_str = sm_qualifier_name (name_str, downcase_owner_name, DB_MAX_USER_LENGTH);
err = alter_stored_procedure_code (parser, sp_mop, target_cls, owner_str, sp_recompile);
if (err != NO_ERROR)
{
goto error;
}
}
}
/* change the comment */
if (sp_comment != NULL)
{
db_make_string (&user_val, comment_str);
err = obj_set (sp_mop, SP_ATTR_COMMENT, &user_val);
if (err != NO_ERROR)
{
goto error;
}
}
err = db_update_obj_timestamp (sp_mop);
if (err != NO_ERROR)
{
goto error;
}
error:
pr_clear_value (&user_val);
pr_clear_value (&sp_type_val);
pr_clear_value (&sp_lang_val);
pr_clear_value (&target_cls_val);
AU_ENABLE (save);
return err;
}
/*
* jsp_map_pt_misc_to_sp_type
* return : stored procedure type ( Procedure or Function )
* pt_enum(in): Misc Types
*
* Note:
*/
static SP_TYPE_ENUM
jsp_map_pt_misc_to_sp_type (PT_MISC_TYPE pt_enum)
{
if (pt_enum == PT_SP_PROCEDURE)
{
return SP_TYPE_PROCEDURE;
}
else
{
return SP_TYPE_FUNCTION;
}
}
/*
* jsp_map_pt_misc_to_sp_mode
* return : stored procedure mode ( input or output or inout )
* pt_enum(in) : Misc Types
*
* Note:
*/
static SP_MODE_ENUM
jsp_map_pt_misc_to_sp_mode (PT_MISC_TYPE pt_enum)
{
if (pt_enum == PT_INPUT || pt_enum == PT_NOPUT)
{
return SP_MODE_IN;
}
else if (pt_enum == PT_OUTPUT)
{
return SP_MODE_OUT;
}
else
{
return SP_MODE_INOUT;
}
}
static SP_DIRECTIVE_ENUM
jsp_map_pt_to_sp_authid (PT_MISC_TYPE pt_authid)
{
assert (pt_authid == PT_AUTHID_OWNER || pt_authid == PT_AUTHID_CALLER);
return (pt_authid == PT_AUTHID_OWNER ? SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_OWNER :
SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_CALLER);
}
static SP_DIRECTIVE_ENUM
jsp_map_pt_to_sp_dtrm_type (PT_MISC_TYPE pt_dtrm_type, SP_DIRECTIVE_ENUM directive)
{
assert (pt_dtrm_type == PT_NOT_DETERMINISTIC || pt_dtrm_type == PT_DETERMINISTIC);
if (pt_dtrm_type == PT_DETERMINISTIC)
{
directive = static_cast<SP_DIRECTIVE_ENUM> (static_cast<int> (directive) | static_cast<int>
(SP_DIRECTIVE_ENUM::SP_DIRECTIVE_DETERMINISTIC));
}
return directive;
}
/*
* jsp_check_stored_procedure_name -
* return: java stored procedure name
* str(in) :
*
* Note: convert lowercase
*/
static char *
jsp_check_stored_procedure_name (const char *str)
{
char buffer[SM_MAX_IDENTIFIER_LENGTH + 2];
char tmp[SM_MAX_IDENTIFIER_LENGTH + 2];
char *name = NULL;
static const int dbms_output_len = strlen ("dbms_output.");
if (strncasecmp (str, "dbms_output.", dbms_output_len) == 0)
{
sprintf (buffer, "public.dbms_output.%s",
sm_downcase_name (str + dbms_output_len, tmp, SM_MAX_IDENTIFIER_LENGTH));
}
else
{
sm_user_specified_name (str, buffer, SM_MAX_IDENTIFIER_LENGTH);
}
name = strdup (buffer);
return name;
}
/*
* drop_stored_procedure -
* return: Error code
* name(in): jsp name
* expected_type(in):
*
* Note:
*/
static int
drop_stored_procedure (const char *name, SP_TYPE_ENUM expected_type)
{
MOP sp_mop, arg_mop, owner, save_user;
DB_VALUE sp_type_val, arg_cnt_val, args_val, owner_val, generated_val, target_cls_val, lang_val, temp;
SP_TYPE_ENUM real_type;
std::string class_name;
const char *target_cls;
DB_SET *arg_set_p;
int save, i, arg_cnt, lang;
int err;
char unique_name[DB_MAX_IDENTIFIER_LENGTH + 1];
unique_name[0] = '\0';
AU_DISABLE (save);
db_make_null (&args_val);
db_make_null (&owner_val);
sp_mop = jsp_find_stored_procedure (name, DB_AUTH_SELECT);
if (sp_mop == NULL)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto error;
}
err = db_get (sp_mop, SP_ATTR_OWNER, &owner_val);
if (err != NO_ERROR)
{
goto error;
}
owner = db_get_object (&owner_val);
if (!ws_is_same_object (owner, Au_user) && !au_is_dba_group_member (Au_user))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DDL_NOT_ALLOWED_PRIVILEGES, 1, "drop");
err = er_errid ();
goto error;
}
err = db_get (sp_mop, SP_ATTR_IS_SYSTEM_GENERATED, &generated_val);
if (err != NO_ERROR)
{
goto error;
}
if (1 == db_get_int (&generated_val))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DROP_NOT_ALLOWED_SYSTEM_GENERATED, 0);
err = er_errid ();
goto error;
}
err = db_get (sp_mop, SP_ATTR_SP_TYPE, &sp_type_val);
if (err != NO_ERROR)
{
goto error;
}
real_type = (SP_TYPE_ENUM) db_get_int (&sp_type_val);
if (real_type != expected_type)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_TYPE, 2, name,
real_type == SP_TYPE_FUNCTION ? "FUNCTION" : "PROCEDURE");
err = er_errid ();
goto error;
}
// delete _db_stored_procedure_code
err = db_get (sp_mop, SP_ATTR_LANG, &lang_val);
if (err != NO_ERROR)
{
goto error;
}
lang = db_get_int (&lang_val);
if (lang == SP_LANG_PLCSQL)
{
err = db_get (sp_mop, SP_ATTR_TARGET_CLASS, &target_cls_val);
if (err != NO_ERROR)
{
goto error;
}
target_cls = db_get_string (&target_cls_val);
err = drop_stored_procedure_code (target_cls);
if (err != NO_ERROR)
{
goto error;
}
}
err = db_get (sp_mop, SP_ATTR_ARG_COUNT, &arg_cnt_val);
if (err != NO_ERROR)
{
goto error;
}
arg_cnt = db_get_int (&arg_cnt_val);
err = db_get (sp_mop, SP_ATTR_ARGS, &args_val);
if (err != NO_ERROR)
{
goto error;
}
arg_set_p = db_get_set (&args_val);
for (i = 0; i < arg_cnt; i++)
{
set_get_element (arg_set_p, i, &temp);
arg_mop = db_get_object (&temp);
err = obj_delete (arg_mop);
pr_clear_value (&temp);
if (err != NO_ERROR)
{
goto error;
}
}
/* before deleting an object, all permissions are revoked. */
if (jsp_get_unique_name (sp_mop, unique_name, DB_MAX_IDENTIFIER_LENGTH) == NULL)
{
assert (er_errid () != NO_ERROR);
}
save_user = Au_user;
if (AU_SET_USER (owner) == NO_ERROR)
{
err = au_object_revoke_all_privileges (DB_OBJECT_PROCEDURE, owner, unique_name);
if (err != NO_ERROR)
{
AU_SET_USER (save_user);
goto error;
}
}
AU_SET_USER (save_user);
err = au_delete_auth_of_dropping_database_object (DB_OBJECT_PROCEDURE, name);
if (err != NO_ERROR)
{
goto error;
}
err = obj_delete (sp_mop);
error:
AU_ENABLE (save);
pr_clear_value (&args_val);
pr_clear_value (&owner_val);
return err;
}
/*
* drop_stored_procedure_code -
* return: Error code
* name(in): jsp name
*
* Note:
*/
static int
drop_stored_procedure_code (const char *name)
{
MOP code_mop, owner;
DB_VALUE owner_val, generated_val;
int save;
int err;
AU_DISABLE (save);
db_make_null (&owner_val);
code_mop = jsp_find_stored_procedure_code (name);
if (code_mop == NULL)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto error;
}
err = db_get (code_mop, SP_ATTR_OWNER, &owner_val);
if (err != NO_ERROR)
{
goto error;
}
owner = db_get_object (&owner_val);
if (!ws_is_same_object (owner, Au_user) && !au_is_dba_group_member (Au_user))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DDL_NOT_ALLOWED_PRIVILEGES, 1, "drop");
err = er_errid ();
goto error;
}
err = db_get (code_mop, SP_ATTR_IS_SYSTEM_GENERATED, &generated_val);
if (err != NO_ERROR)
{
goto error;
}
if (!DB_IS_NULL (&generated_val) && 1 == db_get_int (&generated_val))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DROP_NOT_ALLOWED_SYSTEM_GENERATED, 0);
err = er_errid ();
goto error;
}
// TODO: If a unreloadable SP is deleted, mark a flag in PL server to block calling the deleted SP
err = obj_delete (code_mop);
error:
AU_ENABLE (save);
pr_clear_value (&owner_val);
return err;
}
/*
* alter_stored_procedure_code -
* return: Error code
* name(in): jsp name
*
* Note:
*/
int
alter_stored_procedure_code (PARSER_CONTEXT *parser, MOP sp_mop, const char *name, const char *owner_str,
int sp_recompile)
{
const char *scode = NULL, *decl = NULL;
int scode_len, save, err;
MOP code_mop;
DB_VALUE scode_val, value;
PLCSQL_COMPILE_REQUEST compile_request;
PLCSQL_COMPILE_RESPONSE compile_response;
SP_INFO sp_info;
SP_CODE_INFO code_info;
DB_OBJECT *object_p;
DB_OTMPL *obt_p = NULL;
AU_DISABLE (save);
db_make_null (&scode_val);
db_make_null (&value);
code_mop = jsp_find_stored_procedure_code (name);
if (code_mop == NULL)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto error;
}
err = db_get (code_mop, SP_CODE_ATTR_SCODE, &scode_val);
if (err != NO_ERROR)
{
goto error;
}
scode = db_get_string (&scode_val);
scode_len = db_get_string_size (&scode_val);
sp_info.owner = db_find_user (owner_str);
assert (scode && scode_len);
compile_request.code.assign (scode, scode_len);
compile_request.owner.assign (owner_str);
pr_clear_value (&scode_val);
// TODO: Only the owner's rights is supported for PL/CSQL
au_perform_push_user (sp_info.owner);
err = plcsql_transfer_file (compile_request, compile_response);
au_perform_pop_user ();
if (err == NO_ERROR && compile_response.err_code == NO_ERROR)
{
decl = compile_response.java_signature.c_str ();
}
else
{
if (err == NO_ERROR && compile_response.err_code == NO_ERROR)
{
decl = compile_response.java_signature.c_str ();
}
else
{
err = ER_SP_COMPILE_ERROR;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_COMPILE_ERROR, 1, compile_response.err_msg.c_str ());
pt_record_error (parser, parser->statement_number, compile_response.err_line, compile_response.err_column, er_msg (),
NULL);
goto error;
}
}
if (decl)
{
std::string target = decl;
sp_split_target_signature (target, sp_info.target_class, sp_info.target_method);
}
code_info.name = sp_info.target_class;
code_info.ocode = compile_response.compiled_code;
if (sp_recompile == 1)
{
/* recompile */
code_info.owner = NULL;
}
else
{
/* owner to */
code_info.owner = sp_info.owner;
}
err = sp_edit_stored_procedure_code (code_mop, code_info);
if (err != NO_ERROR)
{
goto error;
}
/* Update the target_class column in the _db_stored_procedure catalog. */
obt_p = dbt_edit_object (sp_mop);
if (obt_p == NULL)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto error;
}
db_make_string (&value, sp_info.target_class.data ());
err = dbt_put_internal (obt_p, SP_ATTR_TARGET_CLASS, &value);
pr_clear_value (&value);
if (err != NO_ERROR)
{
goto error;
}
db_make_string (&value, sp_info.target_method.data ());
err = dbt_put_internal (obt_p, SP_ATTR_TARGET_METHOD, &value);
pr_clear_value (&value);
if (err != NO_ERROR)
{
goto error;
}
err = db_update_otmpl_timestamp (obt_p);
if (err != NO_ERROR)
{
goto error;
}
object_p = dbt_finish_object (obt_p);
if (!object_p)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
goto error;
}
obt_p = NULL;
err = locator_flush_instance (object_p);
if (err != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
err = er_errid ();
obj_delete (object_p);
goto error;
}
error:
AU_ENABLE (save);
pr_clear_value (&scode_val);
pr_clear_value (&value);
return err;
}
/*
* jsp_set_prepare_call -
* return: none
*
* Note:
*/
void
jsp_set_prepare_call (void)
{
int depth = tran_get_libcas_depth ();
is_prepare_call[depth] = true;
}
/*
* jsp_unset_prepare_call -
* return: none
*
* Note:
*/
void
jsp_unset_prepare_call (void)
{
int depth = tran_get_libcas_depth ();
is_prepare_call[depth] = false;
}
/*
* jsp_is_prepare_call -
* return: bool
*
* Note:
*/
bool
jsp_is_prepare_call ()
{
int depth = tran_get_libcas_depth ();
return is_prepare_call[depth];
}
static int
jsp_check_overflow_args (PARSER_CONTEXT *parser, PT_NODE *node, int num_params, int num_args)
{
if (num_args > num_params)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_PARAM_COUNT, 2, num_params, num_args);
return er_errid ();
}
else if (num_args < num_params)
{
// there are trailing default arguments
return num_params - num_args;
}
return 0;
}
/*
* pt_to_method_arglist () - converts a parse expression tree list of
* method call arguments to method argument array
* return: A NULL on error occurred
* parser(in):
* target(in):
* node_list(in): should be parse name nodes
* subquery_as_attr_list(in):
*/
static int *
pt_to_method_arglist (PARSER_CONTEXT *parser, PT_NODE *target, PT_NODE *node_list, PT_NODE *subquery_as_attr_list)
{
int *arg_list = NULL;
int i = 1;
int num_args = pt_length_of_list (node_list) + 1;
PT_NODE *node;
arg_list = (int *) db_private_alloc (NULL, num_args);
if (!arg_list)
{
return NULL;
}
if (subquery_as_attr_list != NULL)
{
if (target != NULL)
{
/* the method call target is the first element in the array */
arg_list[0] = pt_find_attribute (parser, target, subquery_as_attr_list);
if (arg_list[0] == -1)
{
return NULL;
}
}
else
{
i = 0;
}
for (node = node_list; node != NULL; node = node->next)
{
arg_list[i] = pt_find_attribute (parser, node, subquery_as_attr_list);
if (arg_list[i] == -1)
{
return NULL;
}
i++;
}
}
else
{
for (node = node_list; node != NULL; node = node->next)
{
arg_list[i] = i;
i++;
}
}
return arg_list;
}
/*
* jsp_make_pl_signature () - converts a parse expression tree list of pl calls to pl_signature struct
* return: error_code
* parser(in):
* node_list(in): should be parse pl nodes
* subquery_as_attr_list(in):
* sig(out): pl_signature struct
*/
int
jsp_make_pl_signature (PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *subquery_as_attr_list, cubpl::pl_signature &sig)
{
int save = 0;
int error = NO_ERROR;
char user_name_buffer [DB_MAX_USER_LENGTH + 1];
DB_OBJECT *mop_p = NULL;
assert (node);
sp_entry entry (NUM_SP_ATTR);
{
PT_NODE *method_name_node = node->info.method_call.method_name;
const char *name;
if (PT_NAME_RESOLVED (method_name_node))
{
int custom_print_saved = parser->custom_print;
parser->custom_print |= PT_SUPPRESS_QUOTES;
parser->custom_print &= ~PT_PRINT_QUOTES;
name = parser_print_tree (parser, method_name_node);
parser->custom_print = custom_print_saved;
}
else
{
name = PT_NAME_ORIGINAL (method_name_node);
}
sig.name = db_private_strdup (NULL, name);
if (PT_IS_METHOD (node))
{
sig.type = PT_IS_CLASS_METHOD (node) ? PL_TYPE_CLASS_METHOD : PL_TYPE_INSTANCE_METHOD;
}
else
{
mop_p = jsp_find_stored_procedure (name, DB_AUTH_EXECUTE);
if (mop_p == NULL)
{
error = er_errid ();
assert (error != NO_ERROR);
goto exit;
}
AU_DISABLE (save);
entry.oid = *WS_OID (mop_p);
for (int i = 0; i < NUM_SP_ATTR; i++)
{
error = obj_get (mop_p, sp_get_entry_name (i).data (), &entry.vals[i]);
if (error != NO_ERROR)
{
goto exit;
}
}
int lang = db_get_int (&entry.vals[INDEX_SP_ATTR_LANG]);
sig.type = (lang == SP_LANG_PLCSQL) ? PL_TYPE_PLCSQL : PL_TYPE_JAVA_SP;
/* semantic check */
int directive = db_get_int (&entry.vals[INDEX_SP_ATTR_DIRECTIVE]);
const char *auth_name = (! (directive & SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_CALLER) ? jsp_get_owner_name (
name, user_name_buffer, DB_MAX_USER_LENGTH) : au_get_current_user_name ());
int result_type = db_get_int (&entry.vals[INDEX_SP_ATTR_RETURN_TYPE]);
error = jsp_check_return_type_supported ((DB_TYPE) result_type);
if (error != NO_ERROR)
{
goto exit;
}
// args
int num_params = db_get_int (&entry.vals[INDEX_SP_ATTR_ARG_COUNT]);
DB_SET *param_set = db_get_set (&entry.vals[INDEX_SP_ATTR_ARGS]);
error = jsp_make_pl_args (parser, node, num_params, param_set, sig);
if (error != NO_ERROR)
{
goto exit;
}
#if defined (CS_MODE)
sig.auth = db_private_strdup (NULL, auth_name);
if (directive & SP_DIRECTIVE_ENUM::SP_DIRECTIVE_DETERMINISTIC)
{
sig.is_deterministic = true;
}
else
{
sig.is_deterministic = false;
}
#endif
sig.result_type = result_type;
if (! (directive & SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_CALLER))
{
jsp_get_owner_name (name, user_name_buffer, DB_MAX_USER_LENGTH);
sig.auth = db_private_strndup (NULL, user_name_buffer, DB_MAX_USER_LENGTH);
}
else
{
sig.auth = db_private_strdup (NULL, au_get_current_user_name ());
}
}
// make pl_ext
if (PT_IS_METHOD (node))
{
PT_NODE *dt = node->info.method_call.on_call_target->data_type;
/* beware of virtual classes */
sig.ext.method.class_name = (dt->info.data_type.virt_object) ? (char *) db_get_class_name (
dt->info.data_type.virt_object) : (char *) dt->info.data_type.entity->info.name.original;
sig.arg.set_arg_size (pt_length_of_list (node->info.method_call.arg_list) + 1);
sig.ext.method.arg_pos = pt_to_method_arglist (parser, node->info.method_call.on_call_target,
node->info.method_call.arg_list, subquery_as_attr_list);
}
else
{
sig.ext.sp.target_class_name = db_private_strdup (NULL, db_get_string (&entry.vals[INDEX_SP_ATTR_TARGET_CLASS]));
sig.ext.sp.target_method_name = db_private_strdup (NULL, db_get_string (&entry.vals[INDEX_SP_ATTR_TARGET_METHOD]));
if (sig.ext.sp.target_class_name != NULL)
{
MOP code_mop = jsp_find_stored_procedure_code (sig.ext.sp.target_class_name);
if (code_mop)
{
sig.ext.sp.code_oid = *WS_OID (code_mop);
}
else
{
// Java SP
sig.ext.sp.code_oid = OID_INITIALIZER;
}
}
}
}
exit:
if (mop_p != NULL)
{
AU_ENABLE (save);
}
return error;
}
int
jsp_make_pl_args (PARSER_CONTEXT *parser, PT_NODE *node, int num_params, DB_SET *param_set, cubpl::pl_signature &sig)
{
int error = NO_ERROR;
DB_VALUE temp;
db_make_null (&temp);
{
sig.arg.set_arg_size (num_params);
// check default arguments
int num_args = pt_length_of_list (node->info.method_call.arg_list);
int num_trailing_default_args = jsp_check_overflow_args (parser, node, num_params, num_args);
if (num_trailing_default_args < 0)
{
error = er_errid ();
goto exit_on_error;
}
sp_entry entry (NUM_SP_ARG_ATTR);
for (int i = 0; i < num_params; i++)
{
set_get_element (param_set, i, &temp);
MOP arg_mop_p = db_get_object (&temp);
if (arg_mop_p == NULL)
{
error = er_errid ();
assert (error != NO_ERROR);
goto exit_on_error;
}
for (int i = 0; i < NUM_SP_ARG_ATTR; i++)
{
error = obj_get (arg_mop_p, sp_args_get_entry_name (i).data (), &entry.vals[i]);
if (error != NO_ERROR)
{
goto exit_on_error;
}
}
int arg_mode = db_get_int (&entry.vals[INDEX_SP_ARG_ATTR_MODE]);
error = jsp_check_out_param_in_query (parser, node, arg_mode);
if (error != NO_ERROR)
{
goto exit_on_error;
}
int arg_type = db_get_int (&entry.vals[INDEX_SP_ARG_ATTR_DATA_TYPE]);
error = jsp_check_param_type_supported ((DB_TYPE) arg_type, arg_mode);
if (error != NO_ERROR)
{
goto exit_on_error;
}
const char *default_value_str = NULL;
int default_value_size = PL_ARG_DEFAULT_NONE;
int num_required_args = num_params - num_trailing_default_args;
if (i >= num_required_args)
{
int is_optional = db_get_int (&entry.vals[INDEX_SP_ARG_ATTR_IS_OPTIONAL]);
if (is_optional == 1)
{
const DB_VALUE &default_val = entry.vals[INDEX_SP_ARG_ATTR_DEFAULT_VALUE];
if (!DB_IS_NULL (&default_val))
{
default_value_size = db_get_string_size (&default_val); // null character
if (default_value_size > 0)
{
default_value_str = db_get_string (&default_val);
}
}
else
{
default_value_size = PL_ARG_DEFAULT_NULL; // special value when default value is *NULL*
}
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_PARAM_COUNT, 2, num_params, num_args);
error = er_errid ();
goto exit_on_error;
}
}
sig.arg.arg_mode[i] = arg_mode;
sig.arg.arg_type[i] = arg_type;
sig.arg.arg_default_value_size[i] = default_value_size;
if (default_value_str)
{
sig.arg.arg_default_value[i] = db_private_strndup (NULL, default_value_str, default_value_size);
}
}
}
exit_on_error:
return error;
}
static int
check_execute_authorization (const MOP sp_obj, const DB_AUTH au_type)
{
int error = NO_ERROR;
MOP owner_mop = NULL;
DB_VALUE owner;
if (au_type != DB_AUTH_EXECUTE)
{
return NO_ERROR;
}
if (au_is_dba_group_member (Au_user))
{
return NO_ERROR;
}
// check execute authorization (Au_user is granted by owner)
if (au_check_procedure_authorization (sp_obj) == NO_ERROR)
{
return NO_ERROR;
}
return ER_FAILED;
}
PT_NODE *
jsp_get_default_expr_node_list (PARSER_CONTEXT *parser, cubpl::pl_signature &sig)
{
PT_NODE *default_next_node_list = NULL;
PT_NODE *default_next_node = NULL;
for (int i = 0; i < sig.arg.arg_size; i++)
{
if (sig.arg.arg_default_value_size[i] == PL_ARG_DEFAULT_NULL)
{
default_next_node = pt_make_string_value (parser, NULL);
}
else if (sig.arg.arg_default_value_size[i] == 0)
{
default_next_node = pt_make_string_value (parser, "");
}
else if (sig.arg.arg_default_value_size[i] > 0)
{
DB_DEFAULT_EXPR default_expr;
pt_get_default_expression_from_string (parser, sig.arg.arg_default_value[i], sig.arg.arg_default_value_size[i],
&default_expr);
// from pt_resolve_default_value
if (default_expr.default_expr_type != DB_DEFAULT_NONE)
{
PT_OP_TYPE op = pt_op_type_from_default_expr_type (default_expr.default_expr_type);
PT_NODE *default_op_value_node = pt_expression_0 (parser, op);
if (default_expr.default_expr_op == NULL_DEFAULT_EXPRESSION_OPERATOR)
{
default_next_node = default_op_value_node;
}
else
{
PT_NODE *arg1, *arg2, *arg3;
arg1 = default_op_value_node;
bool has_user_format = default_expr.default_expr_format ? true : false;
arg2 = pt_make_string_value (parser, default_expr.default_expr_format);
if (arg2 == NULL)
{
parser_free_tree (parser, default_op_value_node);
return NULL;
}
arg3 = parser_new_node (parser, PT_VALUE);
if (arg3 == NULL)
{
parser_free_tree (parser, default_op_value_node);
parser_free_tree (parser, arg2);
return NULL;
}
arg3->type_enum = PT_TYPE_INTEGER;
const char *lang_str = prm_get_string_value (PRM_ID_INTL_DATE_LANG);
int flag = 0;
lang_set_flag_from_lang (lang_str, has_user_format, 0, &flag);
arg3->info.value.data_value.i = (long) flag;
default_next_node = parser_make_expression (parser, PT_TO_CHAR, arg1, arg2, arg3);
if (default_next_node == NULL)
{
parser_free_tree (parser, default_op_value_node);
parser_free_tree (parser, arg2);
parser_free_tree (parser, arg3);
return NULL;
}
}
}
else
{
default_next_node = pt_make_string_value (parser, sig.arg.arg_default_value[i]);
}
}
if (default_next_node != NULL)
{
default_next_node = pt_semantic_type (parser, default_next_node, NULL);
if (default_next_node == NULL)
{
return NULL;
}
default_next_node_list = parser_append_node (default_next_node, default_next_node_list);
}
}
return default_next_node_list;
}