File object_print.c¶
File List > cubrid > src > object > object_print.c
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.
*
*/
/*
* object_print.c - Routines to print dbvalues
*/
#ident "$Id$"
#include "object_print.h"
#include "authenticate.h"
#include "chartype.h"
#include "class_description.hpp"
#include "dbi.h"
#include "dbtype.h"
#include "error_manager.h"
#include "locator_cl.h"
#include "message_catalog.h"
#include "msgcat_help.hpp"
#include "network_interface_cl.h"
#include "object_description.hpp"
#include "object_print_util.hpp"
#include "object_printer.hpp"
#include "printer.hpp"
#include "schema_manager.h"
#include "string_buffer.hpp"
#include "trigger_description.hpp"
#include "trigger_manager.h"
#if defined (SUPPRESS_STRLEN_WARNING)
#define strlen(s1) ((int) strlen(s1))
#endif /* defined (SUPPRESS_STRLEN_WARNING) */
#define MATCH_TOKEN(string, token) \
((string == NULL) ? 0 : intl_mbs_casecmp(string, token) == 0)
static char *obj_print_next_token (char *ptr, char *buf);
/* This will be in one of the language directories under $CUBRID/msg */
/* TRIGGER SUPPORT FUNCTIONS */
/* TRIGGER HELP */
/*
* help_trigger_names () - Returns an array of strings
* return: error code
* names_ptr(in):
*
* Note :
* Returns an array of strings. Each string is the name of
* a trigger accessible to the current user.
* The array must be freed with help_free_names().
* Changed to return an error and return the names through an
* argument so we can tell the difference between a system error
* and the absense of triggers.
* Class names should be the same but we always have classes in the
* system so it doesn't really matter.
*/
int
help_trigger_names (char ***names_ptr)
{
int error = NO_ERROR;
DB_OBJLIST *triggers, *t;
char **names;
char *name;
int count, i;
size_t buf_size;
names = NULL;
/* this should filter the list based on the current user */
error = tr_find_all_triggers (&triggers);
if (error == NO_ERROR)
{
count = ws_list_length ((DB_LIST *) triggers);
if (count)
{
buf_size = sizeof (char *) * (count + 1);
names = (char **) malloc (buf_size);
if (names == NULL)
{
error = ER_OUT_OF_VIRTUAL_MEMORY;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, buf_size);
}
else
{
for (i = 0, t = triggers; t != NULL; t = t->next)
{
if (tr_trigger_name (t->op, &name) == NO_ERROR)
{
names[i] = object_print::copy_string ((char *) name);
i++;
ws_free_string (name);
}
}
names[i] = NULL;
}
}
if (triggers != NULL)
{
db_objlist_free (triggers);
}
}
*names_ptr = names;
return error;
}
/* HELP PRINTING */
/* These functions build help structures and print them to a file. */
/*
* help_print_obj () - Prints the description of a class or instance object
* to a generic output.
* return: none
* fp(in):file pointer
* obj(in):class or instance to describe
*/
void
help_print_obj (print_output & output_ctx, MOP obj)
{
int i, status;
status = locator_is_class (obj, DB_FETCH_READ);
if (status < 0)
{
return;
}
else if (status > 0)
{
if (locator_is_root (obj))
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_ROOTCLASS_TITLE));
}
else
{
class_description cinfo;
if (cinfo.init (obj, class_description::CSQL_SCHEMA_COMMAND) == NO_ERROR)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_CLASS_TITLE),
cinfo.class_type, cinfo.name);
if (cinfo.supers != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_SUPER_CLASSES));
for (i = 0; cinfo.supers[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.supers[i]);
}
}
if (cinfo.subs != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_SUB_CLASSES));
for (i = 0; cinfo.subs[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.subs[i]);
}
}
if (cinfo.attributes != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_ATTRIBUTES));
for (i = 0; cinfo.attributes[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.attributes[i]);
}
}
if (cinfo.methods != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_METHODS));
for (i = 0; cinfo.methods[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.methods[i]);
}
}
if (cinfo.class_attributes != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_CLASS_ATTRIBUTES));
for (i = 0; cinfo.class_attributes[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.class_attributes[i]);
}
}
if (cinfo.class_methods != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_CLASS_METHODS));
for (i = 0; cinfo.class_methods[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.class_methods[i]);
}
}
if (cinfo.resolutions != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_RESOLUTIONS));
for (i = 0; cinfo.resolutions[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.resolutions[i]);
}
}
if (cinfo.method_files != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_METHOD_FILES));
for (i = 0; cinfo.method_files[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.method_files[i]);
}
}
if (cinfo.query_spec != NULL)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_QUERY_SPEC));
for (i = 0; cinfo.query_spec[i] != NULL; i++)
{
output_ctx (" %s\n", cinfo.query_spec[i]);
}
}
if (cinfo.triggers.size () > 0) //triggers
{
/* fprintf(fp, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_TRIGGERS)); */
output_ctx ("Triggers:\n");
for (size_t n = cinfo.triggers.size (), i = 0; i < n; ++i)
{
output_ctx (" %s\n", cinfo.triggers[i]);
}
}
}
}
}
else
{
(void) tr_is_trigger (obj, &status);
if (status)
{
trigger_description tinfo;
if (tinfo.init (obj) == NO_ERROR)
{
output_ctx ("Trigger : %s", tinfo.name);
if (tinfo.status)
{
output_ctx (" (INACTIVE)\n");
}
else
{
output_ctx ("\n");
}
output_ctx (" %s %s ", tinfo.condition_time, tinfo.event);
if (tinfo.class_name != NULL)
{
if (tinfo.attribute != NULL)
{
output_ctx ("%s ON %s ", tinfo.attribute, tinfo.class_name);
}
else
{
output_ctx ("ON %s ", tinfo.class_name);
}
}
output_ctx ("PRIORITY %s\n", tinfo.priority);
if (tinfo.condition)
{
output_ctx (" IF %s\n", tinfo.condition);
}
if (tinfo.action != NULL)
{
output_ctx (" EXECUTE ");
if (strcmp (tinfo.condition_time, tinfo.action_time) != 0)
{
output_ctx ("%s ", tinfo.action_time);
}
output_ctx ("%s\n", tinfo.action);
}
if (tinfo.comment != NULL && tinfo.comment[0] != '\0')
{
output_ctx (" ");
help_print_describe_comment (output_ctx, tinfo.comment);
output_ctx ("\n");
}
}
}
else
{
object_description oinfo;
if (oinfo.init (obj) == NO_ERROR)
{
output_ctx (msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_HELP, MSGCAT_HELP_OBJECT_TITLE),
oinfo.classname);
if (oinfo.attributes != NULL)
{
for (i = 0; oinfo.attributes[i] != NULL; i++)
{
output_ctx ("%s\n", oinfo.attributes[i]);
}
}
if (oinfo.shared != NULL)
{
for (i = 0; oinfo.shared[i] != NULL; i++)
{
output_ctx ("%s\n", oinfo.shared[i]);
}
}
}
}
}
}
/* CLASS LIST HELP */
/*
* help_class_names () - Returns an array containing the names of
* all classes in the system.
* return: array of name strings
* qualifier(in):
*
* Note :
* The array must be freed with help_free_class_names().
*/
char **
help_class_names (const char *qualifier)
{
DB_OBJLIST *mops, *m;
char **names;
int count, i, outcount;
DB_OBJECT *requested_owner, *owner;
char buffer[2 * DB_MAX_IDENTIFIER_LENGTH + 4];
const char *unique_name;
const char *class_name;
requested_owner = NULL;
owner = NULL;
if (qualifier && *qualifier && strcmp (qualifier, "*") != 0)
{
/* look up class in qualifiers' schema */
requested_owner = db_find_user (qualifier);
/* if this guy does not exist, it has no classes */
if (!requested_owner)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_INVALID_USER, 1, qualifier);
return NULL;
}
}
names = NULL;
mops = db_fetch_all_classes (DB_FETCH_READ);
/* vector fetch as many as possible (void)db_fetch_list(mops, DB_FETCH_READ, 0); */
count = ws_list_length ((DB_LIST *) mops);
outcount = 0;
if (count)
{
names = (char **) malloc (sizeof (char *) * (count + 1));
if (names != NULL)
{
for (i = 0, m = mops; i < count; i++, m = m->next)
{
unique_name = db_get_class_name (m->op);
buffer[0] = '\0';
if (!requested_owner && sm_check_name (unique_name))
{
snprintf (buffer, sizeof (buffer) - 1, "%s", unique_name);
names[outcount++] = object_print::copy_string (buffer);
continue;
}
owner = db_get_owner (m->op);
class_name = sm_remove_qualifier_name (unique_name);
if (ws_is_same_object (requested_owner, owner) && sm_check_name (class_name))
{
snprintf (buffer, sizeof (buffer) - 1, "%s", class_name);
names[outcount++] = object_print::copy_string (buffer);
continue;
}
snprintf (buffer, sizeof (buffer) - 1, "%s", "unknown_class");
names[outcount++] = object_print::copy_string (buffer);
}
names[outcount] = NULL;
}
}
if (mops != NULL)
{
db_objlist_free (mops);
}
return names;
}
/*
* help_free_names () - Frees an array of class names built by
* help_class_names() or help_base_class_names().
* return: class name array
* names(in): class name array
*/
void
help_free_names (char **names)
{
if (names != NULL)
{
object_print::free_strarray (names);
}
}
/*
* backward compatibility, should be using help_free_names() for all
* name arrays.
*/
/*
* help_free_class_names () -
* return: none
* names(in):
*/
void
help_free_class_names (char **names)
{
help_free_names (names);
}
/*
* help_fprint_class_names () - Prints the names of all classes
* in the system to a file.
* return: none
* fp(in): file pointer
* qualifier(in):
*/
void
help_fprint_class_names (FILE * fp, const char *qualifier)
{
char **names;
int i;
names = help_class_names (qualifier);
if (names != NULL)
{
for (i = 0; names[i] != NULL; i++)
{
fprintf (fp, "%s\n", names[i]);
}
help_free_class_names (names);
}
}
/* MISC HELP FUNCTIONS */
/*
* help_describe_mop () - This writes a description of the MOP
* to the given buffer.
* return: number of characters in the description
* obj(in): object pointer to describe
* buffer(in): buffer to contain the description
* maxlen(in): length of the buffer
*
* Note :
* Used to get a printed representation of a MOP.
* This should only be used in special cases since OID's aren't
* supposed to be visible.
*/
int
help_describe_mop (DB_OBJECT * obj, char *buffer, int maxlen)
{
SM_CLASS *class_;
char oidbuffer[64]; /* three integers, better be big enough */
int required, total;
total = 0;
if ((buffer != NULL) && (obj != NULL) && (maxlen > 0))
{
if (au_fetch_class (obj, &class_, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
{
sprintf (oidbuffer, "%ld.%ld.%ld", (DB_C_LONG) WS_OID (obj)->volid, (DB_C_LONG) WS_OID (obj)->pageid,
(DB_C_LONG) WS_OID (obj)->slotid);
required = strlen (oidbuffer) + strlen (sm_ch_name ((MOBJ) class_)) + 2;
if (locator_is_class (obj, DB_FETCH_READ) > 0)
{
required++;
if (maxlen >= required)
{
sprintf (buffer, "*%s:%s", sm_ch_name ((MOBJ) class_), oidbuffer);
total = required;
}
}
else if (maxlen >= required)
{
sprintf (buffer, "%s:%s", sm_ch_name ((MOBJ) class_), oidbuffer);
total = required;
}
}
}
return total;
}
/* GENERAL INFO */
/*
* This is used to dump random information about the database
* to the standard output device. The information requested
* comes in as a string that is "parsed" to determine the nature
* of the request. This is intended primarily as a backdoor
* for the "info" method on the root class. This allows us
* to get information dumped to stdout from batch CSQL
* files which isn't possible currently since session commands
* aren't allowed.
*
* The recognized commands are:
*
* schema display the names of all classes (;schema)
* schema foo display the definition of class foo (;schema foo)
* trigger display the names of all triggers (;trigger)
* trigger foo display the definition of trigger foo (;trigger foo)
* workspace dump the workspace statistics
*
*/
/*
* Little tokenizing hack for help_display_info.
*/
/*
* obj_print_next_token () -
* return: char *
* ptr(in):
* buffer(in):
*/
static char *
obj_print_next_token (char *ptr, char *buffer)
{
char *p;
p = ptr;
while (char_isspace ((DB_C_INT) (*p)) && *p != '\0')
{
p++;
}
while (!char_isspace ((DB_C_INT) (*p)) && *p != '\0')
{
*buffer = *p;
buffer++;
p++;
}
*buffer = '\0';
return p;
}
/*
* help_print_info () -
* return: none
* command(in):
* fpp(in):
*/
void
help_print_info (const char *command, FILE * fpp)
{
char buffer[128];
char *ptr;
DB_OBJECT *class_mop;
char **names;
int i;
if (command == NULL)
{
return;
}
ptr = obj_print_next_token ((char *) command, buffer);
if (fpp == NULL)
{
fpp = stdout;
}
file_print_output output_ctx (fpp);
if (MATCH_TOKEN (buffer, "schema"))
{
ptr = obj_print_next_token (ptr, buffer);
if (!strlen (buffer))
{
help_fprint_class_names (fpp, NULL);
}
else
{
class_mop = db_find_class (buffer);
if (class_mop != NULL)
{
help_print_obj (output_ctx, class_mop);
}
else
{
fprintf (fpp, "\nERROR: %s\n", er_msg ());
}
}
}
else if (MATCH_TOKEN (buffer, "trigger"))
{
ptr = obj_print_next_token (ptr, buffer);
if (!strlen (buffer))
{
if (!help_trigger_names (&names))
{
if (names == NULL)
{
fprintf (fpp, "No triggers defined.\n");
}
else
{
fprintf (fpp, "Triggers: \n");
for (i = 0; names[i] != NULL; i++)
{
fprintf (fpp, " %s\n", names[i]);
}
help_free_names (names);
}
}
}
else
{
//help_print_trigger (buffer, fpp);
trigger_description td;
if (td.init (buffer) == NO_ERROR)
{
td.fprint (fpp);
}
}
}
else if (MATCH_TOKEN (buffer, "deferred"))
{
tr_dump (fpp);
}
else if (MATCH_TOKEN (buffer, "workspace"))
{
ws_dump (fpp);
}
else if (MATCH_TOKEN (buffer, "lock"))
{
lock_dump (fpp, 0);
}
else if (MATCH_TOKEN (buffer, "stats"))
{
ptr = obj_print_next_token (ptr, buffer);
if (!strlen (buffer))
{
fprintf (fpp, "Info stats class-name\n");
}
else
{
stats_dump (buffer, fpp);
}
}
else if (MATCH_TOKEN (buffer, "logstat"))
{
log_dump_stat (fpp);
}
else if (MATCH_TOKEN (buffer, "csstat"))
{
thread_dump_cs_stat (fpp);
}
else if (MATCH_TOKEN (buffer, "plan"))
{
qmgr_dump_query_plans (fpp);
}
else if (MATCH_TOKEN (buffer, "qcache"))
{
qmgr_dump_query_cache (fpp);
}
else if (MATCH_TOKEN (buffer, "trantable"))
{
logtb_dump_trantable (fpp);
}
else if (MATCH_TOKEN (buffer, "ndv"))
{
ptr = obj_print_next_token (ptr, buffer);
if (!strlen (buffer))
{
fprintf (fpp, "Info ndv class-name\n");
}
else
{
stats_ndv_dump (buffer, fpp);
}
}
}
/*
* help_print_describe_comment() - Print description of a comment to a generic output.
* return: N/A
* output_ctx(in/out) : output context
* comment(in) : a comment string to be printed
*/
void
help_print_describe_comment (print_output & output_ctx, const char *comment)
{
/* TODO : optimize printing directly to string_buffer of output_ctx */
string_buffer sb;
object_printer printer (sb);
assert (comment != NULL);
printer.describe_comment (comment);
output_ctx ("%.*s", int (sb.len ()), sb.get_buffer ());
}