예제 #1
0
boolean_t check_trigger_name(char *name_str, uint4 *name_len)
{
	uint4		len, lcl_name_len;
	unsigned char	*ptr;

	/* To conform to the other uses of the check_* functions and their use in the GET_CLI_STR_AND_CHECK macro
	 * name_len is passed in as a uint4 *, but in this case a uint4 would suffice.  To mitigate the dereferencing
	 * issues, a local copy is used.
	 */
	lcl_name_len = *name_len;
	if (MAX_USER_TRIGNAME_LEN < lcl_name_len)
	{
		util_out_print_gtmio("Trigger name length [!UL] exceeds maximum supported length of [!UL]",
			FLUSH, lcl_name_len, MAX_USER_TRIGNAME_LEN);
		return FALSE;
	}
	ptr = (unsigned char *)name_str;
	if (('%' != *ptr) && !ISALPHA_ASCII(*ptr))
	{
		util_out_print_gtmio("Trigger name does not begin with an ascii alphabet or %", FLUSH);
		return FALSE;
	}
	for (len = lcl_name_len - 1, ptr++; (0 < len) && ISALNUM_ASCII(*ptr); ptr++, len--)
	    	;
	if (len)
		util_out_print_gtmio("Trigger name has non-alphanumeric character", FLUSH);
	return (0 == len);
}
예제 #2
0
STATICFNDEF boolean_t process_options(char *option_str, uint4 option_len, boolean_t *isolation, boolean_t *noisolation,
			       boolean_t *consistency, boolean_t *noconsistency)
{
	char		local_options[MAX_OPTIONS_LEN];
	char		*ptr, *strtokptr;

	if (MAX_OPTIONS_LEN < option_len)
	{
		util_out_print_gtmio("Too many options", FLUSH);
		return FALSE;
	}
	memcpy(local_options, option_str, option_len);
	*isolation = *noisolation = *consistency = *noconsistency = FALSE;
	ptr = local_options;
	for ( ; 0 < option_len; ptr++, option_len--)
		*ptr = TOUPPER(*ptr);
	ptr = STRTOK_R(local_options, ",", &strtokptr);
	do
	{
		switch (*ptr)
		{
			case 'C':
				if (1 == STRLEN(ptr))
					*consistency = TRUE;
				else
				{
					assert(0 == MEMCMP_LIT(ptr, HASHT_OPT_CONSISTENCY));
					*consistency = TRUE;
				}
				break;
			case 'I':
				if (1 == STRLEN(ptr))
					*isolation = TRUE;
				else
				{
					assert(0 == MEMCMP_LIT(ptr, HASHT_OPT_ISOLATION));
					*isolation = TRUE;
				}
				break;
			case 'N':
				assert('O' == *(ptr + 1));
				if ('C' == *(ptr + 2))
				{
					assert(0 == MEMCMP_LIT(ptr, HASHT_OPT_NOCONSISTENCY));
					*noconsistency = TRUE;
				} else
				{
					assert('I' == *(ptr + 2));
					assert(0 == MEMCMP_LIT(ptr, HASHT_OPT_NOISOLATION));
					*noisolation = TRUE;
				}
				break;
			default:
				assert(FALSE);	/* Parsing should have found invalid command */
				break;
		}
	} while (ptr = STRTOK_R(NULL, ",", &strtokptr));
	return !((*isolation && *noisolation) || (*consistency && *noconsistency));
}
예제 #3
0
STATICFNDEF char *scan_to_end_quote(char *ptr, int len, int max_len)
{
	int			str_len = 0;

	if ((1 >= len) || ('"' != *ptr))
		return NULL;	/* Invalid string - it needs at least "" */
	if (max_len < ++str_len)
	{
		util_out_print_gtmio("String too long", FLUSH);
		return NULL;
	}
	ptr++;
	len--;
	for ( ; 0 < len; len--, ptr++)
	{	/* Scan until the closing quote */
		if ('"' == *ptr)
		{
			if (1 == len)
				break;
			if ('"' == *(ptr + 1))
			{
				if (max_len < ++str_len)
				{
					util_out_print_gtmio("String too long", FLUSH);
					return NULL;
				}
				ptr++;
				len--;
			} else
				break;
		}
		if (max_len < ++str_len)
		{
			util_out_print_gtmio("String too long", FLUSH);
			return NULL;
		}
	}
	return (('"' == *ptr) ? ptr + 1 : NULL);
}
예제 #4
0
STATICFNDEF boolean_t process_subscripts(char *subscr_str, uint4 *subscr_len, char **next_str, char *out_str, int4 *out_max)
{
	boolean_t	alternation;
	char		dst[MAX_GVSUBS_LEN];
	int		dst_len;
	char		*dst_ptr;
	int		len;
	boolean_t	have_pattern;
	boolean_t	have_range;
	boolean_t	have_star;
	boolean_t	have_dot;
	int		i;
	int		lvn_count;
	uint4		lvn_len[MAX_LVN_COUNT];
	char		*lvn_start;
	char		*lvn_str[MAX_LVN_COUNT];
	int		multiplier;
	boolean_t	newsub;
	int		num1;
	int		num2;
	char		*ptr;
	char		*ptr1;
	char		*save_dst_ptr;
	int		save_len;
	char		*start_dst_ptr;
	uint4		start_len;
	uint4		subsc_count;
	uint4		tmp_len;
	boolean_t	valid_sub;

	have_pattern = have_range = valid_sub = have_star = FALSE;
	ptr = subscr_str;
	start_len = len = *subscr_len;
	dst_len = 0;
	newsub = TRUE;
	subsc_count = lvn_count = 0;
	start_dst_ptr = dst_ptr = dst;
	while ((0 < len) && (')' != *ptr))
	{
		if (ISDIGIT_ASCII(*ptr) || ('-' == *ptr))
		{
			PROCESS_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
			newsub = FALSE;
			valid_sub = TRUE;
		}
		else if (ISALPHA_ASCII(*ptr) || ('%' == *ptr))
		{
			if (!newsub)
			{
				util_out_print_gtmio("Invalid subscript", FLUSH);
				return FALSE;
			}
			lvn_start = ptr;
			tmp_len = 0;
			do
			{
				if (MAX_MIDENT_LEN < ++tmp_len)
				{
					util_out_print_gtmio("Variable name too long", FLUSH);
					return FALSE;
				}
				if (MAX_GVSUBS_LEN < ++dst_len)
				{
					util_out_print_gtmio("Subscript too long", FLUSH);
					return FALSE;
				}
				*dst_ptr++ = *ptr++;
				len--;
			} while (ISALNUM_ASCII(*ptr));
			if ('=' != *ptr)
			{
				util_out_print_gtmio("Invalid variable name in subscript", FLUSH);
				return FALSE;
			}
			for (i = 0; i < lvn_count; i++)
			{
				if ((lvn_len[i] == tmp_len) && (0 == strncmp(lvn_str[i], lvn_start, tmp_len)))
				{
					util_out_print_gtmio("Duplicate variable name in subscript", FLUSH);
					return FALSE;
				}
			}
			lvn_str[lvn_count] = lvn_start;
			lvn_len[lvn_count] = tmp_len;
			lvn_count++;
			if (MAX_GVSUBS_LEN < ++dst_len)
			{
				util_out_print_gtmio("Subscript too long", FLUSH);
				return FALSE;
			}
			*dst_ptr++ = *ptr++;		/* move past = */
			start_dst_ptr = dst_ptr;
			len--;
			if ((0 < len) && ((',' == *ptr) || (')' == *ptr)))
			{
				util_out_print_gtmio("Variable name not followed by valid subscript", FLUSH);
				return FALSE;
			}
			continue;
		} else
		{
			switch (*ptr)
			{
				case '"':
					PROCESS_STRING(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
					valid_sub = TRUE;
					newsub = FALSE;
					break;
				case '$':
					if (!process_dollar_char(&ptr, &len, have_star, &dst_ptr, &dst_len))
					{
						util_out_print_gtmio("Invalid subscript", FLUSH);
						return FALSE;
					}
					newsub = FALSE;
					valid_sub = TRUE;
					break;
				case '?':
					if (have_range)
					{
						util_out_print_gtmio("Range and pattern match not valid in same subscript", FLUSH);
						return FALSE;
					}
					UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
					ptr1 = ptr;
					alternation = FALSE;
					while ((0 < len) && ((',' != *ptr) || alternation) && ((')' != *ptr) || alternation)
					       && (';' != *ptr))
					{
						num1 = num2 = -1;
						have_dot = FALSE;
						if (ISDIGIT_ASCII(*ptr))
						{
							PROCESS_AND_GET_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, num1,
										MAX_GVSUBS_LEN);
						}
						if ('.' == *ptr)
						{
							have_dot = TRUE;
							if (MAX_GVSUBS_LEN < ++dst_len)
							{
								util_out_print_gtmio("Subscript too long", FLUSH);
								return FALSE;
							}
							*dst_ptr++ = *ptr++;
							len--;
							if (ISDIGIT_ASCII(*ptr))
							{
								PROCESS_AND_GET_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, num2,
									MAX_GVSUBS_LEN);
							}
							if (-1 == num1)
								num1 = 0;
						}
						switch (*ptr)
						{
							case '(':
								if (!alternation && (0 <= num1))
								{
									UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len,
										   MAX_GVSUBS_LEN);
									alternation = TRUE;
									continue;
								}
								break;
							case ',':
								if (alternation && (-1 == num1) && (-1 == num2))
								{
									UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len,
										   MAX_GVSUBS_LEN);
									continue;
								}
								break;
							case ')':
								if (alternation && (-1 == num1) && (-1 == num2))
								{
									UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len,
										   MAX_GVSUBS_LEN);
									alternation = FALSE;
									continue;
								}
								break;
							default:
								break;
						}
						if ((0 <= num1) && (0 <= num2) && (num2 < num1))
						{
							util_out_print_gtmio("Invalid pattern match range", FLUSH);
							return FALSE;
						}
						switch (TOUPPER(*ptr))
						{
							case 'E':
								if (have_dot && (0 >= num1) && (-1 == num2))
								{ /* Treat ?.E the same as * */
									have_star = TRUE;
									dst_ptr = start_dst_ptr;
									if (MAX_GVSUBS_LEN < ++dst_len)
									{
										util_out_print_gtmio("Subscript too long", FLUSH);
										return FALSE;
									}
									*dst_ptr++ = '*';
								}
								/* Note: we're dropping into the following case */
							case 'A':
							case 'C':
							case 'K':
							case 'L':
							case 'N':
							case 'P':
							case 'U':
							case 'V':

								UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
								break;
							case '"':
								PROCESS_STRING(ptr, len, have_star, dst_ptr, dst_len,
									       MAX_GVSUBS_LEN);
								break;
								/* Note: we're dropping into the default/error case */
							default:
								CONV_CH_AND_PRINT("Unexpected character !AD in pattern code", ptr);
								return FALSE;
						}
					}
					have_pattern = TRUE;
					valid_sub = TRUE;
					newsub = FALSE;
					break;
				case ':':
					if (have_range)
					{
						util_out_print_gtmio("Range within a range not allowed", FLUSH);
						return FALSE;
					}
					if (have_pattern)
					{
						util_out_print_gtmio("Pattern not allowed as a range", FLUSH);
						return FALSE;
					}
					UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
					if (ISDIGIT_ASCII(*ptr) || ('-' == *ptr))
					{
						PROCESS_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
					}
					else if ('"' == *ptr)
					{
						PROCESS_STRING(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
					} else if ('$' == *ptr)
					{
						if (!process_dollar_char(&ptr, &len, have_star, &dst_ptr, &dst_len))
						{
							util_out_print_gtmio("Invalid range value", FLUSH);
							return FALSE;
						}
					} else if ((0 < len) && (',' != *ptr) && (';' != *ptr) && (')' != *ptr))
					{
						util_out_print_gtmio("Invalid string range", FLUSH);
						return FALSE;
					} else
					{	/* A range with no lower end - just scan the numeric or string */
						ptr1 = ptr;
						if (ISDIGIT_ASCII(*ptr) || ('-' == *ptr))
						{
							PROCESS_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
						} else if ('"' == *ptr1)
						{
							PROCESS_STRING(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
						} else if ((0 < len) && ((',' != *ptr) && (';' != *ptr) && (')' != *ptr)))
						{
							util_out_print_gtmio("Range value must be integer or string", FLUSH);
							return FALSE;
						} else if (!valid_sub)
						{ /* this is a single ":" - treat it just like a * */
							have_star = TRUE;
							dst_ptr = start_dst_ptr;
							if (MAX_GVSUBS_LEN < ++dst_len)
							{
								util_out_print_gtmio("Subscript too long", FLUSH);
								return FALSE;
							}
							*dst_ptr++ = '*';
						}
					}
					valid_sub = TRUE;
					newsub = FALSE;
					have_range = TRUE;
					break;
				case '*':
					if (!have_star)
					{
						have_star = TRUE;
						dst_ptr = start_dst_ptr;
						if (MAX_GVSUBS_LEN < ++dst_len)
						{
							util_out_print_gtmio("Subscript too long", FLUSH);
							return FALSE;
						}
						*dst_ptr++ = '*';
					}
					ptr++;
					len--;
					if ((0 < len) && (',' != *ptr) && (';' != *ptr) && (')' != *ptr))
					{
						util_out_print_gtmio("Invalid use of *", FLUSH);
						return FALSE;
					} else
						valid_sub = TRUE;
					newsub = FALSE;
					break;
				case ';':
					UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
					/* Delete extraneous ; in the subscript */
					if ((!have_star) && (newsub || ((0 < len)
						&& ((',' == *ptr) || (';' == *ptr) || ISALPHA_ASCII(*ptr)
							|| ('%' == *ptr) || (')' == *ptr)))))
						dst_ptr--;
					valid_sub = FALSE;
					have_pattern = have_range = FALSE;
					break;
				case ',':
					if (newsub)
					{
						util_out_print_gtmio("Empty subscript not allowed", FLUSH);
						return FALSE;
					}
					if (MAX_GVSUBSCRIPTS <= ++subsc_count)
					{
						util_out_print_gtmio("Too many subscripts", FLUSH);
						return FALSE;
					}
					if (MAX_GVSUBS_LEN < ++dst_len)
					{
						util_out_print_gtmio("Subscript too long", FLUSH);
						return FALSE;
					}
					*dst_ptr++ = *ptr++;
					len--;
					start_dst_ptr = dst_ptr;
					newsub = TRUE;
					have_range = have_pattern = valid_sub = have_star = FALSE;
					break;
				default:
					CONV_CH_AND_PRINT("Invalid character !AD in subscript", ptr);
					return FALSE;
			}
		}
	}
	if ((0 == len) && (')' != *ptr))
	{
		util_out_print_gtmio("Missing \")\" after global subscript", FLUSH);
		return FALSE;
	}
	if ((start_len == len) || newsub)
	{
		util_out_print_gtmio("Empty subscript not allowed", FLUSH);
		return FALSE;
	}
	if ((')' == *ptr) && (MAX_GVSUBSCRIPTS <= ++subsc_count))
	{
		util_out_print_gtmio("Too many subscripts", FLUSH);
		return FALSE;
	}
	CHECK_FOR_ROOM_IN_OUTPUT_AND_COPY(dst, out_str, (int)(dst_ptr - dst), *out_max);
	*subscr_len = (uint4)(dst_ptr - dst);
	*next_str = ptr + 1;
	return TRUE;
}
예제 #5
0
STATICFNDEF boolean_t process_delim(char *delim_str, uint4 *delim_len)
{
	int		char_count;
	mstr		dst;
	int		dst_len;
	char		*dst_ptr;
	char		dst_string[MAX_DELIM_LEN + 1];
	uint4		len;
	char		*ptr;
	char		*ptr1;
	int		q_len;
	char		src_string[MAX_DELIM_LEN + 1];
	mstr		src;
	char		*src_ptr;

	if (MAX_DELIM_LEN < *delim_len)
	{
		util_out_print_gtmio("Delimiter too long", FLUSH);
		return FALSE;
	}
	ptr = delim_str;
	len = *delim_len;
	src_ptr = src_string;
	dst_len = 0;
	/* If ", scan to end quote
	 * If $, look for char --> c or zchar --> zch
	 * If _, leave it
	 */
	while (0 < len)
	{
		switch (*ptr)
		{
			case '"':
				PROCESS_STRING(ptr, len, FALSE, src_ptr, dst_len, MAX_DELIM_LEN);
				break;
			case '$':
				UPDATE_DST(ptr, len, FALSE, src_ptr, dst_len, MAX_DELIM_LEN);
				if (0 == len)
				{
					util_out_print_gtmio("Invalid entry in delimiter", FLUSH);
					return FALSE;
				}
				if ((3 < len) && ('C' == lower_to_upper_table[*ptr])
						&& ('H' == lower_to_upper_table[*(ptr + 1)])
						&& ('A' == lower_to_upper_table[*(ptr + 2)])
						&& ('R' == lower_to_upper_table[*(ptr + 3)]))
				{
					if (MAX_DELIM_LEN < ++dst_len)
					{
						util_out_print_gtmio("Trigger definition too long", FLUSH);
						return FALSE;
					}
					*src_ptr++ = 'C';
					ptr += 4;
					len -= 4;
				} else if ((4 < len) && ('Z' == lower_to_upper_table[*ptr])
						&& ('C' == lower_to_upper_table[*(ptr + 1)])
						&& ('H' == lower_to_upper_table[*(ptr + 2)])
						&& ('A' == lower_to_upper_table[*(ptr + 3)])
						&& ('R' == lower_to_upper_table[*(ptr + 4)]))
				{
					if (MAX_DELIM_LEN < (dst_len + 3))
					{
						util_out_print_gtmio("Trigger definition too long", FLUSH);
						return FALSE;
					}
					MEMCPY_LIT(src_ptr, "ZCH");
					src_ptr += 3;
					dst_len += 3;
					ptr += 5;
					len -= 5;
				} else
				{
					UPDATE_DST(ptr, len, FALSE, src_ptr, dst_len, MAX_DELIM_LEN);
				}
				break;
			default:
				UPDATE_DST(ptr, len, FALSE, src_ptr, dst_len, MAX_DELIM_LEN);
				break;
		}
	}
	*src_ptr = '\0';
	src.addr = src_string;
	src.len = (mstr_len_t)(src_ptr - src_string);
	dst.addr = dst_string;
	dst.len = 0;
	if (!zwr2format(&src, &dst))
	{
		util_out_print_gtmio("Invalid delimiter", FLUSH);
		return FALSE;
	}
	if (MAX_DELIM_LEN < dst.len)
	{
		util_out_print_gtmio("Delimiter too long", FLUSH);
		return FALSE;
	}
	memcpy(delim_str, dst_string, dst.len);
	*delim_len = dst.len;
	return TRUE;
}
예제 #6
0
STATICFNDEF boolean_t process_dollar_char(char **src_ptr, int *src_len, boolean_t have_star, char **d_ptr, int *dst_len)
{
	int		char_count;
	char		*char_ptr;
	int		len;
	char		*dst_ptr;
	char		dst_string[MAX_DCHAR_LEN];
	int		lcl_dst_len;
	mstr		m_dst;
	mstr		m_src;
	char		*ptr;
	int		q_len;
	char		*tmp_dst_ptr;

	tmp_dst_ptr = dst_ptr = *d_ptr;
	ptr = *src_ptr;
	len = *src_len;
	lcl_dst_len = *dst_len;
	assert('$' == *ptr);
	UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
	if (0 == len)
		return FALSE;
	switch (*ptr)
	{
		case 'c':
		case 'C':
			UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
			if ((0 < len) && ('(' == *ptr))
				break;
			else if ((3 < len) && ('H' == lower_to_upper_table[*ptr])
					&& ('A' == lower_to_upper_table[*(ptr + 1)])
					&& ('R' == lower_to_upper_table[*(ptr + 2)]) && ('(' == *(ptr + 3)))
			{
				ptr += 3;
				len -= 3;
				break;
			}
			else
				return FALSE;
			break;
		case 'z':
		case 'Z':
			UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
			if ((2 < len) && ('C' == lower_to_upper_table[*ptr])
					&& ('H' == lower_to_upper_table[*(ptr + 1)]) && ('(' == *(ptr + 2)))
			{
				ptr += 2;
				len -= 2;
			}
			else if ((4 < len) && ('C' == lower_to_upper_table[*ptr])
					&& ('H' == lower_to_upper_table[*(ptr + 1)])
					&& ('A' == lower_to_upper_table[*(ptr + 2)])
					&& ('R' == lower_to_upper_table[*(ptr + 3)]) && ('(' == *(ptr + 4)))
			{
				ptr += 4;
				len -= 4;
			}
			else
				return FALSE;
			if (MAX_GVSUBS_LEN < lcl_dst_len + 2)
			{
				util_out_print_gtmio("Subscript too long", FLUSH);
				return FALSE;
			}
			MEMCPY_LIT(dst_ptr, "CH");
			dst_ptr += 2;
			lcl_dst_len += 2;
			break;
		default:
			return FALSE;
	}
	assert('(' == *ptr);
	UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
	while ((0 < len) && (')' != *ptr))
	{
		UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
	}
	q_len = 0;
	if (!have_star)
	{
		if (MAX_GVSUBS_LEN < ++lcl_dst_len)
		{
			util_out_print_gtmio("$[Z]CHAR expression too long", FLUSH);
			return FALSE;
		}
		*dst_ptr++ = *ptr++;
		*dst_ptr = '\0';
		m_src.addr = tmp_dst_ptr;
		m_src.len = (mstr_len_t)(dst_ptr - tmp_dst_ptr);
		m_dst.addr = dst_string;
		m_dst.len = 0;
		if (!zwr2format(&m_src, &m_dst))
			return FALSE;
		lcl_dst_len = *dst_len;		/* Reset length because we're creating the final version now */
		if (MAX_GVSUBS_LEN < ++lcl_dst_len)
		{
			util_out_print_gtmio("Subscript too long", FLUSH);
			return FALSE;
		}
		*tmp_dst_ptr++ = '"';
		char_ptr = m_dst.addr;
		if (MAX_GVSUBS_LEN < (lcl_dst_len + m_dst.len))
		{
			util_out_print_gtmio("Subscript too long", FLUSH);
			return FALSE;
		}
		for (char_count = 0; m_dst.len > char_count; char_count++)
		{
			if ('"' == *char_ptr)
			{
				if (MAX_GVSUBS_LEN < ++lcl_dst_len)
				{
					util_out_print_gtmio("Subscript too long", FLUSH);
					return FALSE;
				}
				*tmp_dst_ptr++ = '"';
				q_len++;
			}
			*tmp_dst_ptr++ = *char_ptr++;
			lcl_dst_len++;
		}
		if (MAX_GVSUBS_LEN < ++lcl_dst_len)
		{
			util_out_print_gtmio("Subscript too long", FLUSH);
			return FALSE;
		}
		*tmp_dst_ptr++ = '"';
		dst_ptr = tmp_dst_ptr;
	}
	else
		ptr++;
	assert(!have_star || ((dst_ptr == *d_ptr) && (lcl_dst_len == *dst_len)));
	*src_ptr = ptr;
	*src_len = len + 2 + q_len;	/* Allow for the open and close quotes and any internal quotes */
	*d_ptr = dst_ptr;
	*dst_len = lcl_dst_len;
	return TRUE;
}
예제 #7
0
int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index)
{
	int			count;
	mval			mv_val;
	mval			*mv_val_ptr;
	char			*ptr1;
	int4			result;
	int4			retval;
	stringkey		kill_hash, set_hash;
	int			sub_indx;
	char			tmp_trig_str[MAX_BUFF_SIZE];
	int4			trig_len;
	char			trig_name[MAX_TRIGNAME_LEN];
	int			trig_name_len;
	int			tmp_len;
	char			*tt_val[NUM_SUBS];
	uint4			tt_val_len[NUM_SUBS];
	mval			trigger_value;
	mval			trigger_index;
	mval			xecute_index;
	uint4			xecute_idx;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(!gv_cur_region->read_only);		/* caller should have already checked this */
	assert(cs_addrs->hasht_tree == gv_target);	/* should have been set up by caller */
	assert(gv_target->root);			/* should have been ensured by caller */
	mv_val_ptr = &mv_val;
	MV_FORCE_UMVAL(&trigger_index, index);
	count = MV_FORCE_UINT(trigger_count);
	/* build up array of values - needed for comparison in hash stuff */
	ptr1 = tmp_trig_str;
	memcpy(ptr1, trigvn, trigvn_len);
	ptr1 += trigvn_len;
	*ptr1++ = '\0';
	tmp_len = trigvn_len + 1;
	/* Assert that BHASH and LHASH are not part of NUM_SUBS calculation (confirms the -2 done in the #define of NUM_SUBS) */
	assert(BHASH_SUB == NUM_SUBS);
	assert(LHASH_SUB == (NUM_SUBS + 1));
	for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
	{
		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[sub_indx],
						 STRLEN(trigger_subs[sub_indx]));
		trig_len = gvcst_get(&trigger_value) ? trigger_value.str.len : 0;
		if (0 == trig_len)
		{
			if (((TRIGNAME_SUB == sub_indx) || (CMD_SUB == sub_indx) || (CHSET_SUB == sub_indx)))
			{ /* CMD, NAME and CHSET cannot be zero length */
				if (CDB_STAGNATE > t_tries)
					t_retry(cdb_sc_triggermod);
				assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
				rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
						trigvn_len, trigvn, STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
			}
			tt_val[sub_indx] = NULL;
			tt_val_len[sub_indx] = 0;
			continue;
		}
		if (TRIGNAME_SUB == sub_indx)
		{
			trig_name_len = MIN(trig_len, MAX_TRIGNAME_LEN);
			assert(MAX_TRIGNAME_LEN >= trig_len);
			memcpy(trig_name, trigger_value.str.addr, trig_name_len);
			tt_val[sub_indx] = NULL;
			tt_val_len[sub_indx] = 0;
			continue;
		}
		tt_val[sub_indx] = ptr1;
		tt_val_len[sub_indx] = trig_len;
		tmp_len += trig_len;
		if (0 < trig_len)
		{
			if (MAX_BUFF_SIZE <= tmp_len)
				return VAL_TOO_LONG;
			memcpy(ptr1, trigger_value.str.addr, trig_len);
			ptr1 += trig_len;
		}
		*ptr1++ = '\0';
		tmp_len++;
	}
	/* Get trigger name, set hash value, and kill hash values from trigger before we delete it.
	 * The values will be used in clean ups associated with the deletion
	 */
	/* $get(^#t(GVN,trigger_index,"LHASH") for deletion in cleanup_trigger_hash */
	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[LHASH_SUB],
		STRLEN(trigger_subs[LHASH_SUB]));
	if (gvcst_get(mv_val_ptr))
		kill_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
	else
	{
		util_out_print_gtmio("The LHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
		kill_hash.hash_code = 0;
	}
	/* $get(^#t(GVN,trigger_index,"BHASH") for deletion in cleanup_trigger_hash */
	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[BHASH_SUB],
		STRLEN(trigger_subs[BHASH_SUB]));
	if (gvcst_get(mv_val_ptr))
		set_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
	else
	{
		util_out_print_gtmio("The BHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
		set_hash.hash_code = 0;
	}
	/* kill ^#t(GVN,trigger_index) */
	BUILD_HASHT_SUB_MSUB_CURRKEY(trigvn, trigvn_len, trigger_index);
	gvcst_kill(TRUE);
	assert(0 == gvcst_data());
	if (1 == count)
	{ /* This is the last trigger for "trigvn" - clean up trigger name, remove #LABEL and #COUNT */
		assert(1 == index);
		BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL));
		gvcst_kill(TRUE);
		BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
		gvcst_kill(TRUE);
		cleanup_trigger_name(trigvn, trigvn_len, trig_name, trig_name_len);
		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, index);
	} else
	{
		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, index);
		cleanup_trigger_name(trigvn, trigvn_len, trig_name, trig_name_len);
		if (index != count)
		{	/* Shift the last trigger (index is #COUNT value) to the just deleted trigger's index.
			 * This way count is always accurate and can still be used as the index for new triggers.
			 * Note - there is no dependence on the trigger order, or this technique wouldn't work.
			 */
			ptr1 = tmp_trig_str;
			memcpy(ptr1, trigvn, trigvn_len);
			ptr1 += trigvn_len;
			*ptr1++ = '\0';
			tmp_len = trigvn_len + 1;
			for (sub_indx = 0; sub_indx < NUM_TOTAL_SUBS; sub_indx++)
			{
				/* $get(^#t(GVN,trigger_count,sub_indx) */
				BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[sub_indx],
								STRLEN(trigger_subs[sub_indx]));
				if (gvcst_get(&trigger_value))
				{
					trig_len = trigger_value.str.len;
					/* set ^#t(GVN,trigger_index,sub_indx)=^#t(GVN,trigger_count,sub_indx) */
					SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MVAL(trigvn, trigvn_len, trigger_index,
						trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), trigger_value, result);
					assert(PUT_SUCCESS == result);
				} else if (XECUTE_SUB == sub_indx)
				{	/* multi line trigger broken up because it exceeds record size */
					for (xecute_idx = 0; ; xecute_idx++)
					{
						i2mval(&xecute_index, xecute_idx);
						BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, *trigger_count,
							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index);
						if (!gvcst_get(&trigger_value))
							break;
						SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_MVAL(trigvn, trigvn_len, trigger_index,
							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index,
							trigger_value, result);
						assert(PUT_SUCCESS == result);
					}
					assert (xecute_idx >= 2); /* multi-line trigger, indices 0, 1 and 2 MUST be defined */
				} else
				{
					if (((TRIGNAME_SUB == sub_indx) || (CMD_SUB == sub_indx) ||
						 (CHSET_SUB == sub_indx)))
					{ /* CMD, NAME and CHSET cannot be zero length */
						if (CDB_STAGNATE > t_tries)
							t_retry(cdb_sc_triggermod);
						assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
						rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD,
								6, trigvn_len, trigvn, trigvn_len, trigvn,
								STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
					}
					/* OPTIONS, PIECES and DELIM can be zero */
					trig_len = 0;
				}
				if (NUM_SUBS > sub_indx)
				{
					tt_val[sub_indx] = ptr1;
					tt_val_len[sub_indx] = trig_len;
					tmp_len += trig_len;
					if (0 < trig_len)
					{
						if (MAX_BUFF_SIZE <= tmp_len)
						{ /* Exceeding the temporary buffer is impossible, restart*/
							if (CDB_STAGNATE > t_tries)
								t_retry(cdb_sc_triggermod);
							assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
							rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD,
									6, trigvn_len, trigvn, trigvn_len, trigvn,
									STRLEN(trigger_subs[sub_indx]), trigger_subs[sub_indx]);
						}
						memcpy(ptr1, trigger_value.str.addr, trig_len);
						ptr1 += trig_len;
					}
					*ptr1++ = '\0';
					tmp_len++;
				}
			}
			/* $get(^#t(GVN,trigger_count,"LHASH") for update_trigger_hash_value */
			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[LHASH_SUB],
							 STRLEN(trigger_subs[LHASH_SUB]));
			if (!gvcst_get(mv_val_ptr))
				return PUT_SUCCESS;
			kill_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
			/* $get(^#t(GVN,trigger_count,"BHASH") for update_trigger_hash_value */
			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[BHASH_SUB],
							 STRLEN(trigger_subs[BHASH_SUB]));
			if (!gvcst_get(mv_val_ptr))
				return PUT_SUCCESS;
			set_hash.hash_code = (uint4)MV_FORCE_UINT(mv_val_ptr);
			/* update hash values from above */
			if (VAL_TOO_LONG == (retval = update_trigger_hash_value(trigvn, trigvn_len, tt_val, tt_val_len,
					&set_hash, &kill_hash, count, index)))
				return VAL_TOO_LONG;
			/* fix the value ^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) to point to the correct "index" */
			if (VAL_TOO_LONG == (retval = update_trigger_name_value(tt_val[TRIGNAME_SUB],
					tt_val_len[TRIGNAME_SUB], index)))
				return VAL_TOO_LONG;
			/* kill ^#t(GVN,COUNT) which was just shifted to trigger_index */
			BUILD_HASHT_SUB_MSUB_CURRKEY(trigvn, trigvn_len, *trigger_count);
			gvcst_kill(TRUE);
		}
		/* Update #COUNT */
		count--;
		MV_FORCE_UMVAL(trigger_count, count);
		SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT), *trigger_count,
			result);
		assert(PUT_SUCCESS == result);		/* Size of count can only get shorter or stay the same */
	}
	return PUT_SUCCESS;
}
예제 #8
0
void trigger_delete_all(char *trigger_rec, uint4 len, uint4 *trig_stats)
{
	int			count;
	sgmnt_addrs		*csa;
	mval			curr_gbl_name;
	int			cycle;
	mval			*mv_count_ptr;
	mval			*mv_cycle_ptr;
	gd_region		*reg, *reg_top;
	int4			result;
	gd_region		*lgtrig_reg;
	mval			trigger_cycle;
	mval			trigger_count;
	boolean_t		this_db_updated;
	uint4			triggers_deleted;
	mval			trigjrec;
	boolean_t		jnl_format_done;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(0 < dollar_tlevel);
	jnl_format_done = FALSE;
	lgtrig_reg = NULL;
	trigjrec.mvtype = MV_STR;
	trigjrec.str.len = len;
	trigjrec.str.addr = trigger_rec;
	triggers_deleted = 0;
	for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
	{
		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
		csa = cs_addrs;
		if (NULL == csa)	/* not BG or MM access method */
			continue;
		/* gv_target now points to ^#t in region "reg" */
		/* To write the LGTRIG logical jnl record, choose some region that has journaling enabled */
		if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
			lgtrig_reg = reg;
		if (!gv_target->root)
			continue;
		/* kill ^#t("#TNAME") */
		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME));
		if (0 != gvcst_data())
		{	/* Issue error if we dont have permissions to touch ^#t global */
			if (reg->read_only)
				rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
			gvcst_kill(TRUE);
		}
		/* Kill all descendents of ^#t(trigvn, ...) where trigvn is any global with a trigger,
		 * but skip the ^#t("#...",...) entries. Setup ^#t("$") as the key for op_gvorder
		 */
		BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STRLEN(LITERAL_MAXHASHVAL));
		TREF(gv_last_subsc_null) = FALSE; /* We know its not null, but prior state is unreliable */
		this_db_updated = FALSE;
		while (TRUE)
		{
			op_gvorder(&curr_gbl_name);
			/* quit:$length(curr_gbl_name)=0 */
			if (0 == curr_gbl_name.str.len)
				break;
			/* $get(^#t(curr_gbl_name,#COUNT)) */
			BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
							LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
			if (gvcst_get(&trigger_count))
			{
				/* Now that we know there is something to kill, check if we have permissions to touch ^#t global */
				if (reg->read_only)
					rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
				mv_count_ptr = &trigger_count;
				count = MV_FORCE_UINT(mv_count_ptr);
				/* $get(^#t(curr_gbl_name,#CYCLE)) */
				BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
					LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE));
				if (!gvcst_get(&trigger_cycle))
				{	/* Found #COUNT, there must be #CYCLE */
					if (CDB_STAGNATE > t_tries)
						t_retry(cdb_sc_triggermod);
					assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
					rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_TRIGDEFBAD, 6,
							curr_gbl_name.str.len, curr_gbl_name.str.addr,
							curr_gbl_name.str.len, curr_gbl_name.str.addr, LEN_AND_LIT("\"#CYCLE\""),
							ERR_TEXT, 2, RTS_ERROR_TEXT("#CYCLE field is missing"));
				}
				mv_cycle_ptr = &trigger_cycle;
				cycle = MV_FORCE_UINT(mv_cycle_ptr);
				if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
				{
					jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
					jnl_format_done = TRUE;
				}
				/* kill ^#t(curr_gbl_name) */
				BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
				gvcst_kill(TRUE);
				/* Note : ^#t(curr_gbl_name,"#TRHASH") is also killed as part of the above */
				cycle++;
				MV_FORCE_MVAL(&trigger_cycle, cycle);
				/* set ^#t(curr_gbl_name,#CYCLE)=trigger_cycle */
				SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(curr_gbl_name.str.addr, curr_gbl_name.str.len,
					LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE), trigger_cycle, result);
				assert(PUT_SUCCESS == result);
				this_db_updated = TRUE;
				triggers_deleted += count;
			} /* else there is no #COUNT, then no triggers, leave #CYCLE alone */
			/* get ready for op_gvorder() call for next trigger under ^#t */
			BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
		}
		if (this_db_updated)
		{
			csa->incr_db_trigger_cycle = TRUE;
			if (dollar_ztrigger_invoked)
			{	/* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction,
				 * on this region, will re-read. See trigger_update.c for a comment on why it is okay
				 * for db_dztrigger_cycle to be incremented more than once in the same transaction
				 */
				csa->db_dztrigger_cycle++;
			}
		}
	}
	if (!jnl_format_done && (NULL != lgtrig_reg))
	{	/* There was no journaled region that had a ^#t update, but found at least one journaled region
		 * so write a LGTRIG logical jnl record there.
		 */
		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(lgtrig_reg);
		csa = cs_addrs;
		JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);	/* see previous usage for comment on why it is needed */
		assert(dollar_tlevel);
		T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);	/* needed to set update_trans TRUE on this region
									 * even if NO db updates happen to ^#t nodes. */
		jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
		jnl_format_done = TRUE;
	}
	if (triggers_deleted)
	{
		util_out_print_gtmio("All existing triggers (count = !UL) deleted", FLUSH, triggers_deleted);
		trig_stats[STATS_DELETED] += triggers_deleted;
		trig_stats[STATS_NOERROR_TRIGFILE]++;
	} else
	{
		util_out_print_gtmio("No matching triggers found for deletion", FLUSH);
		trig_stats[STATS_UNCHANGED_TRIGFILE]++;
	}
}
예제 #9
0
boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 *trig_stats)
{
	sgmnt_addrs		*csa;
	char			curr_name[MAX_MIDENT_LEN + 1];
	uint4			curr_name_len, orig_name_len;
	mval			mv_curr_nam;
	char			*ptr;
	char			*name_tail_ptr;
	char			save_name[MAX_MIDENT_LEN + 1];
	gv_key			save_currkey[DBKEYALLOC(MAX_KEY_SZ)];
	gd_region		*save_gv_cur_region, *lgtrig_reg;
	gv_namehead		*save_gv_target;
	sgm_info		*save_sgm_info_ptr;
	mval			trig_gbl;
	mval			*trigger_count;
	char			trigvn[MAX_MIDENT_LEN + 1];
	int			trigvn_len;
	int			trig_indx;
	int			badpos;
	boolean_t		wildcard;
	char			utilprefix[1024];
	int			utilprefixlen;
	boolean_t		first_gtmio;
	uint4			triggers_deleted;
	mval			trigjrec;
	boolean_t		jnl_format_done;
	gd_region		*reg, *reg_top;
	char			disp_trigvn[MAX_MIDENT_LEN + SPANREG_REGION_LITLEN + MAX_RN_LEN + 1 + 1];
					/* SPANREG_REGION_LITLEN for " (region ", MAX_RN_LEN for region name,
					 * 1 for ")" and 1 for trailing '\0'.
					 */
	int			disp_trigvn_len;
	int			trig_protected_mval_push_count;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	badpos = 0;
	trigjrec.mvtype = MV_STR;
	trigjrec.str.len = trigger_name_len--;
	trigjrec.str.addr = trigger_name++;
	orig_name_len = trigger_name_len;
	if ((0 == trigger_name_len)
		|| (trigger_name_len != (badpos = validate_input_trigger_name(trigger_name, trigger_name_len, &wildcard))))
	{	/* is the input name valid */
		CONV_STR_AND_PRINT("Invalid trigger NAME string: ", orig_name_len, trigger_name);
		/* badpos is the string position where the bad character was found, pretty print it */
		trig_stats[STATS_ERROR_TRIGFILE]++;
		return TRIG_FAILURE;
	}
	name_tail_ptr = trigger_name + trigger_name_len - 1;
	if ((TRIGNAME_SEQ_DELIM == *name_tail_ptr) || wildcard)
		trigger_name_len--; /* drop the trailing # sign for wildcard */
	jnl_format_done = FALSE;
	lgtrig_reg = NULL;
	first_gtmio = TRUE;
	triggers_deleted = 0;
	assert(trigger_name_len < MAX_MIDENT_LEN);
	memcpy(save_name, trigger_name, trigger_name_len);
	save_name[trigger_name_len] = '\0';
	utilprefixlen = ARRAYSIZE(utilprefix);
	trig_protected_mval_push_count = 0;
	INCR_AND_PUSH_MV_STENT(trigger_count); /* Protect trigger_count from garbage collection */
	for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions; reg < reg_top; reg++)
	{
		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(reg);
		csa = cs_addrs;
		if (NULL == csa)	/* not BG or MM access method */
			continue;
		/* gv_target now points to ^#t in region "reg" */
		/* To write the LGTRIG logical jnl record, choose some region that has journaling enabled */
		if (!reg->read_only && !jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
			lgtrig_reg = reg;
		if (!gv_target->root)
			continue;
		memcpy(curr_name, save_name, trigger_name_len);
		curr_name_len = trigger_name_len;
		do {
			/* GVN = $get(^#t("#TNAME",curr_name)) */
			BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), curr_name, curr_name_len);
			if (gvcst_get(&trig_gbl))
			{
				if (reg->read_only)
					rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(reg));
				SAVE_TRIGGER_REGION_INFO(save_currkey);
				ptr = trig_gbl.str.addr;
				trigvn_len = MIN(trig_gbl.str.len, MAX_MIDENT_LEN);
				STRNLEN(ptr, trigvn_len, trigvn_len);
				ptr += trigvn_len;
				if ((trig_gbl.str.len == trigvn_len) || ('\0' != *ptr))
				{	/* We expect $c(0) in the middle of ptr. If not found, this is a restartable situation */
					if (CDB_STAGNATE > t_tries)
						t_retry(cdb_sc_triggermod);
					assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""),
							curr_name_len, curr_name);
				}
				memcpy(trigvn, trig_gbl.str.addr, trigvn_len);
				/* the index is just beyond the length of the GVN string */
				ptr++;
				A2I(ptr, trig_gbl.str.addr + trig_gbl.str.len, trig_indx);
				if (1 > trig_indx)
				{	/* Trigger indexes start from 1 */
					if (CDB_STAGNATE > t_tries)
						t_retry(cdb_sc_triggermod);
					assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""),
							curr_name_len, curr_name);
				}
				SET_DISP_TRIGVN(reg, disp_trigvn, disp_trigvn_len, trigvn, trigvn_len);
				/* $get(^#t(GVN,"COUNT") */
				BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
				if (!gvcst_get(trigger_count))
				{
					UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
					util_out_print_gtmio("Trigger named !AD exists in the lookup table, "
							"but global ^!AD has no triggers",
							FLUSH, curr_name_len, curr_name, disp_trigvn_len, disp_trigvn);
					trig_stats[STATS_ERROR_TRIGFILE]++;
					RETURN_AND_POP_MVALS(TRIG_FAILURE);
				}
				if (!jnl_format_done && JNL_WRITE_LOGICAL_RECS(csa))
				{
					jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
					jnl_format_done = TRUE;
				}
				/* kill the target trigger for GVN at index trig_indx */
				if (PUT_SUCCESS != (trigger_delete(trigvn, trigvn_len, trigger_count, trig_indx)))
				{
					UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
					util_out_print_gtmio("Trigger named !AD exists in the lookup table for global ^!AD,"	\
								" but was not deleted!", FLUSH, orig_name_len, trigger_name,
								disp_trigvn_len, disp_trigvn);
					trig_stats[STATS_ERROR_TRIGFILE]++;
					RETURN_AND_POP_MVALS(TRIG_FAILURE);
				} else
				{
					csa->incr_db_trigger_cycle = TRUE;
					trigger_incr_cycle(trigvn, trigvn_len);	/* ^#t records changed, increment cycle */
					if (dollar_ztrigger_invoked)
					{	/* Increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this
						 * transaction, on this region, will re-read triggers. See trigger_update.c
						 * for a comment on why it is okay for db_dztrigger_cycle to be incremented
						 * more than once in the same transaction.
						 */
						csa->db_dztrigger_cycle++;
					}
					trig_stats[STATS_DELETED]++;
					if (0 == trig_stats[STATS_ERROR_TRIGFILE])
					{
						UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
						util_out_print_gtmio("Deleted trigger named '!AD' for global ^!AD",
								FLUSH, curr_name_len, curr_name, disp_trigvn_len, disp_trigvn);
					}
				}
				trigger_count->mvtype = 0; /* allow stp_gcol to release the current contents if necessary */
				RESTORE_TRIGGER_REGION_INFO(save_currkey);
				triggers_deleted++;
			}
			if (!wildcard)
				/* not a wild card, don't $order for the next match */
				break;
			op_gvorder(&mv_curr_nam);
			if (0 == mv_curr_nam.str.len)
				break;
			assert(mv_curr_nam.str.len < MAX_MIDENT_LEN);
			memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
			curr_name_len = mv_curr_nam.str.len;
			if (0 != memcmp(curr_name, save_name, trigger_name_len))
				/* stop when gv_order returns a string that no longer starts save_name */
				break;
		} while (TRUE);
	}
	DECR_AND_POP_MV_STENT();
	if (!jnl_format_done && (NULL != lgtrig_reg))
	{	/* There was no journaled region that had a ^#t update, but found at least one journaled region
		 * so write a LGTRIG logical jnl record there.
		 */
		GVTR_SWITCH_REG_AND_HASHT_BIND_NAME(lgtrig_reg);
		csa = cs_addrs;
		/* Attach to jnlpool. Normally SET or KILL of the ^#t records take care of this but in
		 * case this is a NO-OP trigger operation that wont update any ^#t records and we still
		 * want to write a TLGTRIG/ULGTRIG journal record. Hence the need to do this.
		 */
		JNLPOOL_INIT_IF_NEEDED(csa, csa->hdr, csa->nl);
		assert(dollar_tlevel);
		/* below is needed to set update_trans TRUE on this region even if NO db updates happen to ^#t nodes */
		T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_TRIGLOADFAIL);
		jnl_format(JNL_LGTRIG, NULL, &trigjrec, 0);
		jnl_format_done = TRUE;
	}
	if (wildcard)
	{
		UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
		if (triggers_deleted)
		{
			trig_stats[STATS_NOERROR_TRIGFILE]++;
			util_out_print_gtmio("All existing triggers named !AD (count = !UL) now deleted",
				FLUSH, orig_name_len, trigger_name, triggers_deleted);
		} else
		{
			trig_stats[STATS_UNCHANGED_TRIGFILE]++;
			util_out_print_gtmio("No matching triggers of the form !AD found for deletion",
				FLUSH, orig_name_len, trigger_name);
		}
	} else if (triggers_deleted)
	{
		/* util_out_print_gtmio of "Deleted trigger named ..." already done so no need to do it again */
		trig_stats[STATS_NOERROR_TRIGFILE]++;
	} else
	{	/* No names match. But treat it as a no-op (i.e. success). */
		UTIL_PRINT_PREFIX_IF_NEEDED(first_gtmio, utilprefix, &utilprefixlen);
		util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
		trig_stats[STATS_UNCHANGED_TRIGFILE]++;
	}
	return TRIG_SUCCESS;
}
예제 #10
0
void trigger_delete_all(void)
{
	int			count;
	char			count_str[MAX_DIGITS_IN_INT + 1];
	sgmnt_addrs		*csa;
	mval			curr_gbl_name;
	int			cycle;
	mstr			gbl_name;
	mname_entry		gvent;
	gv_namehead		*hasht_tree, *gvt;
	mval			*mv_count_ptr;
	mval			*mv_cycle_ptr;
	mval			mv_indx;
	gd_region		*reg;
	int			reg_indx;
	int4			result;
	char			save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)];
	gv_key			*save_gv_currkey;
	gd_region		*save_gv_cur_region;
	gv_namehead		*save_gv_target;
	sgm_info		*save_sgm_info_ptr;
	int			trig_indx;
	mval			trigger_cycle;
	mval			trigger_count;
	mval			val;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(0 < dollar_tlevel);
	/* Before we delete any triggers, verify that none of the triggers have been fired in this transaction. If they have,
	 * this creates an un-commitable transaction that will end in a TPFAIL error. Since that error indicates database
	 * damage, we'd rather detect this avoidable condition and give a descriptive error instead (TRIGMODINTP).
	 */
	for (gvt = gv_target_list; NULL != gvt; gvt = gvt->next_gvnh)
	{
		if (gvt->trig_local_tn == local_tn)
			rts_error(VARLSTCNT(1) ERR_TRIGMODINTP);
	}
	SWITCH_TO_DEFAULT_REGION;
	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
	if (0 != gv_target->root)
	{
		/* kill ^#t("#TRHASH") */
		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTRHASH, STRLEN(LITERAL_HASHTRHASH));
		gvcst_kill(TRUE);
		/* kill ^#t("#TNAME") */
		BUILD_HASHT_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME));
		gvcst_kill(TRUE);
	}
	for (reg_indx = 0, reg = gd_header->regions; reg_indx < gd_header->n_regions; reg_indx++, reg++)
	{
		if (!reg->open)
			gv_init_reg(reg);
		if (!reg->read_only)
		{
			gv_cur_region = reg;
			change_reg();
			csa = cs_addrs;
			SETUP_TRIGGER_GLOBAL;
			INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
			/* There might not be any ^#t in this region, so check */
			if (0 != gv_target->root)
			{	/* Kill all descendents of ^#t(trigvn, indx) where trigvn is any global with a trigger,
				 * but skip the "#XYZ" entries. setup ^#t(trigvn,"$") as the PREV key for op_gvorder
				 */
				BUILD_HASHT_SUB_CURRKEY(LITERAL_MAXHASHVAL, STRLEN(LITERAL_MAXHASHVAL));
				TREF(gv_last_subsc_null) = FALSE; /* We know its not null, but prior state is unreliable */
				while (TRUE)
				{
					op_gvorder(&curr_gbl_name);
					/* quit:$length(curr_gbl_name)=0 */
					if (0 == curr_gbl_name.str.len)
						break;
					/* $get(^#t(curr_gbl_name,#COUNT)) */
					BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
						LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
					if (gvcst_get(&trigger_count))
					{
						mv_count_ptr = &trigger_count;
						count = MV_FORCE_INT(mv_count_ptr);
						/* $get(^#t(curr_gbl_name,#CYCLE)) */
						BUILD_HASHT_SUB_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len,
							LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE));
						if (!gvcst_get(&trigger_cycle))
							assert(FALSE); /* Found #COUNT, there must be #CYCLE */
						mv_cycle_ptr = &trigger_cycle;
						cycle = MV_FORCE_INT(mv_cycle_ptr);
						/* kill ^#t(curr_gbl_name) */
						BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
						gvcst_kill(TRUE);
						cycle++;
						MV_FORCE_MVAL(&trigger_cycle, cycle);
						/* set ^#t(curr_gbl_name,#CYCLE)=trigger_cycle */
						SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(curr_gbl_name.str.addr, curr_gbl_name.str.len,
							LITERAL_HASHCYCLE, STRLEN(LITERAL_HASHCYCLE), trigger_cycle, result);
						assert(PUT_SUCCESS == result);
					} /* else there is no #COUNT, then no triggers, leave #CYCLE alone */
					/* get ready for op_gvorder() call for next trigger under ^#t */
					BUILD_HASHT_SUB_CURRKEY(curr_gbl_name.str.addr, curr_gbl_name.str.len);
				}
				csa->incr_db_trigger_cycle = TRUE;
				if (dollar_ztrigger_invoked)
				{	/* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction,
					 * on this region, will re-read. See trigger_update.c for a comment on why it is okay
					 * for db_dztrigger_cycle to be incremented more than once in the same transaction
					 */
					csa->db_dztrigger_cycle++;
				}
			}
		}
	}
	util_out_print_gtmio("All existing triggers deleted", FLUSH);
}
예제 #11
0
int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index)
{
	int			count;
	mval			*mv_cnt_ptr;
	mval			mv_val;
	mval			*mv_val_ptr;
	int			num_len;
	char			*ptr1;
	int4			result;
	int4			retval;
	char			save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)];
	gv_key			*save_gv_currkey;
	stringkey		kill_hash, set_hash;
	int			sub_indx;
	char			tmp_trig_str[MAX_BUFF_SIZE];
	int4			trig_len;
	char			trig_name[MAX_TRIGNAME_LEN];
	int			trig_name_len;
	int			tmp_len;
	char			*tt_val[NUM_SUBS];
	uint4			tt_val_len[NUM_SUBS];
	mval			trigger_value;
	mval			trigger_index;
	mval			xecute_index;
	uint4			xecute_idx;
	uint4			used_trigvn_len;
	mval			val;
	char			val_str[MAX_DIGITS_IN_INT + 1];
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	mv_val_ptr = &mv_val;
	MV_FORCE_MVAL(&trigger_index, index);
	count = MV_FORCE_INT(trigger_count);
	/* build up array of values - needed for comparison in hash stuff */
	ptr1 = tmp_trig_str;
	memcpy(ptr1, trigvn, trigvn_len);
	ptr1 += trigvn_len;
	*ptr1++ = '\0';
	tmp_len = trigvn_len + 1;
	for (sub_indx = 0; sub_indx < NUM_SUBS; sub_indx++)
	{
		BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[sub_indx],
						 STRLEN(trigger_subs[sub_indx]));
		trig_len = gvcst_get(&trigger_value) ? trigger_value.str.len : 0;
		if (0 == trig_len)
		{
			tt_val[sub_indx] = NULL;
			tt_val_len[sub_indx] = 0;
			continue;
		}
		if (TRIGNAME_SUB == sub_indx)
		{
			trig_name_len = trig_len;
			assert(MAX_TRIGNAME_LEN >= trig_len);
			memcpy(trig_name, trigger_value.str.addr, trig_name_len);
			tt_val[sub_indx] = NULL;
			tt_val_len[sub_indx] = 0;
			continue;
		}
		tt_val[sub_indx] = ptr1;
		tt_val_len[sub_indx] = trig_len;
		tmp_len += trig_len;
		if (0 < trig_len)
		{
			if (MAX_BUFF_SIZE <= tmp_len)
				return VAL_TOO_LONG;
			memcpy(ptr1, trigger_value.str.addr, trig_len);
			ptr1 += trig_len;
		}
		*ptr1++ = '\0';
		tmp_len++;
	}
	/* Get trigger name, set hash value, and kill hash values from trigger before we delete it.
	 * The values will be used in clean ups associated with the deletion
	 */
	/* $get(^#t(GVN,trigger_index,"LHASH") for deletion in  cleanup_trigger_hash */
	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[LHASH_SUB],
		STRLEN(trigger_subs[LHASH_SUB]));
	if (gvcst_get(mv_val_ptr))
		kill_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
	else {
		util_out_print_gtmio("The LHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
		kill_hash.hash_code = 0;
	}
	/* $get(^#t(GVN,trigger_index,"BHASH") for deletion in  cleanup_trigger_hash */
	BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, trigger_index, trigger_subs[BHASH_SUB],
		STRLEN(trigger_subs[BHASH_SUB]));
	if (gvcst_get(mv_val_ptr))
		set_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
	else {
		util_out_print_gtmio("The BHASH for global ^!AD does not exist", FLUSH, trigvn_len, trigvn);
		set_hash.hash_code = 0;
	}
	/* kill ^#t(GVN,trigger_index) */
	BUILD_HASHT_SUB_MSUB_CURRKEY(trigvn, trigvn_len, trigger_index);
	gvcst_kill(TRUE);
	assert(0 == gvcst_data());
	if (1 == count)
	{ /* This is the last trigger for "trigvn" - clean up trigger name, remove #LABEL and #COUNT */
		assert(1 == index);
		BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL));
		gvcst_kill(TRUE);
		BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
		gvcst_kill(TRUE);
		cleanup_trigger_name(trigvn, trigvn_len, trig_name, trig_name_len);
		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, 0);
	} else
	{
		cleanup_trigger_hash(trigvn, trigvn_len, tt_val, tt_val_len, &set_hash, &kill_hash, TRUE, index);
		cleanup_trigger_name(trigvn, trigvn_len, trig_name, trig_name_len);
		if (index != count)
		{	/* Shift the last trigger (index is #COUNT value) to the just deleted trigger's index.
			 * This way count is always accurate and can still be used as the index for new triggers.
			 * Note - there is no dependence on the trigger order, or this technique wouldn't work.
			 */
			ptr1 = tmp_trig_str;
			memcpy(ptr1, trigvn, trigvn_len);
			ptr1 += trigvn_len;
			*ptr1++ = '\0';
			for (sub_indx = 0; sub_indx < NUM_TOTAL_SUBS; sub_indx++)
			{
				/* $get(^#t(GVN,trigger_count,sub_indx) */
				BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[sub_indx],
								STRLEN(trigger_subs[sub_indx]));
				if (gvcst_get(&trigger_value))
				{
					trig_len = trigger_value.str.len;
					/* set ^#t(GVN,trigger_index,sub_indx)=^#t(GVN,trigger_count,sub_indx) */
					SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MVAL(trigvn, trigvn_len, trigger_index,
						trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), trigger_value, result);
					assert(PUT_SUCCESS == result);
				} else if (XECUTE_SUB == sub_indx)
				{ /* multi line trigger broken up because it exceeds record size */
					for (xecute_idx = 0; ; xecute_idx++)
					{
						i2mval(&xecute_index, xecute_idx);
						BUILD_HASHT_SUB_MSUB_SUB_MSUB_CURRKEY(trigvn, trigvn_len, *trigger_count,
							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index);
						if (!gvcst_get(&trigger_value))
							break;
						SET_TRIGGER_GLOBAL_SUB_MSUB_SUB_MSUB_MVAL(trigvn, trigvn_len, trigger_index,
							trigger_subs[sub_indx], STRLEN(trigger_subs[sub_indx]), xecute_index,
							trigger_value, result);
						assert(PUT_SUCCESS == result);
					}
					assert (xecute_idx >= 2); /* multi-line trigger, indices 0, 1 and 2 MUST be defined */
				} else
				{
					/* in PRO this is a nasty case that will result in an access violation
					 * because data that should be present is not. In the next go around
					 * with trigger installation this case should be handled better */
					assert(!((TRIGNAME_SUB == sub_indx) || (CMD_SUB == sub_indx) ||
						 (CHSET_SUB == sub_indx))); /* these should not be zero length */
					trig_len = 0;
				}
				if (NUM_SUBS > sub_indx)
				{
					tt_val[sub_indx] = ptr1;
					tt_val_len[sub_indx] = trig_len;
					if (0 < trig_len)
					{
						memcpy(ptr1, trigger_value.str.addr, trig_len);
						ptr1 += trig_len;
					}
					*ptr1++ = '\0';
				}
			}
			/* $get(^#t(GVN,trigger_count,"LHASH") for update_trigger_hash_value */
			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[LHASH_SUB],
							 STRLEN(trigger_subs[LHASH_SUB]));
			if (!gvcst_get(mv_val_ptr))
				return PUT_SUCCESS;
			kill_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
			/* $get(^#t(GVN,trigger_count,"BHASH") for update_trigger_hash_value */
			BUILD_HASHT_SUB_MSUB_SUB_CURRKEY(trigvn, trigvn_len, *trigger_count, trigger_subs[BHASH_SUB],
							 STRLEN(trigger_subs[BHASH_SUB]));
			if (!gvcst_get(mv_val_ptr))
				return PUT_SUCCESS;
			set_hash.hash_code = (uint4)MV_FORCE_INT(mv_val_ptr);
			/* update hash values from above */
			if (VAL_TOO_LONG == (retval = update_trigger_hash_value(trigvn, trigvn_len, tt_val, tt_val_len,
					&set_hash, &kill_hash, count, index)))
				return VAL_TOO_LONG;
			/* fix the value ^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) to point to the correct "index" */
			if (VAL_TOO_LONG == (retval = update_trigger_name_value(trigvn_len, tt_val[TRIGNAME_SUB],
					tt_val_len[TRIGNAME_SUB], index)))
				return VAL_TOO_LONG;
			/* kill ^#t(GVN,COUNT) which was just shifted to trigger_index */
			BUILD_HASHT_SUB_MSUB_CURRKEY(trigvn, trigvn_len, *trigger_count);
			gvcst_kill(TRUE);
		}
		/* Update #COUNT */
		count--;
		MV_FORCE_MVAL(trigger_count, count);
		SET_TRIGGER_GLOBAL_SUB_SUB_MVAL(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT), *trigger_count,
			result);
		assert(PUT_SUCCESS == result);		/* Size of count can only get shorter or stay the same */
	}
	trigger_incr_cycle(trigvn, trigvn_len);
	return PUT_SUCCESS;
}
예제 #12
0
boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 *trig_stats)
{
	sgmnt_addrs		*csa;
	char			curr_name[MAX_MIDENT_LEN + 1];
	uint4			curr_name_len, orig_name_len;
	mstr			gbl_name;
	mname_entry		gvent;
	gv_namehead		*hasht_tree;
	int			len;
	mval			mv_curr_nam;
	boolean_t		name_found;
	char			*ptr;
	char			*name_tail_ptr;
	char			save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)];
	gv_key			*save_gv_currkey;
	gd_region		*save_gv_cur_region;
	gv_namehead		*save_gv_target;
	char			save_name[MAX_MIDENT_LEN + 1];
	sgm_info		*save_sgm_info_ptr;
	mval			trig_gbl;
	mval			trig_value;
	mval			trigger_count;
	char			trigvn[MAX_MIDENT_LEN + 1];
	int			trigvn_len;
	int			trig_indx;
	int			badpos;
	boolean_t		wildcard;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	badpos = 0;
	orig_name_len = trigger_name_len;
	if ((0 == trigger_name_len) || (trigger_name_len !=
			(badpos = validate_input_trigger_name(trigger_name, trigger_name_len, &wildcard))))
	{	/* is the input name valid */
		CONV_STR_AND_PRINT("Invalid trigger NAME string: ", orig_name_len, trigger_name);
		/* badpos is the string position where the bad character was found, pretty print it */
		return TRIG_FAILURE;
	}
	name_tail_ptr = trigger_name + trigger_name_len - 1;
	if (TRIGNAME_SEQ_DELIM == *name_tail_ptr || wildcard )
		/* drop the trailing # sign or wildcard */
		trigger_name_len--;
	/* $data(^#t) */
	SWITCH_TO_DEFAULT_REGION;
	INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
	if (0 == gv_target->root)
	{
		util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
		return TRIG_FAILURE;
	}
	name_found = FALSE;
	assert(trigger_name_len < MAX_MIDENT_LEN);
	memcpy(save_name, trigger_name, trigger_name_len);
	save_name[trigger_name_len] = '\0';
	memcpy(curr_name, save_name, trigger_name_len);
	curr_name_len = trigger_name_len;
	STR2MVAL(mv_curr_nam, trigger_name, trigger_name_len);
	do {
		/* GVN = $get(^#t("#TNAME",curr_name) */
		BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), curr_name, curr_name_len);
		if (gvcst_get(&trig_gbl))
		{
			SAVE_TRIGGER_REGION_INFO;
			ptr = trig_gbl.str.addr;
			trigvn_len = STRLEN(trig_gbl.str.addr);
			assert(MAX_MIDENT_LEN >= trigvn_len);
			memcpy(trigvn, ptr, trigvn_len);
			ptr += trigvn_len + 1;
			/* the index is just beyon the length of the GVN string */
			A2I(ptr, trig_gbl.str.addr + trig_gbl.str.len, trig_indx);
			gbl_name.addr = trigvn;
			gbl_name.len = trigvn_len;
			GV_BIND_NAME_ONLY(gd_header, &gbl_name);
			csa = gv_target->gd_csa;
			SETUP_TRIGGER_GLOBAL;
			INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
			/* $get(^#t(GVN,"COUNT") */
			BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHCOUNT, STRLEN(LITERAL_HASHCOUNT));
			/* if it does not exist, return false */
			if (!gvcst_get(&trigger_count))
			{
				util_out_print_gtmio("Trigger named !AD exists in the lookup table, "
						"but global ^!AD has no triggers",
						FLUSH, curr_name_len, curr_name, trigvn_len, trigvn);
				return TRIG_FAILURE;
			}
			/* kill the target trigger for GVN at index trig_indx */
			if (PUT_SUCCESS != (trigger_delete(trigvn, trigvn_len, &trigger_count, trig_indx)))
			{
				util_out_print_gtmio("Trigger named !AD exists in the lookup table, but was not deleted!",
						FLUSH, orig_name_len, trigger_name);
			} else
			{
				csa->incr_db_trigger_cycle = TRUE;
				if (dollar_ztrigger_invoked)
				{	/* increment db_dztrigger_cycle so that next gvcst_put/gvcst_kill in this transaction,
					 * on this region, will re-read triggers. See trigger_update.c for a comment on why
					 * it is okay for db_dztrigger_cycle to be incremented more than once in the same
					 * transaction
					 */
					csa->db_dztrigger_cycle++;
				}
				trig_stats[STATS_DELETED]++;
				if (0 == trig_stats[STATS_ERROR])
					util_out_print_gtmio("Deleted trigger named '!AD' for global ^!AD",
							FLUSH, curr_name_len, curr_name, trigvn_len, trigvn);
			}
			RESTORE_TRIGGER_REGION_INFO;
			name_found = TRUE;
		} else
		{ /* no names match, if !wildcard report an error */
			if (!wildcard)
			{
				util_out_print_gtmio("Trigger named !AD does not exist",
						FLUSH, orig_name_len, trigger_name);
				return TRIG_FAILURE;
			}
		}
		if (!wildcard)
			/* not a wild card, don't $order for the next match */
			break;
		op_gvorder(&mv_curr_nam);
		if (0 == mv_curr_nam.str.len)
			break;
		assert(mv_curr_nam.str.len < MAX_MIDENT_LEN);
		memcpy(curr_name, mv_curr_nam.str.addr, mv_curr_nam.str.len);
		curr_name_len = mv_curr_nam.str.len;
		if (0 != memcmp(curr_name, save_name, trigger_name_len))
			/* stop when gv_order returns a string that no longer starts save_name */
			break;
	} while (wildcard);
	if (name_found)
		return TRIG_SUCCESS;
	util_out_print_gtmio("Trigger named !AD does not exist", FLUSH, orig_name_len, trigger_name);
	return TRIG_FAILURE;
}
예제 #13
0
STATICFNDEF boolean_t trigger_trgfile_tpwrap_helper(char *trigger_filename, uint4 trigger_filename_len, boolean_t noprompt,
						    boolean_t lcl_implicit_tpwrap)
{
	boolean_t		all_triggers_error;
	uint4			i;
	io_pair			io_save_device;
	io_pair			io_trigfile_device;
	int			len;
	int4			record_num;
	boolean_t		trigger_status;
	enum cdb_sc		cdb_status;
	uint4			trig_stats[NUM_STATS];
	char			*trigger_rec;
	char			*values[NUM_SUBS];
	unsigned short		value_len[NUM_SUBS];

	all_triggers_error = FALSE;
	if (lcl_implicit_tpwrap)
		ESTABLISH_RET(trigger_tpwrap_ch, TRIG_FAILURE);	/* Return through here is a failure */
	io_save_device = io_curr_device;
	file_input_init(trigger_filename, trigger_filename_len);
	if (mupip_error_occurred)
		TRIG_ERROR_RETURN;
	io_trigfile_device = io_curr_device;
	record_num = 0;
	for (i = 0; NUM_STATS > i; i++)
		trig_stats[i] = 0;
	while ((0 == io_curr_device.in->dollar.zeof) && (0 <= (len = file_input_get(&trigger_rec))))
	{
		io_curr_device = io_save_device;
		record_num++;
		if ((0 != len) && (COMMENT_LITERAL != trigger_rec[0]))
			util_out_print_gtmio("File !AD, Line !UL: ", NOFLUSH, trigger_filename_len, trigger_filename, record_num);
		trigger_status = trigger_update_rec(trigger_rec, (uint4)len, noprompt, trig_stats, &io_trigfile_device,
						    &record_num);
		all_triggers_error |= (TRIG_FAILURE == trigger_status);
		io_curr_device = io_trigfile_device;
	}
	if ((-1 == len) && (!io_curr_device.in->dollar.zeof))
	{
		io_curr_device = io_save_device;
		util_out_print_gtmio("File !AD, Line !UL: Line too long", FLUSH, trigger_filename_len, trigger_filename,
			++record_num);
	}
	file_input_close();
	io_curr_device = io_save_device;
	if (all_triggers_error)
	{
		util_out_print_gtmio("=========================================", FLUSH);
		util_out_print_gtmio("!UL trigger file entries matched existing triggers", FLUSH, trig_stats[STATS_UNCHANGED]);
		util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR]);
		util_out_print_gtmio("!UL trigger file entries have no errors", FLUSH,
				     trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_MODIFIED]);
		util_out_print_gtmio("=========================================", FLUSH);
		TRIG_ERROR_RETURN;
	}
	if (lcl_implicit_tpwrap)
	{
		GVTR_OP_TCOMMIT(cdb_status);
		if (cdb_sc_normal != cdb_status)
			t_retry(cdb_status);	/* won't return */
		REVERT;
	}
	if ((0 == trig_stats[STATS_ERROR])
		&& (0 != (trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_UNCHANGED]
			  + trig_stats[STATS_MODIFIED])))
	{
		util_out_print_gtmio("=========================================", FLUSH);
		util_out_print_gtmio("!UL triggers added", FLUSH, trig_stats[STATS_ADDED]);
		util_out_print_gtmio("!UL triggers deleted", FLUSH, trig_stats[STATS_DELETED]);
		util_out_print_gtmio("!UL trigger file entries not changed", FLUSH, trig_stats[STATS_UNCHANGED]);
		util_out_print_gtmio("!UL triggers modified", FLUSH, trig_stats[STATS_MODIFIED]);
		util_out_print_gtmio("=========================================", FLUSH);
	} else if (0 != trig_stats[STATS_ERROR])
	{
		util_out_print_gtmio("=========================================", FLUSH);
		util_out_print_gtmio("!UL trigger file entries matched existing triggers", FLUSH, trig_stats[STATS_UNCHANGED]);
		util_out_print_gtmio("!UL trigger file entries have errors", FLUSH, trig_stats[STATS_ERROR]);
		util_out_print_gtmio("!UL trigger file entries have no errors", FLUSH,
			       trig_stats[STATS_ADDED] + trig_stats[STATS_DELETED] + trig_stats[STATS_MODIFIED]);
		util_out_print_gtmio("=========================================", FLUSH);
	}
	return TRIG_SUCCESS;
}