Commit 3681b3ec authored by cmiller@zippy.cornsilk.net's avatar cmiller@zippy.cornsilk.net

Merge bk-internal.mysql.com:/home/bk/mysql-4.1

into  zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-4.1-maint
parents 80dadacb e9bdddfa
...@@ -2629,7 +2629,7 @@ com_connect(String *buffer, char *line) ...@@ -2629,7 +2629,7 @@ com_connect(String *buffer, char *line)
bzero(buff, sizeof(buff)); bzero(buff, sizeof(buff));
if (buffer) if (buffer)
{ {
strmov(buff, line); strmake(buff, line, sizeof(buff) - 1);
tmp= get_arg(buff, 0); tmp= get_arg(buff, 0);
if (tmp && *tmp) if (tmp && *tmp)
{ {
...@@ -2743,7 +2743,7 @@ com_use(String *buffer __attribute__((unused)), char *line) ...@@ -2743,7 +2743,7 @@ com_use(String *buffer __attribute__((unused)), char *line)
char *tmp, buff[FN_REFLEN + 1]; char *tmp, buff[FN_REFLEN + 1];
bzero(buff, sizeof(buff)); bzero(buff, sizeof(buff));
strmov(buff, line); strmake(buff, line, sizeof(buff) - 1);
tmp= get_arg(buff, 0); tmp= get_arg(buff, 0);
if (!tmp || !*tmp) if (!tmp || !*tmp)
{ {
......
...@@ -1352,3 +1352,16 @@ select database(); ...@@ -1352,3 +1352,16 @@ select database();
database() database()
имя_базы_в_кодировке_утф8_длиной_больше_чем_45 имя_базы_в_кодировке_утф8_длиной_больше_чем_45
drop database имя_базы_в_кодировке_утф8_длиной_больше_чем_45; drop database имя_базы_в_кодировке_утф8_длиной_больше_чем_45;
use test;
create table t1(a char(10)) default charset utf8;
insert into t1 values ('123'), ('456');
explain
select substr(Z.a,-1), Z.a from t1 as Y join t1 as Z on Y.a=Z.a order by 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Y ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
1 SIMPLE Z ALL NULL NULL NULL NULL 2 Using where
select substr(Z.a,-1), Z.a from t1 as Y join t1 as Z on Y.a=Z.a order by 1;
substr(Z.a,-1) a
3 123
6 456
drop table t1;
...@@ -694,6 +694,18 @@ t1 CREATE TABLE `t1` ( ...@@ -694,6 +694,18 @@ t1 CREATE TABLE `t1` (
`from_unixtime(1) + 0` double(23,6) default NULL `from_unixtime(1) + 0` double(23,6) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
SET NAMES latin1;
SET character_set_results = NULL;
SHOW VARIABLES LIKE 'character_set_results';
Variable_name Value
character_set_results
CREATE TABLE testBug8868 (field1 DATE, field2 VARCHAR(32) CHARACTER SET BINARY);
INSERT INTO testBug8868 VALUES ('2006-09-04', 'abcd');
SELECT DATE_FORMAT(field1,'%b-%e %l:%i%p') as fmtddate, field2 FROM testBug8868;
fmtddate field2
Sep-4 12:00AM abcd
DROP TABLE testBug8868;
SET NAMES DEFAULT;
(select time_format(timediff(now(), DATE_SUB(now(),INTERVAL 5 DAY)),'%H') As H) (select time_format(timediff(now(), DATE_SUB(now(),INTERVAL 5 DAY)),'%H') As H)
union union
(select time_format(timediff(now(), DATE_SUB(now(),INTERVAL 5 DAY)),'%H') As H); (select time_format(timediff(now(), DATE_SUB(now(),INTERVAL 5 DAY)),'%H') As H);
......
...@@ -272,3 +272,10 @@ desc t3; ...@@ -272,3 +272,10 @@ desc t3;
Field Type Null Key Default Extra Field Type Null Key Default Extra
a double 0 a double 0
drop table t1,t2,t3; drop table t1,t2,t3;
select 1e-308, 1.00000001e-300, 100000000e-300;
1e-308 1.00000001e-300 100000000e-300
0 1.00000001e-300 1e-292
select 10e307;
10e307
1e+308
End of 4.1 tests
...@@ -1087,5 +1087,17 @@ create database имя_базы_в_кодировке_утф8_длиной_бо ...@@ -1087,5 +1087,17 @@ create database имя_базы_в_кодировке_утф8_длиной_бо
use имя_базы_в_кодировке_утф8_длиной_больше_чем_45; use имя_базы_в_кодировке_утф8_длиной_больше_чем_45;
select database(); select database();
drop database имя_базы_в_кодировке_утф8_длиной_больше_чем_45; drop database имя_базы_в_кодировке_утф8_длиной_больше_чем_45;
use test;
#
# Bug #20204: "order by" changes the results returned
#
create table t1(a char(10)) default charset utf8;
insert into t1 values ('123'), ('456');
explain
select substr(Z.a,-1), Z.a from t1 as Y join t1 as Z on Y.a=Z.a order by 1;
select substr(Z.a,-1), Z.a from t1 as Y join t1 as Z on Y.a=Z.a order by 1;
drop table t1;
# End of 4.1 tests # End of 4.1 tests
...@@ -368,6 +368,25 @@ create table t1 select now() - now(), curtime() - curtime(), ...@@ -368,6 +368,25 @@ create table t1 select now() - now(), curtime() - curtime(),
show create table t1; show create table t1;
drop table t1; drop table t1;
#
# 21913: DATE_FORMAT() Crashes mysql server if I use it through
# mysql-connector-j driver.
#
SET NAMES latin1;
SET character_set_results = NULL;
SHOW VARIABLES LIKE 'character_set_results';
CREATE TABLE testBug8868 (field1 DATE, field2 VARCHAR(32) CHARACTER SET BINARY);
INSERT INTO testBug8868 VALUES ('2006-09-04', 'abcd');
SELECT DATE_FORMAT(field1,'%b-%e %l:%i%p') as fmtddate, field2 FROM testBug8868;
DROP TABLE testBug8868;
SET NAMES DEFAULT;
# #
# Bug #19844 time_format in Union truncates values # Bug #19844 time_format in Union truncates values
# #
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# i.e. lower_case_filesystem=OFF # i.e. lower_case_filesystem=OFF
# #
-- source include/have_case_sensitive_file_system.inc -- source include/have_case_sensitive_file_system.inc
-- source include/not_embedded.inc
connect (master,localhost,root,,); connect (master,localhost,root,,);
connection master; connection master;
......
...@@ -179,4 +179,13 @@ show warnings; ...@@ -179,4 +179,13 @@ show warnings;
desc t3; desc t3;
drop table t1,t2,t3; drop table t1,t2,t3;
# End of 4.1 tests #
# Bug #22129: A small double precision number becomes zero
#
# check if underflows are detected correctly
select 1e-308, 1.00000001e-300, 100000000e-300;
# check if overflows are detected correctly
select 10e307;
--echo End of 4.1 tests
...@@ -7,6 +7,6 @@ ndbapiincludedir = "$(pkgincludedir)/ndb/ndbapi" ...@@ -7,6 +7,6 @@ ndbapiincludedir = "$(pkgincludedir)/ndb/ndbapi"
mgmapiincludedir = "$(pkgincludedir)/ndb/mgmapi" mgmapiincludedir = "$(pkgincludedir)/ndb/mgmapi"
INCLUDES = $(INCLUDES_LOC) INCLUDES = $(INCLUDES_LOC)
LDADD = $(top_srcdir)/ndb/src/common/portlib/gcc.cpp $(LDADD_LOC) LDADD = $(LDADD_LOC) -L$(top_srcdir)/ndb/src/common/portlib -lmygcc
DEFS = @DEFS@ @NDB_DEFS@ $(DEFS_LOC) $(NDB_EXTRA_FLAGS) DEFS = @DEFS@ @NDB_DEFS@ $(DEFS_LOC) $(NDB_EXTRA_FLAGS)
NDB_CXXFLAGS=@ndb_cxxflags_fix@ $(NDB_CXXFLAGS_LOC) NDB_CXXFLAGS=@ndb_cxxflags_fix@ $(NDB_CXXFLAGS_LOC)
...@@ -3,7 +3,7 @@ LDADD += \ ...@@ -3,7 +3,7 @@ LDADD += \
$(top_builddir)/ndb/src/libndbclient.la \ $(top_builddir)/ndb/src/libndbclient.la \
$(top_builddir)/dbug/libdbug.a \ $(top_builddir)/dbug/libdbug.a \
$(top_builddir)/mysys/libmysys.a \ $(top_builddir)/mysys/libmysys.a \
$(top_builddir)/strings/libmystrings.a @NDB_SCI_LIBS@ $(top_builddir)/strings/libmystrings.a @NDB_SCI_LIBS@ -lmygcc
INCLUDES += -I$(srcdir) -I$(top_srcdir)/include \ INCLUDES += -I$(srcdir) -I$(top_srcdir)/include \
-I$(top_srcdir)/ndb/include \ -I$(top_srcdir)/ndb/include \
......
noinst_HEADERS = gcc.cpp noinst_LIBRARIES = libmygcc.a
libmygcc_a_SOURCES = gcc.cpp
noinst_LTLIBRARIES = libportlib.la noinst_LTLIBRARIES = libportlib.la
......
...@@ -53,7 +53,8 @@ LDADD += \ ...@@ -53,7 +53,8 @@ LDADD += \
$(top_builddir)/ndb/src/common/util/libgeneral.la \ $(top_builddir)/ndb/src/common/util/libgeneral.la \
$(top_builddir)/dbug/libdbug.a \ $(top_builddir)/dbug/libdbug.a \
$(top_builddir)/mysys/libmysys.a \ $(top_builddir)/mysys/libmysys.a \
$(top_builddir)/strings/libmystrings.a @NDB_SCI_LIBS@ $(top_builddir)/strings/libmystrings.a @NDB_SCI_LIBS@ -lmygcc
# Don't update the files from bitkeeper # Don't update the files from bitkeeper
%::SCCS/s.% %::SCCS/s.%
......
...@@ -1109,12 +1109,13 @@ void Item_func_substr::fix_length_and_dec() ...@@ -1109,12 +1109,13 @@ void Item_func_substr::fix_length_and_dec()
} }
if (arg_count == 3 && args[2]->const_item()) if (arg_count == 3 && args[2]->const_item())
{ {
int32 length= (int32) args[2]->val_int() * collation.collation->mbmaxlen; int32 length= (int32) args[2]->val_int();
if (length <= 0) if (length <= 0)
max_length=0; /* purecov: inspected */ max_length=0; /* purecov: inspected */
else else
set_if_smaller(max_length,(uint) length); set_if_smaller(max_length,(uint) length);
} }
max_length*= collation.collation->mbmaxlen;
} }
......
...@@ -6552,10 +6552,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ...@@ -6552,10 +6552,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
} }
switch (method-1) { switch (method-1) {
case 0: case 0:
method_conv= MI_STATS_METHOD_NULLS_EQUAL; method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
break; break;
case 1: case 1:
method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL; method_conv= MI_STATS_METHOD_NULLS_EQUAL;
break; break;
case 2: case 2:
method_conv= MI_STATS_METHOD_IGNORE_NULLS; method_conv= MI_STATS_METHOD_IGNORE_NULLS;
......
...@@ -248,6 +248,10 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs) ...@@ -248,6 +248,10 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs)
0 No conversion needed 0 No conversion needed
1 Either character set conversion or adding leading zeros 1 Either character set conversion or adding leading zeros
(e.g. for UCS-2) must be done (e.g. for UCS-2) must be done
NOTE
to_cs may be NULL for "no conversion" if the system variable
character_set_results is NULL.
*/ */
bool String::needs_conversion(uint32 arg_length, bool String::needs_conversion(uint32 arg_length,
...@@ -256,7 +260,8 @@ bool String::needs_conversion(uint32 arg_length, ...@@ -256,7 +260,8 @@ bool String::needs_conversion(uint32 arg_length,
uint32 *offset) uint32 *offset)
{ {
*offset= 0; *offset= 0;
if ((to_cs == &my_charset_bin) || if (!to_cs ||
(to_cs == &my_charset_bin) ||
(to_cs == from_cs) || (to_cs == from_cs) ||
my_charset_same(from_cs, to_cs) || my_charset_same(from_cs, to_cs) ||
((from_cs == &my_charset_bin) && ((from_cs == &my_charset_bin) &&
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#ifdef HAVE_STACKTRACE #ifdef HAVE_STACKTRACE
#include <unistd.h> #include <unistd.h>
#include <strings.h>
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end) #define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
...@@ -44,7 +45,29 @@ void safe_print_str(const char* name, const char* val, int max_len) ...@@ -44,7 +45,29 @@ void safe_print_str(const char* name, const char* val, int max_len)
} }
#ifdef TARGET_OS_LINUX #ifdef TARGET_OS_LINUX
#define SIGRETURN_FRAME_COUNT 2
#ifdef __i386__
#define SIGRETURN_FRAME_OFFSET 17
#endif
#ifdef __x86_64__
#define SIGRETURN_FRAME_OFFSET 23
#endif
static my_bool is_nptl;
/* Check if we are using NPTL or LinuxThreads on Linux */
void check_thread_lib(void)
{
char buf[5];
#ifdef _CS_GNU_LIBPTHREAD_VERSION
confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof(buf));
is_nptl = !strncasecmp(buf, "NPTL", sizeof(buf));
#else
is_nptl = 0;
#endif
}
#if defined(__alpha__) && defined(__GNUC__) #if defined(__alpha__) && defined(__GNUC__)
/* /*
...@@ -90,7 +113,7 @@ inline uint32* find_prev_pc(uint32* pc, uchar** fp) ...@@ -90,7 +113,7 @@ inline uint32* find_prev_pc(uint32* pc, uchar** fp)
void print_stacktrace(gptr stack_bottom, ulong thread_stack) void print_stacktrace(gptr stack_bottom, ulong thread_stack)
{ {
uchar** fp; uchar** fp;
uint frame_count = 0; uint frame_count = 0, sigreturn_frame_count;
#if defined(__alpha__) && defined(__GNUC__) #if defined(__alpha__) && defined(__GNUC__)
uint32* pc; uint32* pc;
#endif #endif
...@@ -104,24 +127,23 @@ terribly wrong...\n"); ...@@ -104,24 +127,23 @@ terribly wrong...\n");
__asm __volatile__ ("movl %%ebp,%0" __asm __volatile__ ("movl %%ebp,%0"
:"=r"(fp) :"=r"(fp)
:"r"(fp)); :"r"(fp));
if (!fp) #endif
{ #ifdef __x86_64__
fprintf(stderr, "frame pointer (ebp) is NULL, did you compile with\n\ __asm __volatile__ ("movq %%rbp,%0"
-fomit-frame-pointer? Aborting backtrace!\n"); :"=r"(fp)
return; :"r"(fp));
}
#endif #endif
#if defined(__alpha__) && defined(__GNUC__) #if defined(__alpha__) && defined(__GNUC__)
__asm __volatile__ ("mov $30,%0" __asm __volatile__ ("mov $30,%0"
:"=r"(fp) :"=r"(fp)
:"r"(fp)); :"r"(fp));
#endif
if (!fp) if (!fp)
{ {
fprintf(stderr, "frame pointer (fp) is NULL, did you compile with\n\ fprintf(stderr, "frame pointer is NULL, did you compile with\n\
-fomit-frame-pointer? Aborting backtrace!\n"); -fomit-frame-pointer? Aborting backtrace!\n");
return; return;
} }
#endif /* __alpha__ */
if (!stack_bottom || (gptr) stack_bottom > (gptr) &fp) if (!stack_bottom || (gptr) stack_bottom > (gptr) &fp)
{ {
...@@ -151,13 +173,16 @@ terribly wrong...\n"); ...@@ -151,13 +173,16 @@ terribly wrong...\n");
:"r"(pc)); :"r"(pc));
#endif /* __alpha__ */ #endif /* __alpha__ */
/* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
sigreturn_frame_count = is_nptl ? 1 : 2;
while (fp < (uchar**) stack_bottom) while (fp < (uchar**) stack_bottom)
{ {
#ifdef __i386__ #if defined(__i386__) || defined(__x86_64__)
uchar** new_fp = (uchar**)*fp; uchar** new_fp = (uchar**)*fp;
fprintf(stderr, "%p\n", frame_count == SIGRETURN_FRAME_COUNT ? fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
*(fp+17) : *(fp+1)); *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
#endif /* __386__ */ #endif /* defined(__386__) || defined(__x86_64__) */
#if defined(__alpha__) && defined(__GNUC__) #if defined(__alpha__) && defined(__GNUC__)
uchar** new_fp = find_prev_fp(pc, fp); uchar** new_fp = find_prev_fp(pc, fp);
......
...@@ -19,16 +19,20 @@ extern "C" { ...@@ -19,16 +19,20 @@ extern "C" {
#endif #endif
#ifdef TARGET_OS_LINUX #ifdef TARGET_OS_LINUX
#if defined(HAVE_STACKTRACE) || (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) #if defined(HAVE_STACKTRACE) || (defined (__x86_64__) || defined (__i386__) || (defined(__alpha__) && defined(__GNUC__)))
#undef HAVE_STACKTRACE #undef HAVE_STACKTRACE
#define HAVE_STACKTRACE #define HAVE_STACKTRACE
extern char* __bss_start; extern char* __bss_start;
extern char* heap_start; extern char* heap_start;
#define init_stacktrace() { heap_start = (char*) &__bss_start; } #define init_stacktrace() do { \
heap_start = (char*) &__bss_start; \
check_thread_lib(); \
} while(0);
void print_stacktrace(gptr stack_bottom, ulong thread_stack); void print_stacktrace(gptr stack_bottom, ulong thread_stack);
void safe_print_str(const char* name, const char* val, int max_len); void safe_print_str(const char* name, const char* val, int max_len);
void check_thread_lib(void);
#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */ #endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
#endif /* TARGET_OS_LINUX */ #endif /* TARGET_OS_LINUX */
......
...@@ -30,7 +30,8 @@ ...@@ -30,7 +30,8 @@
#include <m_ctype.h> #include <m_ctype.h>
#define MAX_DBL_EXP 308 #define MAX_DBL_EXP 308
#define MAX_RESULT_FOR_MAX_EXP 1.79769313486232 #define MAX_RESULT_FOR_MAX_EXP 1.7976931348623157
#define MIN_RESULT_FOR_MIN_EXP 2.225073858507202
static double scaler10[] = { static double scaler10[] = {
1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90
}; };
...@@ -57,10 +58,11 @@ double my_strtod(const char *str, char **end_ptr, int *error) ...@@ -57,10 +58,11 @@ double my_strtod(const char *str, char **end_ptr, int *error)
{ {
double result= 0.0; double result= 0.0;
uint negative= 0, ndigits, dec_digits= 0, neg_exp= 0; uint negative= 0, ndigits, dec_digits= 0, neg_exp= 0;
int exp= 0, digits_after_dec_point= 0; int exp= 0, digits_after_dec_point= 0, tmp_exp;
const char *old_str, *end= *end_ptr, *start_of_number; const char *old_str, *end= *end_ptr, *start_of_number;
char next_char; char next_char;
my_bool overflow=0; my_bool overflow=0;
double scaler= 1.0;
*error= 0; *error= 0;
if (str >= end) if (str >= end)
...@@ -91,6 +93,7 @@ double my_strtod(const char *str, char **end_ptr, int *error) ...@@ -91,6 +93,7 @@ double my_strtod(const char *str, char **end_ptr, int *error)
while ((next_char= *str) >= '0' && next_char <= '9') while ((next_char= *str) >= '0' && next_char <= '9')
{ {
result= result*10.0 + (next_char - '0'); result= result*10.0 + (next_char - '0');
scaler= scaler*10.0;
if (++str == end) if (++str == end)
{ {
next_char= 0; /* Found end of string */ next_char= 0; /* Found end of string */
...@@ -114,6 +117,7 @@ double my_strtod(const char *str, char **end_ptr, int *error) ...@@ -114,6 +117,7 @@ double my_strtod(const char *str, char **end_ptr, int *error)
{ {
result= result*10.0 + (next_char - '0'); result= result*10.0 + (next_char - '0');
digits_after_dec_point++; digits_after_dec_point++;
scaler= scaler*10.0;
if (++str == end) if (++str == end)
{ {
next_char= 0; next_char= 0;
...@@ -144,39 +148,54 @@ double my_strtod(const char *str, char **end_ptr, int *error) ...@@ -144,39 +148,54 @@ double my_strtod(const char *str, char **end_ptr, int *error)
} while (str < end && my_isdigit(&my_charset_latin1, *str)); } while (str < end && my_isdigit(&my_charset_latin1, *str));
} }
} }
if ((exp= (neg_exp ? exp + digits_after_dec_point : tmp_exp= neg_exp ? exp + digits_after_dec_point : exp - digits_after_dec_point;
exp - digits_after_dec_point))) if (tmp_exp)
{
double scaler;
if (exp < 0)
{
exp= -exp;
neg_exp= 1; /* neg_exp was 0 before */
}
if (exp + ndigits >= MAX_DBL_EXP + 1 && result)
{ {
int order;
/* /*
This is not 100 % as we actually will give an owerflow for Check for underflow/overflow.
17E307 but not for 1.7E308 but lets cut some corners to make life order is such an integer number that f = C * 10 ^ order,
simpler where f is the resulting floating point number and 1 <= C < 10.
Here we compute the modulus
*/ */
if (exp + ndigits > MAX_DBL_EXP + 1 || order= exp + (neg_exp ? -1 : 1) * (ndigits - 1);
result >= MAX_RESULT_FOR_MAX_EXP) if (order < 0)
{ order= -order;
if (order >= MAX_DBL_EXP && result)
{
double c;
/* Compute modulus of C (see comment above) */
c= result / scaler * 10.0;
if (neg_exp) if (neg_exp)
{
if (order > MAX_DBL_EXP || c < MIN_RESULT_FOR_MIN_EXP)
{
result= 0.0; result= 0.0;
goto done;
}
}
else else
{
if (order > MAX_DBL_EXP || c > MAX_RESULT_FOR_MAX_EXP)
{
overflow= 1; overflow= 1;
goto done; goto done;
} }
} }
scaler= 1.0; }
exp= tmp_exp;
if (exp < 0)
{
exp= -exp;
neg_exp= 1; /* neg_exp was 0 before */
}
while (exp >= 100) while (exp >= 100)
{ {
scaler*= 1.0e100; result= neg_exp ? result/1.0e100 : result*1.0e100;
exp-= 100; exp-= 100;
} }
scaler*= scaler10[exp/10]*scaler1[exp%10]; scaler= scaler10[exp/10]*scaler1[exp%10];
if (neg_exp) if (neg_exp)
result/= scaler; result/= scaler;
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment