summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormwesdorp <mwesdorp>2013-07-20 16:18:35 +0000
committermwesdorp <mwesdorp>2013-07-20 16:18:35 +0000
commit401914fae46f2c9d8b20e2fcf806f69844a20d12 (patch)
treea156be6fa3242a43105e2a1324aff96a80e4095a /src
parent85624b6169eee1219ce692d75bdea94ff526be44 (diff)
sqsh-2.3 new features and bugfixes
Diffstat (limited to 'src')
-rw-r--r--src/cmd_connect.c10
-rw-r--r--src/cmd_do.c41
-rw-r--r--src/cmd_func.c8
-rw-r--r--src/cmd_input.c128
-rw-r--r--src/config.h.in7
-rw-r--r--src/dsp_conv.c246
-rw-r--r--src/dsp_desc.c368
-rw-r--r--src/dsp_html.c32
-rw-r--r--src/dsp_meta.c70
-rw-r--r--src/sqsh_config.h2
-rw-r--r--src/sqsh_global.c8
-rw-r--r--src/sqsh_global.h15
-rw-r--r--src/sqsh_init.c36
-rw-r--r--src/sqsh_job.c4
-rw-r--r--src/sqsh_readline.c224
-rw-r--r--src/var.h3
-rw-r--r--src/var_misc.c71
17 files changed, 915 insertions, 358 deletions
diff --git a/src/cmd_connect.c b/src/cmd_connect.c
index 964e659..681e754 100644
--- a/src/cmd_connect.c
+++ b/src/cmd_connect.c
@@ -42,7 +42,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: cmd_connect.c,v 1.31 2013/05/05 19:50:43 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: cmd_connect.c,v 1.32 2013/07/20 16:18:35 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -1247,8 +1247,6 @@ int cmd_connect( argc, argv )
/*-- If autouse has been set, use it --*/
if (autouse != NULL && *autouse != '\0')
{
- CS_INT ret = CS_SUCCEED;
-
if (ct_cmd_alloc( g_connection, &cmd ) != CS_SUCCEED)
goto connect_succeed;
@@ -1271,12 +1269,8 @@ int cmd_connect( argc, argv )
goto connect_succeed;
}
- while (ct_results( cmd, &result_type ) != CS_END_RESULTS) {
- if(result_type == CS_CMD_FAIL)
- ret = CS_FAIL;
- }
+ while (ct_results( cmd, &result_type ) != CS_END_RESULTS);
ct_cmd_drop( cmd );
-
}
connect_succeed:
diff --git a/src/cmd_do.c b/src/cmd_do.c
index e110c95..c7a5ccf 100644
--- a/src/cmd_do.c
+++ b/src/cmd_do.c
@@ -51,8 +51,8 @@ static int cmd_do_exec _ANSI_ARGS(( CS_CONNECTION*, char*,
char* ));
/*
-** sg_jmp_buf: The following buffer is used to contain the location
-** to which this module will return upon receipt of a
+** sg_jmp_buf: The following buffer is used to contain the location
+** to which this module will return upon receipt of a
** SIGINT. It is only used while waiting on input from the
** user.
*/
@@ -86,9 +86,9 @@ int cmd_do( argc, argv )
*/
env_tran( g_env );
- while ((ch = sqsh_getopt( argc, argv, "S:U:P:D:n" )) != EOF)
+ while ((ch = sqsh_getopt( argc, argv, "S:U:P:D:n" )) != EOF)
{
- switch (ch)
+ switch (ch)
{
case 'n' :
do_connection = False;
@@ -107,7 +107,7 @@ int cmd_do( argc, argv )
ret = env_put( g_env, "database", sqsh_optarg, ENV_F_TRAN );
break;
default :
- ret = False;
+ ret = False;
}
if (ret != True)
@@ -121,9 +121,9 @@ int cmd_do( argc, argv )
** If there are any errors on the command line, or there are
** any options left over then we have an error.
*/
- if( (argc - sqsh_optind) > 0 || have_error == True)
+ if( (argc - sqsh_optind) > 0 || have_error == True)
{
- fprintf( stderr,
+ fprintf( stderr,
"Use: \\do [-n] [-S server] [-U user] [-P pass] [-D db]\n"
" -n Do not establish new connection (cannot issue SQL)\n"
" -S Perform do-loop on specified server\n"
@@ -194,7 +194,7 @@ int cmd_do( argc, argv )
return(CMD_FAIL);
}
- if (sqsh_expand( varbuf_getstr( g_sqlbuf ), expand_buf,
+ if (sqsh_expand( varbuf_getstr( g_sqlbuf ), expand_buf,
(EXP_STRIPESC|EXP_COMMENT|EXP_COLUMNS) ) == False)
{
fprintf( stderr, "\\do: Expansion failure: %s\n",
@@ -223,7 +223,7 @@ int cmd_do( argc, argv )
orig_conn = g_connection;
/*
- ** And replace then with new copies. Note that setting
+ ** And replace then with new copies. Note that setting
** g_connection to NULL will cause a new connection to be
** established for us by \connect.
*/
@@ -240,7 +240,7 @@ int cmd_do( argc, argv )
if (do_connection == True)
{
g_connection = NULL;
- if (jobset_run( g_jobset, "\\connect", &exit_status ) == -1)
+ if (jobset_run( g_jobset, "\\connect", &exit_status ) == -1)
{
fprintf( stderr, "\\do: Connect failed\n" );
ret = exit_status;
@@ -252,7 +252,7 @@ int cmd_do( argc, argv )
ret = cmd_do_exec( orig_conn, sql, varbuf_getstr(do_buf) );
}
- if (do_connection == True &&
+ if (do_connection == True &&
g_connection != NULL)
{
if (ct_close( g_connection, CS_UNUSED ) != CS_SUCCEED)
@@ -330,7 +330,7 @@ static int cmd_do_exec( conn, sql, dobuf )
/*
** Suck in the results.
*/
- while ((retcode = ct_results( cmd, &result_type ))
+ while ((retcode = ct_results( cmd, &result_type ))
== CS_SUCCEED)
{
/*
@@ -385,7 +385,7 @@ static int cmd_do_exec( conn, sql, dobuf )
/*
** Save away the column description in the global table
- ** of column descriptions (these will be referenced
+ ** of column descriptions (these will be referenced
** during expansion of the sqlbuf.
*/
g_do_cols[g_do_ncols] = desc;
@@ -400,8 +400,8 @@ static int cmd_do_exec( conn, sql, dobuf )
** For each row we fetch back, we want to execute
** the dobuf.
*/
- if ((ret = cmd_input()) == CMD_FAIL ||
- ret == CMD_ABORT ||
+ if ((ret = cmd_input()) == CMD_FAIL ||
+ ret == CMD_ABORT ||
ret == CMD_INTERRUPTED ||
ret == CMD_BREAK ||
ret == CMD_RETURN)
@@ -602,7 +602,7 @@ int cmd_body_input( buf )
if (*cp == '\\')
{
++cp;
- for(i = 0; i < (sizeof(cmd)-1) && *cp != '\0' &&
+ for(i = 0; i < (sizeof(cmd)-1) && *cp != '\0' &&
isalpha((int)*cp); ++i, ++cp)
{
cmd[i] = *cp;
@@ -628,9 +628,10 @@ int cmd_body_input( buf )
prompt_indent[i] = '\0';
env_put( g_env, "prompt_indent", prompt_indent, ENV_F_TRAN );
}
- else if ((strcmp( cmd, "do" ) == 0) ||
- strcmp( cmd, "func" ) == 0 ||
- strcmp( cmd, "while" ) == 0)
+ else if ( strcmp( cmd, "do" ) == 0 ||
+ strcmp( cmd, "for" ) == 0 || /* sqsh-2.3 - Improvement suggested by Niki Hansche */
+ strcmp( cmd, "func" ) == 0 ||
+ strcmp( cmd, "while" ) == 0)
{
/*
** If we hit another \do statement, then we want to
@@ -673,7 +674,7 @@ static void cmd_do_sigint_cancel( sig, user_data )
{
if (user_data != NULL)
{
- ct_cancel( (CS_CONNECTION*)user_data, (CS_COMMAND*)NULL,
+ ct_cancel( (CS_CONNECTION*)user_data, (CS_COMMAND*)NULL,
CS_CANCEL_ATTN );
}
sg_canceled = True;
diff --git a/src/cmd_func.c b/src/cmd_func.c
index 1dcb4f4..5f52dfd 100644
--- a/src/cmd_func.c
+++ b/src/cmd_func.c
@@ -70,13 +70,12 @@ int cmd_func( argc, argv )
do_export = True;
break;
default :
- fprintf( stderr, "\\func: -%c: Invalid option\n",
- (int)ch );
+ fprintf( stderr, "\\func: %s\n", sqsh_get_errstr());
have_error = True;
}
}
- if ((argc - sqsh_optind) != 1)
+ if ( have_error || (argc - sqsh_optind) != 1)
{
fprintf( stderr, "Use: \\func [-x] <name>\n" );
fprintf( stderr, " <body>\n" );
@@ -181,8 +180,7 @@ int cmd_call( argc, argv )
if (f == NULL)
{
- fprintf( stderr, "\\call: Error calling %s: %s\n",
- func_name ? (char*)func_name : "NULL", sqsh_get_errstr() );
+ fprintf( stderr, "\\call: Error calling %s: %s\n", func_name ? (char*)func_name : "NULL", sqsh_get_errstr() );
return(CMD_FAIL);
}
diff --git a/src/cmd_input.c b/src/cmd_input.c
index 2a9172c..60bf67c 100644
--- a/src/cmd_input.c
+++ b/src/cmd_input.c
@@ -52,7 +52,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: cmd_input.c,v 1.8 2013/04/25 14:09:47 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: cmd_input.c,v 1.9 2013/07/20 16:18:35 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -63,6 +63,8 @@ static int input_read _ANSI_ARGS(( varbuf_t*, int ));
#if defined(USE_READLINE)
static int DynKeywordLoad _ANSI_ARGS(( void )); /* sqsh-2.1.8 - Feature dynamic keyword load */
#endif
+/* sqsh-2.3 - Check if we currently are in a C style comment in the SQL buffer */
+static int csc_buffer _ANSI_ARGS(( varbuf_t* ));
/*
* The following macro is used to determine if a line of input is
@@ -365,8 +367,8 @@ int cmd_input()
*/
env_get( g_env, "semicolon_hack", &semicolon_hack );
env_get( g_env, "semicolon_hack2", &semicolon_hack2 );
- if ( (strchr( str, ';') != NULL && (ch = input_strchr( g_sqlbuf, str, ';' )) != NULL) &&
- ((semicolon_hack != NULL && *semicolon_hack == '1' && !is_cmd) ||
+ if ( (strchr( str, ';') != NULL && (ch = input_strchr( g_sqlbuf, str, ';' )) != NULL) &&
+ ((semicolon_hack != NULL && *semicolon_hack == '1' && !is_cmd) ||
(semicolon_hack2 != NULL && *semicolon_hack2 == '1'))
)
{
@@ -871,8 +873,12 @@ static int input_read( output_buf, interactive )
* table name, [_0-9A-Za-z]. If we hit a comment, then we
* simply ignore this line, without even incrementing the
* line number.
+ * sqsh-2.3 - Only ignore sqsh # comments if the current
+ * SQL buffer did not start a C style comment construct,
+ * that is not closed so far, and if we are not inside a
+ * single or double quotes string.
*/
- if (IS_COMMENT(str))
+ if (IS_COMMENT(str) && csc_buffer( g_sqlbuf ) == 0)
{
if (is_continued)
{
@@ -1073,6 +1079,120 @@ static char* input_strchr( varbuf, str, c )
}
/*
+ * csc_buffer():
+ *
+ * sqsh-2.3 - Blast through the SQL buffer that is created up
+ * till now and see if we are in a quoted or double
+ * quoted string or in a C style comment.
+ * Return the value of the quote_type that reflects the
+ * current situation. (0 means not in quotes or comments)
+ */
+static int csc_buffer( varbuf )
+ varbuf_t *varbuf;
+{
+#define QUOTE_NONE 0
+#define QUOTE_SINGLE 1
+#define QUOTE_DOUBLE 2
+#define QUOTE_COMMENT 3
+
+ char *cptr;
+ int quote_type = QUOTE_NONE;
+ int csclevel = 0;
+
+
+ if ( (cptr = varbuf_getstr(varbuf)) == NULL )
+ return QUOTE_NONE;
+
+ /*-- Blast through varbuf --*/
+ for (; *cptr != '\0'; ++cptr)
+ {
+ /*
+ * First step over any escape characters and the character
+ * that is escaped by \\ itself, but still do a sanity
+ * check on end of string altogether.
+ */
+ if (*cptr == '\\' && *(cptr + 1) == '\\')
+ {
+ cptr += 3;
+ if (*cptr == '\0' || *(cptr - 1) == '\0')
+ break;
+ }
+
+ switch (quote_type)
+ {
+ case QUOTE_NONE:
+ switch (*cptr)
+ {
+ case '\'':
+ quote_type = QUOTE_SINGLE;
+ break;
+ case '\"':
+ quote_type = QUOTE_DOUBLE;
+ break;
+ case '/' :
+ if (*(cptr + 1) == '*')
+ {
+ quote_type = QUOTE_COMMENT;
+ ++csclevel;
+ ++cptr;
+ }
+ break;
+ case '-': /* -- comment till end of end line */
+ if (*(cptr + 1) == '-')
+ {
+ while (*cptr != '\n' && *cptr != '\0')
+ ++cptr;
+
+ if (*cptr == '\0')
+ --cptr;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case QUOTE_COMMENT:
+ /*
+ * C style comments in SQL may be nested, but do not
+ * take quoting or -- comments in account anymore.
+ * This is according to isql behavior.
+ */
+ if (*cptr == '/' && *(cptr + 1) == '*')
+ {
+ ++cptr;
+ ++csclevel;
+ }
+ else if (*cptr == '*' && *(cptr + 1) == '/')
+ {
+ ++cptr;
+ if (--csclevel == 0)
+ quote_type = QUOTE_NONE;
+ }
+ break;
+
+ case QUOTE_SINGLE:
+ if (*cptr == '\'')
+ {
+ quote_type = QUOTE_NONE;
+ }
+ break;
+
+ case QUOTE_DOUBLE:
+ if (*cptr == '\"')
+ {
+ quote_type = QUOTE_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return quote_type;
+}
+
+/*
* input_sigint_jmp():
*
* Used to catch ^C's from the user. If there is currently a database
diff --git a/src/config.h.in b/src/config.h.in
index 56f5fd8..aa2abc0 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -81,4 +81,11 @@
*/
#undef SYSV_SIGNALS
+/*
+ * sqsh-2.3 : Test availability of locale
+ */
+#undef HAVE_LOCALE_H
+#undef HAVE_LOCALECONV
+#undef HAVE_SETLOCALE
+
#endif
diff --git a/src/dsp_conv.c b/src/dsp_conv.c
index 44d75d1..eec24b3 100644
--- a/src/dsp_conv.c
+++ b/src/dsp_conv.c
@@ -28,10 +28,15 @@
#include "sqsh_error.h"
#include "sqsh_compat.h"
#include "dsp.h"
+#include "config.h"
+
+#if defined(HAVE_LOCALE_H)
+#include <locale.h>
+#endif
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: dsp_conv.c,v 1.5 2013/04/18 11:54:43 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: dsp_conv.c,v 1.6 2013/07/20 16:18:35 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -52,9 +57,18 @@ static int sg_datetime_len = -1;
static int sg_datetime4_len = -1;
static int sg_date_len = -1;
static int sg_time_len = -1;
+static int sg_bigdatetime_len = -1;
+static int sg_bigtime_len = -1;
+#if defined(HAVE_SETLOCALE)
+static char *sg_locale = NULL;
+#endif
+#if defined(CS_BIGDATETIME_TYPE) && defined(CS_BIGTIME_TYPE)
+static char sg_datetime_def[64] = "%b %d %Y %l:%M:%S.%q%p";
+static char sg_time_def[64] = "%l:%M:%S.%q%p";
+#endif
/*-- Prototypes --*/
-static CS_INT dsp_type_len _ANSI_ARGS(( CS_CONTEXT*, CS_CHAR*,
+static CS_INT dsp_type_len _ANSI_ARGS(( CS_CONTEXT*, CS_CHAR*,
CS_DATAFMT*, CS_VOID* ));
static char* dsp_datetime_strip _ANSI_ARGS(( CS_INT, char*, int ));
@@ -75,8 +89,9 @@ int dsp_datetimefmt_set( fmt )
* we are now changing the format from what it was, these
* variables should be reset.
*/
- sg_datetime_len = -1;
- sg_datetime4_len = -1;
+ sg_datetime_len = -1;
+ sg_datetime4_len = -1;
+ sg_bigdatetime_len = -1;
/*
* If the format is NULL or "default", then we simply store
@@ -195,7 +210,8 @@ int dsp_timefmt_set( fmt )
* we are now changing the format from what it was, these
* variables should be reset.
*/
- sg_time_len = -1;
+ sg_time_len = -1;
+ sg_bigtime_len = -1;
/*
* If the format is NULL or "default", then we simply store
@@ -241,11 +257,12 @@ char* dsp_timefmt_get()
*
* Calculates the maximum number of characters required to store
* a date in a string format of the current locale. This function
- * is similar to dsp_money_len() except that every month is
+ * is similar to dsp_money_len() except that every month is
* converted to verify if particular month names are longer than
* others.
*
* sqsh-2.1.9 - Also implement date and time datatype conversions.
+ * sqsh-2.3 - Improve handling of bigdatetime and bigtime data types.
*/
CS_INT dsp_datetime_len( ctxt, type )
CS_CONTEXT *ctxt;
@@ -260,6 +277,30 @@ CS_INT dsp_datetime_len( ctxt, type )
int max_len;
int len;
char *fmt;
+#if defined(CS_BIGDATETIME_TYPE) && defined(CS_BIGTIME_TYPE)
+ char *conv_fmt;
+#endif
+#if defined(HAVE_SETLOCALE)
+ char *locale;
+
+ /*
+ * sqsh-2.3 : If the locale was changed recently, we have to reset
+ * the cached type len values.
+ */
+ locale = setlocale (LC_ALL, NULL);
+ if ( sg_locale != locale )
+ {
+ DBG(sqsh_debug(DEBUG_DISPLAY, "locale changed to %s\n", locale);)
+
+ sg_locale = locale;
+ sg_datetime_len = -1;
+ sg_datetime4_len = -1;
+ sg_date_len = -1;
+ sg_time_len = -1;
+ sg_bigdatetime_len = -1;
+ sg_bigtime_len = -1;
+ }
+#endif
/*
* Check to see if we have cached the value from the last time
@@ -276,13 +317,6 @@ CS_INT dsp_datetime_len( ctxt, type )
return sg_datetime4_len;
}
-#if defined(CS_BIGDATETIME_TYPE)
- if (type == CS_BIGDATETIME_TYPE && sg_datetime_len != -1)
- {
- return sg_datetime_len;
- }
-#endif
-
#if defined(CS_DATE_TYPE)
if (type == CS_DATE_TYPE && sg_date_len != -1)
{
@@ -297,10 +331,17 @@ CS_INT dsp_datetime_len( ctxt, type )
}
#endif
+#if defined(CS_BIGDATETIME_TYPE)
+ if (type == CS_BIGDATETIME_TYPE && sg_bigdatetime_len != -1)
+ {
+ return sg_bigdatetime_len;
+ }
+#endif
+
#if defined(CS_BIGTIME_TYPE)
- if (type == CS_BIGTIME_TYPE && sg_time_len != -1)
+ if (type == CS_BIGTIME_TYPE && sg_bigtime_len != -1)
{
- return sg_time_len;
+ return sg_bigtime_len;
}
#endif
@@ -313,19 +354,10 @@ CS_INT dsp_datetime_len( ctxt, type )
if ((type == CS_DATETIME_TYPE && *sg_datetime_fmt == '\0')
|| (type == CS_DATETIME4_TYPE && *sg_datetime_fmt == '\0')
-#if defined(CS_BIGDATETIME_TYPE)
- || (type == CS_BIGDATETIME_TYPE && *sg_datetime_fmt == '\0')
-#endif
#if defined(CS_DATE_TYPE)
|| (type == CS_DATE_TYPE && *sg_date_fmt == '\0')
#endif
-#if defined(CS_TIME_TYPE)
- || (type == CS_TIME_TYPE && *sg_time_fmt == '\0')
-#endif
-#if defined(CS_BIGTIME_TYPE)
- || (type == CS_BIGTIME_TYPE && *sg_time_fmt == '\0')
-#endif
- )
+ )
{
dt_fmt.datatype = type;
dt_fmt.maxlength = sizeof(CS_DATETIME);
@@ -346,34 +378,50 @@ CS_INT dsp_datetime_len( ctxt, type )
/*-- Build a made-up day of the month --*/
switch (type)
- {
+ {
+ case CS_DATETIME_TYPE:
+ sprintf( dt_buf, "%d/12/1997 11:59:53.123PM", i );
+ break;
+ case CS_DATETIME4_TYPE:
+ sprintf( dt_buf, "%d/12/1997 11:59PM", i );
+ break;
#if defined(CS_DATE_TYPE)
- case CS_DATE_TYPE:
- sprintf( dt_buf, "%d/12/1997", i );
- break;
-#endif
-#if defined(CS_TIME_TYPE)
- case CS_TIME_TYPE:
- sprintf( dt_buf, "11:59:53:123PM" );
- break;
+ case CS_DATE_TYPE:
+ sprintf( dt_buf, "%d/12/1997", i );
+ break;
#endif
default:
- sprintf( dt_buf, "%d/12/1997 11:59:53:123PM", i );
- break;
- }
+ sprintf( dt_buf, "%d/12/1997 11:59:53PM", i );
+ break;
+ }
len = dsp_type_len( ctxt, (CS_CHAR*)dt_buf, &dt_fmt, &dt );
/*-- Keep track of the longest date encountered --*/
max_len = max(len, max_len);
}
}
+#if defined(CS_TIME_TYPE)
+ else if (type == CS_TIME_TYPE && *sg_time_fmt == '\0')
+ {
+ dt_fmt.datatype = type;
+ dt_fmt.maxlength = sizeof(CS_DATETIME);
+ dt_fmt.locale = NULL;
+ dt_fmt.format = CS_FMT_UNUSED;
+ dt_fmt.scale = 0;
+ dt_fmt.precision = 0;
+ sprintf( dt_buf, "11:59:53.123PM" );
+ max_len = dsp_type_len( ctxt, (CS_CHAR*)dt_buf, &dt_fmt, &dt );
+ }
+#endif
else
{
/*
* If the user has supplied a display format to be used in
* place of the CT-Lib format, then we have a lot of work
- * to do; beginning wth building a reasonable UNIX time
+ * to do; beginning with building a reasonable UNIX time
* structure.
+ * sqsh-2.3 : Note that CS_BIGDATETIME_TYPE and CS_BIGTIME_TYPE
+ * will use a default format here, if one is not supplied.
*/
tm.tm_sec = 59;
tm.tm_min = 59;
@@ -386,30 +434,37 @@ CS_INT dsp_datetime_len( ctxt, type )
/*
* Strip down the format string as defined by the CS_DATETIME
- * datatype, and replace the ms (%u) with the longest possible
+ * datatype, and replace the ms (%q) with the longest possible
* number.
*/
- switch (type)
- {
+ switch (type)
+ {
#if defined(CS_DATE_TYPE)
- case CS_DATE_TYPE:
+ case CS_DATE_TYPE:
fmt = dsp_datetime_strip( type, sg_date_fmt, 999 );
break;
#endif
#if defined(CS_TIME_TYPE)
- case CS_TIME_TYPE:
+ case CS_TIME_TYPE:
fmt = dsp_datetime_strip( type, sg_time_fmt, 999 );
break;
#endif
+#if defined(CS_BIGDATETIME_TYPE)
+ case CS_BIGDATETIME_TYPE:
+ conv_fmt = sg_datetime_fmt[0] == '\0' ? sg_datetime_def : sg_datetime_fmt;
+ fmt = dsp_datetime_strip( type, conv_fmt, 999999 );
+ break;
+#endif
#if defined(CS_BIGTIME_TYPE)
- case CS_BIGTIME_TYPE:
- fmt = dsp_datetime_strip( type, sg_time_fmt, 999 );
+ case CS_BIGTIME_TYPE:
+ conv_fmt = sg_time_fmt[0] == '\0' ? sg_time_def : sg_time_fmt;
+ fmt = dsp_datetime_strip( type, conv_fmt, 999999 );
break;
#endif
- default:
+ default:
fmt = dsp_datetime_strip( type, sg_datetime_fmt, 999 );
break;
- }
+ }
max_len = 0;
max_month = 0;
@@ -460,41 +515,42 @@ CS_INT dsp_datetime_len( ctxt, type )
}
}
- DBG(sqsh_debug(DEBUG_DISPLAY,
- "dsp_datetime_len: %s = %d chars\n",
+ DBG(sqsh_debug(DEBUG_DISPLAY,
+ "dsp_datetime_len: %s (type %d) = %d chars\n",
(type == CS_DATETIME_TYPE)?"CS_DATETIME":"Other DATE/TIME type",
- max_len);)
-
- switch(type) {
- case CS_DATETIME_TYPE:
- sg_datetime_len = max_len;
- break;
- case CS_DATETIME4_TYPE:
- sg_datetime4_len = max_len;
- break;
-#if defined(CS_BIGDATETIME_TYPE)
- case CS_BIGDATETIME_TYPE:
- sg_datetime_len = max_len;
- break;
-#endif
+ type, max_len);)
+
+ switch (type) {
+ case CS_DATETIME_TYPE:
+ sg_datetime_len = max_len;
+ break;
+
+ case CS_DATETIME4_TYPE:
+ sg_datetime4_len = max_len;
+ break;
#if defined(CS_DATE_TYPE)
- case CS_DATE_TYPE:
- sg_date_len = max_len;
- break;
+ case CS_DATE_TYPE:
+ sg_date_len = max_len;
+ break;
#endif
#if defined(CS_TIME_TYPE)
- case CS_TIME_TYPE:
- sg_time_len = max_len;
- break;
+ case CS_TIME_TYPE:
+ sg_time_len = max_len;
+ break;
+#endif
+#if defined(CS_BIGDATETIME_TYPE)
+ case CS_BIGDATETIME_TYPE:
+ sg_bigdatetime_len = max_len;
+ break;
#endif
#if defined(CS_BIGTIME_TYPE)
- case CS_BIGTIME_TYPE:
- sg_time_len = max_len;
- break;
+ case CS_BIGTIME_TYPE:
+ sg_bigtime_len = max_len;
+ break;
#endif
- }
+ }
-/* fprintf(stderr, "type = %d, len = %d\n", type, max_len); */
+/* fprintf(stderr, "type = %d, len = %d\n", type, max_len); */
return (CS_INT)max_len;
}
@@ -536,9 +592,14 @@ CS_RETCODE dsp_datetime_conv( ctx, dt_fmt, dt, buf, len, type )
conv_fmt = sg_time_fmt;
break;
#endif
+#if defined(CS_BIGDATETIME_TYPE)
+ case CS_BIGDATETIME_TYPE:
+ conv_fmt = sg_datetime_fmt[0] == '\0' ? sg_datetime_def : sg_datetime_fmt;
+ break;
+#endif
#if defined(CS_BIGTIME_TYPE)
case CS_BIGTIME_TYPE:
- conv_fmt = sg_time_fmt;
+ conv_fmt = sg_time_fmt[0] == '\0' ? sg_time_def : sg_time_fmt;
break;
#endif
default:
@@ -566,8 +627,7 @@ CS_RETCODE dsp_datetime_conv( ctx, dt_fmt, dt, buf, len, type )
(CS_VOID*)buf, /* String */
(CS_INT*)NULL ) != CS_SUCCEED)
{
- fprintf( stderr,
- "dsp_datetime_conv: cs_convert(DATETIME->CHAR) failed\n" );
+ fprintf( stderr, "dsp_datetime_conv: cs_convert(DATETIME->CHAR) failed\n" );
return CS_FAIL;
}
@@ -600,8 +660,12 @@ CS_RETCODE dsp_datetime_conv( ctx, dt_fmt, dt, buf, len, type )
* type of date that we are processing and replace the ms
* field if it exists.
*/
- fmt = dsp_datetime_strip( dt_fmt->datatype, conv_fmt,
- (int)dr.datemsecond );
+#if defined(CS_BIGDATETIME_TYPE) && defined(CS_BIGTIME_TYPE)
+ if (dt_fmt->datatype == CS_BIGDATETIME_TYPE || dt_fmt->datatype == CS_BIGTIME_TYPE)
+ fmt = dsp_datetime_strip( dt_fmt->datatype, conv_fmt, (int) dr.datesecfrac );
+ else
+#endif
+ fmt = dsp_datetime_strip( dt_fmt->datatype, conv_fmt, (int) dr.datemsecond );
/*
* According to the strftime(3C) documentation, there is no real
@@ -647,12 +711,12 @@ CS_INT dsp_money_len( ctxt )
*/
len = dsp_type_len( ctxt, (CS_CHAR*)"-922337203685477.5808",
&mon_fmt, (CS_VOID*)&mon );
-
+
if (len < 19)
{
len = 19;
}
-
+
DBG(sqsh_debug(DEBUG_DISPLAY, "dsp_money_len: CS_MONEY = %d chars\n",
len);)
@@ -771,7 +835,7 @@ static char* dsp_datetime_strip( type, fmt, ms )
/*
* Now, we want to keep date format that the caller specified,
- * but we want to strip out the milisecond (%u) and the
+ * but we want to strip out the millisecond (%q) and the
* delimeter for small and regular datetimes ([]).
*/
for (cp = new_fmt; *fmt != '\0'; ++fmt)
@@ -779,11 +843,21 @@ static char* dsp_datetime_strip( type, fmt, ms )
switch (*fmt)
{
case '%':
- if (*(fmt + 1) == 'u')
+ if (*(fmt + 1) == 'q')
{
fmt += 1;
- sprintf( cp, "%03d", ms );
- cp += 3;
+#if defined(CS_BIGDATETIME_TYPE) && defined(CS_BIGTIME_TYPE)
+ if (type == CS_BIGDATETIME_TYPE || type == CS_BIGTIME_TYPE)
+ {
+ sprintf( cp, "%06d", ms );
+ cp += 6;
+ }
+ else
+#endif
+ {
+ sprintf( cp, "%03d", ms );
+ cp += 3;
+ }
}
else
{
@@ -804,7 +878,7 @@ static char* dsp_datetime_strip( type, fmt, ms )
case ']':
break;
-
+
default:
*cp++ = *fmt;
}
diff --git a/src/dsp_desc.c b/src/dsp_desc.c
index dc29165..7cec4e9 100644
--- a/src/dsp_desc.c
+++ b/src/dsp_desc.c
@@ -32,13 +32,14 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: dsp_desc.c,v 1.10 2013/04/04 10:52:35 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: dsp_desc.c,v 1.11 2013/07/20 16:18:35 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
/*-- Local Prototypes --*/
static CS_INT dsp_dlen _ANSI_ARGS(( CS_DATAFMT* ));
static CS_INT dsp_just _ANSI_ARGS(( CS_INT ));
+static void dsp_display_fmt _ANSI_ARGS(( CS_CHAR*, CS_DATAFMT* ));
/*
* This is almost entirely cheesy. Since CT-Lib does a crappy job
@@ -49,23 +50,48 @@ static CS_INT dsp_just _ANSI_ARGS(( CS_INT ));
* do the dirty work.
* sqsh-2.1.8: Add CS_BINARY_TYPE and CS_IMAGE_TYPE to the list.
* Fix bugreport 3079678.
+ * sqsh-2.3 : Added missing data types to the list (CS_UNITEXT_TYPE,
+ * CS_BIGINT_TYPE,CS_USMALLINT_TYPE,CS_UINT_TYPE,CS_UBIGINT_TYPE)
*/
-#define LET_CTLIB_CONV(t) \
- (((t) == CS_CHAR_TYPE) || \
- ((t) == CS_TEXT_TYPE) || \
- ((t) == CS_TINYINT_TYPE) || \
- ((t) == CS_SMALLINT_TYPE) || \
- ((t) == CS_INT_TYPE) || \
- ((t) == CS_BIT_TYPE) || \
- ((t) == CS_NUMERIC_TYPE) || \
- ((t) == CS_DECIMAL_TYPE) || \
- ((t) == CS_VARCHAR_TYPE) || \
- ((t) == CS_LONGCHAR_TYPE) || \
- ((t) == CS_LONGBINARY_TYPE)|| \
- ((t) == CS_VARBINARY_TYPE) || \
- ((t) == CS_BINARY_TYPE) || \
- ((t) == CS_IMAGE_TYPE) || \
- ((t) == CS_UNICHAR_TYPE))
+#if defined(CS_UNITEXT_TYPE) && defined(CS_BIGINT_TYPE) && defined(CS_USMALLINT_TYPE) && defined(CS_UINT_TYPE) && defined(CS_UBIGINT_TYPE)
+#define LET_CTLIB_CONV(t) ( \
+ ((t) == CS_CHAR_TYPE) \
+ || ((t) == CS_BINARY_TYPE) \
+ || ((t) == CS_LONGCHAR_TYPE) \
+ || ((t) == CS_LONGBINARY_TYPE) \
+ || ((t) == CS_TEXT_TYPE) \
+ || ((t) == CS_IMAGE_TYPE) \
+ || ((t) == CS_TINYINT_TYPE) \
+ || ((t) == CS_SMALLINT_TYPE) \
+ || ((t) == CS_INT_TYPE) \
+ || ((t) == CS_BIT_TYPE) \
+ || ((t) == CS_VARCHAR_TYPE) \
+ || ((t) == CS_VARBINARY_TYPE) \
+ || ((t) == CS_UNICHAR_TYPE) \
+ || ((t) == CS_UNITEXT_TYPE) \
+ || ((t) == CS_BIGINT_TYPE) \
+ || ((t) == CS_USMALLINT_TYPE) \
+ || ((t) == CS_UINT_TYPE) \
+ || ((t) == CS_UBIGINT_TYPE) \
+ )
+#else
+#define LET_CTLIB_CONV(t) ( \
+ ((t) == CS_CHAR_TYPE) \
+ || ((t) == CS_BINARY_TYPE) \
+ || ((t) == CS_LONGCHAR_TYPE) \
+ || ((t) == CS_LONGBINARY_TYPE) \
+ || ((t) == CS_TEXT_TYPE) \
+ || ((t) == CS_IMAGE_TYPE) \
+ || ((t) == CS_TINYINT_TYPE) \
+ || ((t) == CS_SMALLINT_TYPE) \
+ || ((t) == CS_INT_TYPE) \
+ || ((t) == CS_BIT_TYPE) \
+ || ((t) == CS_VARCHAR_TYPE) \
+ || ((t) == CS_VARBINARY_TYPE) \
+ || ((t) == CS_UNICHAR_TYPE) \
+ )
+#endif
+
/*
* dsp_desc_bind():
@@ -92,15 +118,14 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
CS_UNUSED, /* Buffer Length */
(CS_INT*)NULL) != CS_SUCCEED)
{
- fprintf( stderr,
- "dsp_desc_bind: Unable to retrieve column count (CS_NUMDATA)\n" );
+ fprintf( stderr, "dsp_desc_bind: Unable to retrieve column count (CS_NUMDATA)\n" );
return NULL;
}
d = (dsp_desc_t*)malloc( sizeof( dsp_desc_t ) );
c = (dsp_col_t*)malloc( sizeof( dsp_col_t ) * ncols );
- if (d == NULL || c == NULL)
+ if (d == NULL || c == NULL)
{
fprintf( stderr, "dsp_desc_bind: Memory allocation failure.\n" );
if (d != NULL)
@@ -116,7 +141,7 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
d->d_bylist_size = 0;
d->d_bylist = NULL;
- for (i = 0; i < ncols; i++)
+ for (i = 0; i < ncols; i++)
{
d->d_cols[i].c_data = NULL;
@@ -133,7 +158,7 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
d->d_cols[i].c_format.usertype = 0;
d->d_cols[i].c_format.locale = NULL;
}
-
+
if (result_type == CS_COMPUTE_RESULT)
{
if (ct_compute_info( cmd, /* Command */
@@ -144,22 +169,19 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
(CS_INT*)NULL ) != CS_SUCCEED)
{
dsp_desc_destroy( d );
- fprintf( stderr,
- "dsp_desc_bind: Unable to fetch by-list len of compute results\n" );
+ fprintf( stderr, "dsp_desc_bind: Unable to fetch by-list len of compute results\n" );
return NULL;
}
if (d->d_bylist_size > 0)
{
- d->d_bylist = (CS_SMALLINT*)malloc( sizeof(CS_SMALLINT) *
- d->d_bylist_size );
-
+ d->d_bylist = (CS_SMALLINT*)malloc( sizeof(CS_SMALLINT) *d->d_bylist_size );
+
if (d->d_bylist == NULL)
{
dsp_desc_destroy( d );
- fprintf( stderr,
- "dsp_desc_bind: Memory failure for by-list size array\n" );
+ fprintf( stderr, "dsp_desc_bind: Memory failure for by-list size array\n" );
return NULL;
}
@@ -171,26 +193,24 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
(CS_INT*)NULL) != CS_SUCCEED)
{
dsp_desc_destroy( d );
- fprintf( stderr,
- "dsp_desc_bind: Memory allocation failure for by-list array\n" );
+ fprintf( stderr, "dsp_desc_bind: Memory allocation failure for by-list array\n" );
return NULL;
}
}
}
-
+
/*
* Blast through the set of columns, binding the output to a
* friendly chunk of memory.
*/
- for (i = 0; i < ncols; i++)
+ for (i = 0; i < ncols; i++)
{
/*-- Get description for column --*/
- if (ct_describe( cmd, i+1, &d->d_cols[i].c_format ) != CS_SUCCEED)
+ if (ct_describe( cmd, i+1, &d->d_cols[i].c_format ) != CS_SUCCEED)
{
dsp_desc_destroy( d );
- fprintf( stderr,
- "dsp_desc_bind: Unable to fetch description of column #%d\n",
+ fprintf( stderr, "dsp_desc_bind: Unable to fetch description of column #%d\n",
(int)i+1 );
return NULL;
}
@@ -203,9 +223,9 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
d->d_cols[i].c_data = NULL;
#if 0
- /* This code has been commented out as it generates the dreaded
- "bind resulted in truncation" error. */
- if (g_dsp_props.p_maxlen > 0 &&
+ /* This code has been commented out as it generates the dreaded
+ "bind resulted in truncation" error. */
+ if (g_dsp_props.p_maxlen > 0 &&
d->d_cols[i].c_maxlength > g_dsp_props.p_maxlen)
{
d->d_cols[i].c_maxlength = g_dsp_props.p_maxlen;
@@ -222,9 +242,9 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
* request), I am forcing these data types to malloc a tad
* more memory then they may need.
*/
- /* The amount of memory alloced used to be 64 bytes. Pushed
- to 256 following discovery of buffer overflow problems by
- Mike Tibbetts */
+ /* The amount of memory alloced used to be 64 bytes. Pushed
+ to 256 following discovery of buffer overflow problems by
+ Mike Tibbetts */
if (d->d_cols[i].c_format.datatype == CS_FLOAT_TYPE ||
d->d_cols[i].c_format.datatype == CS_REAL_TYPE)
{
@@ -284,12 +304,12 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
" buf = %p,\n"
" bytes= NULL,\n"
" ind = %p)\n",
- (void*)cmd,
- i + 1,
- (int)str_fmt.maxlength,
+ (void*)cmd,
+ i + 1,
+ (int)str_fmt.maxlength,
(void*)d->d_cols[i].c_data,
(void*)&d->d_cols[i].c_nullind);)
-
+
/*
* Now, bind the incoming row to the native data type. That
@@ -319,9 +339,8 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
* data prior to doing the conversion.
*/
d->d_cols[i].c_is_native = CS_TRUE;
- d->d_cols[i].c_native =
- (CS_VOID*)malloc(d->d_cols[i].c_format.maxlength);
-
+ d->d_cols[i].c_native = (CS_VOID*)malloc(d->d_cols[i].c_format.maxlength);
+
if (d->d_cols[i].c_native == NULL)
{
fprintf( stderr,
@@ -351,8 +370,8 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
" buf = %p,\n"
" bytes= %p,\n"
" ind = %p)\n",
- (void*)cmd,
- i + 1,
+ (void*)cmd,
+ i + 1,
(int)d->d_cols[i].c_format.datatype,
(int)d->d_cols[i].c_format.format,
(int)d->d_cols[i].c_format.maxlength,
@@ -425,6 +444,7 @@ dsp_desc_t* dsp_desc_bind( cmd, result_type )
return d;
}
+
CS_INT dsp_desc_fetch( cmd, d )
CS_COMMAND *cmd;
dsp_desc_t *d;
@@ -435,6 +455,9 @@ CS_INT dsp_desc_fetch( cmd, d )
CS_INT j;
CS_INT p;
CS_DATAFMT str_fmt;
+#if defined(HAVE_LOCALE_H)
+ CS_CHAR *radix;
+#endif
if ((r = ct_fetch( cmd, /* Command */
CS_UNUSED, /* Type */
@@ -445,11 +468,11 @@ CS_INT dsp_desc_fetch( cmd, d )
return CS_END_DATA;
}
- /* mpeppler - 4/9/2004
- allow CS_ROW_FAIL results to go through and not abort the entire
- query. CS_ROW_FAIL usually means a conversion or truncation error
- which shouldn't be fatal to the entire query, although a warning
- should be printed. */
+ /* mpeppler - 4/9/2004
+ allow CS_ROW_FAIL results to go through and not abort the entire
+ query. CS_ROW_FAIL usually means a conversion or truncation error
+ which shouldn't be fatal to the entire query, although a warning
+ should be printed. */
if (r != CS_SUCCEED && r != CS_ROW_FAIL)
{
return r;
@@ -487,7 +510,7 @@ CS_INT dsp_desc_fetch( cmd, d )
* nothing left to be done.
* sqsh-2.1.8: Except when the source datatype was binary, then
* we have to prepend the result string with characters '0x'.
- * 20110107: Prepend 0x0 in case of odd number of chars in string.
+ * 20110107: Prepend 0x0 in case of odd number of chars in string.
*/
if (d->d_cols[i].c_is_native == CS_FALSE)
{
@@ -496,8 +519,10 @@ CS_INT dsp_desc_fetch( cmd, d )
d->d_cols[i].c_format.datatype == CS_VARBINARY_TYPE ||
d->d_cols[i].c_format.datatype == CS_IMAGE_TYPE)
{
- for (p = strlen (d->d_cols[i].c_data), j = p%2==0?2:3; p >= 0;
- d->d_cols[i].c_data[p+j] = d->d_cols[i].c_data[p]) p--;
+ p = strlen (d->d_cols[i].c_data);
+ j = (p % 2 == 0 ? 2 : 3);
+ for (; p >= 0; p--)
+ d->d_cols[i].c_data[p+j] = d->d_cols[i].c_data[p];
d->d_cols[i].c_data[0] = '0';
d->d_cols[i].c_data[1] = 'x';
if (j==3) d->d_cols[i].c_data[2] = '0';
@@ -511,17 +536,101 @@ CS_INT dsp_desc_fetch( cmd, d )
* character data here.
*/
str_fmt.maxlength = d->d_cols[i].c_maxlength + 1;
+ str_fmt.precision = d->d_cols[i].c_format.precision;
+ str_fmt.scale = d->d_cols[i].c_format.scale;
+
switch (d->d_cols[i].c_format.datatype)
{
+ case CS_BINARY_TYPE:
+ case CS_LONGBINARY_TYPE:
+ case CS_VARBINARY_TYPE:
+ case CS_IMAGE_TYPE:
+ /*
+ * This case will only be executed if one or more of the datatypes are removed from
+ * the LET_CTLIB_CONV macro.
+ */
+ strcpy( d->d_cols[i].c_data, "0x" );
+ d->d_cols[i].c_format.maxlength = d->d_cols[i].c_native_len;
+
+ if (cs_convert( g_context, /* Context */
+ &d->d_cols[i].c_format, /* Source Format */
+ d->d_cols[i].c_native, /* Source Data */
+ &str_fmt, /* Dest Format */
+ (CS_VOID*)(d->d_cols[i].c_data+2),/* Dest Data */
+ (CS_INT*)NULL ) == CS_FAIL)
+ {
+ fprintf( stderr, "dsp_desc_fetch: cs_convert(BIN->CHAR) column %d failed\n", (int) i+1 );
+ dsp_display_fmt( "src_fmt", &d->d_cols[i].c_format );
+ dsp_display_fmt( "dst_fmt", &str_fmt );
+ return CS_FAIL;
+ }
+ break;
+
+ case CS_NUMERIC_TYPE:
+ case CS_DECIMAL_TYPE:
+ if (cs_convert( g_context, /* Context */
+ &d->d_cols[i].c_format, /* Source Format */
+ d->d_cols[i].c_native, /* Source Data */
+ &str_fmt, /* Dest Format */
+ (CS_VOID*)(d->d_cols[i].c_data),/* Dest Data */
+ (CS_INT*)NULL ) == CS_FAIL)
+ {
+ fprintf( stderr, "dsp_desc_fetch: cs_convert(NUMERIC->CHAR) column %d failed\n", (int) i+1 );
+ dsp_display_fmt( "src_fmt", &d->d_cols[i].c_format );
+ dsp_display_fmt( "dst_fmt", &str_fmt );
+ return CS_FAIL;
+ }
+
+#if defined(HAVE_LOCALE_H)
+ /*
+ * sqsh-2.3: Convert the decimal separator in numeric/decimal datatypes
+ * to the character according to the locale definition of the client.
+ * By courtesy of Niki Hansche.
+ */
+ if (g_lconv != NULL && (radix = (CS_CHAR *) strrchr((CS_CHAR*) (d->d_cols[i].c_data), '.')) != NULL)
+ {
+ *radix = (CS_CHAR) *g_lconv->decimal_point;
+ }
+#endif
+ break;
+
+ case CS_MONEY_TYPE:
+ case CS_MONEY4_TYPE:
+ if (cs_convert( g_context, /* Context */
+ &d->d_cols[i].c_format, /* Source Format */
+ d->d_cols[i].c_native, /* Source Data */
+ &str_fmt, /* Dest Format */
+ (CS_VOID*)(d->d_cols[i].c_data),/* Dest Data */
+ (CS_INT*)NULL ) == CS_FAIL)
+ {
+ fprintf( stderr, "dsp_desc_fetch: cs_convert(MONEY->CHAR) column %d failed\n", (int) i+1 );
+ dsp_display_fmt( "src_fmt", &d->d_cols[i].c_format );
+ dsp_display_fmt( "dst_fmt", &str_fmt );
+ return CS_FAIL;
+ }
+
+#if defined(HAVE_LOCALE_H)
+ /*
+ * sqsh-2.3: Convert the decimal separator in money datatypes
+ * to the character according to the locale definition of the client.
+ * By courtesy of Niki Hansche.
+ */
+ if (g_lconv != NULL && (radix = (CS_CHAR *) strrchr((CS_CHAR*) (d->d_cols[i].c_data), '.')) != NULL)
+ {
+ *radix = (CS_CHAR) *g_lconv->mon_decimal_point;
+ }
+#endif
+ break;
+
case CS_REAL_TYPE:
- sprintf( (char*)d->d_cols[i].c_data, "%*.*f",
+ sprintf( (char*)d->d_cols[i].c_data, "%*.*f",
g_dsp_props.p_real_prec + 2,
g_dsp_props.p_real_scale,
(double)(*((CS_REAL*)d->d_cols[i].c_native)) );
break;
case CS_FLOAT_TYPE:
- sprintf( (char*)d->d_cols[i].c_data, "%*.*f",
+ sprintf( (char*)d->d_cols[i].c_data, "%*.*f",
g_dsp_props.p_flt_prec + 2,
g_dsp_props.p_flt_scale,
(double)(*((CS_FLOAT*)d->d_cols[i].c_native)) );
@@ -533,23 +642,23 @@ CS_INT dsp_desc_fetch( cmd, d )
case CS_DATETIME_TYPE:
case CS_DATETIME4_TYPE:
#if defined(CS_DATE_TYPE)
- case CS_DATE_TYPE:
+ case CS_DATE_TYPE:
#endif
#if defined(CS_TIME_TYPE)
- case CS_TIME_TYPE:
-#endif
-#if defined(CS_BIGTIME_TYPE)
- case CS_BIGTIME_TYPE:
+ case CS_TIME_TYPE:
#endif
#if defined(CS_BIGDATETIME_TYPE)
- case CS_BIGDATETIME_TYPE:
+ case CS_BIGDATETIME_TYPE:
+#endif
+#if defined(CS_BIGTIME_TYPE)
+ case CS_BIGTIME_TYPE:
#endif
if (dsp_datetime_conv( g_context, /* Context */
&d->d_cols[i].c_format, /* Data format */
d->d_cols[i].c_native, /* Data */
d->d_cols[i].c_data, /* Destination */
d->d_cols[i].c_maxlength+1,
- d->d_cols[i].c_format.datatype ) != CS_SUCCEED)
+ d->d_cols[i].c_format.datatype ) != CS_SUCCEED)
{
return CS_FAIL;
}
@@ -565,9 +674,8 @@ CS_INT dsp_desc_fetch( cmd, d )
(CS_VOID*)d->d_cols[i].c_data, /* Dest Data */
(CS_INT*)NULL ) != CS_SUCCEED)
{
- fprintf( stderr,
- "dsp_desc_fetch: cs_convert(%d->CHAR) column %d failed\n",
- (int)d->d_cols[i].c_format.datatype, (int)i+1 );
+ fprintf( stderr, "dsp_desc_fetch: cs_convert(%d->CHAR) column %d failed\n",
+ (int) d->d_cols[i].c_format.datatype, (int) i+1 );
return CS_FAIL;
}
break;
@@ -588,11 +696,11 @@ void dsp_desc_destroy( d )
{
CS_INT i;
- if (d != NULL)
+ if (d != NULL)
{
- if (d->d_cols != NULL)
+ if (d->d_cols != NULL)
{
- for (i = 0; i < d->d_ncols; i++)
+ for (i = 0; i < d->d_ncols; i++)
{
if (d->d_cols[i].c_native != NULL)
{
@@ -615,6 +723,33 @@ void dsp_desc_destroy( d )
}
}
+
+static void dsp_display_fmt( nm, f )
+ CS_CHAR *nm;
+ CS_DATAFMT *f;
+{
+ if (f->namelen > 0 && f->namelen < CS_MAX_NAME)
+ {
+ fprintf( stderr, "%s->name = %*.*s\n",
+ (char*) nm, (int) f->namelen, (int) f->namelen, (char*) f->name );
+ }
+ else
+ {
+ fprintf( stderr, "%s->name = <empty>\n", (char*)nm );
+ }
+ fprintf( stderr, "%s->namelen = %d\n", (char*) nm, (int) f->namelen );
+ fprintf( stderr, "%s->datatype = %d\n", (char*) nm, (int) f->datatype );
+ fprintf( stderr, "%s->format = %d\n", (char*) nm, (int) f->format );
+ fprintf( stderr, "%s->maxlength = %d\n", (char*) nm, (int) f->maxlength);
+ fprintf( stderr, "%s->scale = %d\n", (char*) nm, (int) f->scale );
+ fprintf( stderr, "%s->precision = %d\n", (char*) nm, (int) f->precision);
+ fprintf( stderr, "%s->status = %d\n", (char*) nm, (int) f->status );
+ fprintf( stderr, "%s->count = %d\n", (char*) nm, (int) f->count );
+ fprintf( stderr, "%s->usertype = %d\n", (char*) nm, (int) f->usertype );
+ fprintf( stderr, "%s->locale = %p\n", (char*) nm, (void*) f->locale );
+}
+
+
/*
* dsp_just():
*
@@ -623,20 +758,44 @@ void dsp_desc_destroy( d )
static CS_INT dsp_just( type )
CS_INT type;
{
- switch (type)
+ switch (type)
{
- case CS_BIT_TYPE:
case CS_TINYINT_TYPE:
case CS_SMALLINT_TYPE:
case CS_INT_TYPE:
case CS_REAL_TYPE:
case CS_FLOAT_TYPE:
+ case CS_BIT_TYPE:
+ case CS_DATETIME_TYPE:
+ case CS_DATETIME4_TYPE:
case CS_MONEY_TYPE:
case CS_MONEY4_TYPE:
case CS_NUMERIC_TYPE:
case CS_DECIMAL_TYPE:
- case CS_DATETIME_TYPE:
- case CS_DATETIME4_TYPE:
+#if defined(CS_DATE_TYPE)
+ case CS_DATE_TYPE:
+#endif
+#if defined(CS_TIME_TYPE)
+ case CS_TIME_TYPE:
+#endif
+#if defined(CS_BIGINT_TYPE)
+ case CS_BIGINT_TYPE:
+#endif
+#if defined(CS_USMALLINT_TYPE)
+ case CS_USMALLINT_TYPE:
+#endif
+#if defined(CS_UINT_TYPE)
+ case CS_UINT_TYPE:
+#endif
+#if defined(CS_UBIGINT_TYPE)
+ case CS_UBIGINT_TYPE:
+#endif
+#if defined(CS_BIGDATETIME_TYPE)
+ case CS_BIGDATETIME_TYPE:
+#endif
+#if defined(CS_BIGTIME_TYPE)
+ case CS_BIGTIME_TYPE:
+#endif
return DSP_JUST_RIGHT;
default:
break;
@@ -655,21 +814,27 @@ static CS_INT dsp_just( type )
static CS_INT dsp_dlen( fmt )
CS_DATAFMT *fmt;
{
- switch (fmt->datatype)
+ switch (fmt->datatype)
{
case CS_CHAR_TYPE:
case CS_LONGCHAR_TYPE:
case CS_TEXT_TYPE:
case CS_VARCHAR_TYPE:
+ case CS_UNICHAR_TYPE:
+#if defined(CS_UNITEXT_TYPE)
+ case CS_UNITEXT_TYPE:
+#endif
+#if defined(CS_XML_TYPE)
+ case CS_XML_TYPE:
+#endif
return fmt->maxlength;
- case CS_IMAGE_TYPE:
+
case CS_BINARY_TYPE:
case CS_LONGBINARY_TYPE:
+ case CS_IMAGE_TYPE:
case CS_VARBINARY_TYPE:
- case CS_UNICHAR_TYPE:
return (2 * fmt->maxlength) + 2; /* sqsh-2.1.8 fix */
- case CS_BIT_TYPE:
- return 1;
+
case CS_TINYINT_TYPE:
return 3;
case CS_SMALLINT_TYPE:
@@ -682,22 +847,49 @@ static CS_INT dsp_dlen( fmt )
case CS_FLOAT_TYPE:
/*-- Sign + Decimal + Precision --*/
return 2 + g_dsp_props.p_flt_prec;
+ case CS_BIT_TYPE:
+ return 1;
+
case CS_MONEY4_TYPE:
return dsp_money4_len( g_context );
case CS_MONEY_TYPE:
return dsp_money_len( g_context );
+ case CS_NUMERIC_TYPE:
+ case CS_DECIMAL_TYPE:
+ return (fmt->precision + 3);
+
case CS_DATETIME_TYPE:
case CS_DATETIME4_TYPE:
#if defined(CS_DATE_TYPE)
- case CS_DATE_TYPE:
+ case CS_DATE_TYPE:
#endif
#if defined(CS_TIME_TYPE)
- case CS_TIME_TYPE:
+ case CS_TIME_TYPE:
+#endif
+#if defined(CS_BIGDATETIME_TYPE)
+ case CS_BIGDATETIME_TYPE:
+#endif
+#if defined(CS_BIGTIME_TYPE)
+ case CS_BIGTIME_TYPE:
#endif
return dsp_datetime_len( g_context, fmt->datatype);
- case CS_NUMERIC_TYPE:
- case CS_DECIMAL_TYPE:
- return (fmt->precision + 3);
+
+#if defined(CS_BIGINT_TYPE)
+ case CS_BIGINT_TYPE:
+ return 20;
+#endif
+#if defined(CS_USMALLINT_TYPE)
+ case CS_USMALLINT_TYPE:
+ return 5;
+#endif
+#if defined(CS_UINT_TYPE)
+ case CS_UINT_TYPE:
+ return 10;
+#endif
+#if defined(CS_UBIGINT_TYPE)
+ case CS_UBIGINT_TYPE:
+ return 20;
+#endif
default:
break;
}
diff --git a/src/dsp_html.c b/src/dsp_html.c
index a227869..6513d07 100644
--- a/src/dsp_html.c
+++ b/src/dsp_html.c
@@ -34,7 +34,7 @@ extern int errno;
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: dsp_html.c,v 1.2 2004/04/11 15:14:32 mpeppler Exp $";
+static char RCS_Id[] = "$Id: dsp_html.c,v 1.3 2013/07/20 16:18:35 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -125,7 +125,7 @@ int dsp_html( output, cmd, flags )
case CS_STATUS_RESULT:
if (in_table == CS_TRUE)
{
- dsp_fputs( "</table>\n", output );
+ dsp_fputs( "</tbody>\n</table>\n", output );
in_table = CS_FALSE;
}
@@ -197,7 +197,7 @@ int dsp_html( output, cmd, flags )
if (in_table == CS_TRUE)
{
- dsp_fputs( "</table>\n", output );
+ dsp_fputs( "</tbody>\n</table>\n", output );
}
if (rows_affected != CS_NO_COUNT && !(flags & DSP_F_NOFOOTERS))
@@ -230,7 +230,7 @@ int dsp_html( output, cmd, flags )
if (select_desc == NULL)
goto dsp_fail;
- dsp_fputs( "\n<table border>\n", output );
+ dsp_fputs( "\n<table class=\"sqshtable\" border=\"1\">\n", output );
in_table = CS_TRUE;
/*
@@ -241,7 +241,7 @@ int dsp_html( output, cmd, flags )
if (g_dsp_interrupted)
goto dsp_interrupted;
- dsp_fputs( "<tr>\n", output );
+ dsp_fputs( "<thead>\n<tr>\n", output );
for (i = 0; i < select_desc->d_ncols; i++)
{
col = &select_desc->d_cols[i];
@@ -257,7 +257,7 @@ int dsp_html( output, cmd, flags )
}
dsp_fputs( "</th>\n", output );
}
- dsp_fputs( "</tr>\n", output );
+ dsp_fputs( "</tr>\n</thead>\n", output );
}
if (g_dsp_interrupted)
@@ -272,18 +272,18 @@ int dsp_html( output, cmd, flags )
if (g_dsp_interrupted)
goto dsp_interrupted;
- dsp_fputs( "<tr>\n", output );
+ dsp_fputs( "<tbody>\n<tr>\n", output );
for (i = 0; i < select_desc->d_ncols; i++)
{
col = &select_desc->d_cols[i];
if (col->c_justification == DSP_JUST_RIGHT)
{
- dsp_fputs( " <td align=right>", output );
+ dsp_fputs( " <td style=\"text-align: right;\">", output );
}
else
{
- dsp_fputs( " <td align=left>", output );
+ dsp_fputs( " <td style=\"text-align: left;\">", output );
}
if (col->c_nullind == -1)
@@ -297,7 +297,7 @@ int dsp_html( output, cmd, flags )
dsp_fputs( "</td>\n", output );
}
- dsp_fputs( "</tr>\n", output );
+ dsp_fputs( "</tr>\n</tbody>\n", output );
if (g_dsp_interrupted)
goto dsp_interrupted;
@@ -434,7 +434,7 @@ static CS_INT dsp_comp_prrow_one( output, sel_desc, com_desc )
dsp_col_t *sel_col;
dsp_col_t *com_col;
- dsp_fputs( "<tr>\n", output );
+ dsp_fputs( "<thead>\n<tr>\n", output );
for (i = 0; i < sel_desc->d_ncols; i++)
{
dsp_fputs( " <th>", output );
@@ -462,9 +462,9 @@ static CS_INT dsp_comp_prrow_one( output, sel_desc, com_desc )
dsp_fputs( "</th>", output );
}
- dsp_fputs( "</tr>\n", output );
+ dsp_fputs( "</tr>\n</thead>\n", output );
- dsp_fputs( "<tr>\n", output );
+ dsp_fputs( "<tbody>\n<tr>\n", output );
for (i = 0; i < sel_desc->d_ncols; i++)
{
/*-- Handy Pointer --*/
@@ -472,11 +472,11 @@ static CS_INT dsp_comp_prrow_one( output, sel_desc, com_desc )
if (sel_col->c_justification == DSP_JUST_RIGHT)
{
- dsp_fputs( " <td align=right>", output );
+ dsp_fputs( " <td style=\"text-align: right;\">", output );
}
else
{
- dsp_fputs( " <td align=left>", output );
+ dsp_fputs( " <td style=\"text-align: left;\">", output );
}
/*
@@ -503,7 +503,7 @@ static CS_INT dsp_comp_prrow_one( output, sel_desc, com_desc )
dsp_fputs( "<br>", output );
}
}
- dsp_fputs( "</tr>\n", output );
+ dsp_fputs( "</tr>\n</tbody>\n", output );
return count;
}
diff --git a/src/dsp_meta.c b/src/dsp_meta.c
index 9beb88c..910f141 100644
--- a/src/dsp_meta.c
+++ b/src/dsp_meta.c
@@ -32,7 +32,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: dsp_meta.c,v 1.3 2004/04/11 15:14:32 mpeppler Exp $";
+static char RCS_Id[] = "$Id: dsp_meta.c,v 1.4 2013/07/20 16:18:35 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -370,6 +370,18 @@ static CS_CHAR* dsp_meta_status( s, fmt )
strcat( fmt, "CS_RETURN" );
}
+#if defined(CS_RETURN_CANBENULL)
+ if (s & CS_RETURN_CANBENULL)
+ {
+ if (need_comma)
+ {
+ strcat(fmt, "," );
+ }
+ need_comma = CS_TRUE;
+
+ strcat( fmt, "CS_RETURN_CANBENULL" );
+ }
+#endif
if (s & CS_TIMESTAMP)
{
if (need_comma)
@@ -532,14 +544,6 @@ static CS_CHAR* dsp_meta_datatype( t )
return "CS_DATETIME_TYPE";
case CS_DATETIME4_TYPE:
return "CS_DATETIME4_TYPE";
-#if defined(CS_DATE_TYPE)
- case CS_DATE_TYPE:
- return "CS_DATE_TYPE";
-#endif
-#if defined(CS_TIME_TYPE)
- case CS_TIME_TYPE:
- return "CS_TIME_TYPE";
-#endif
case CS_MONEY_TYPE:
return "CS_MONEY_TYPE";
case CS_MONEY4_TYPE:
@@ -562,6 +566,54 @@ static CS_CHAR* dsp_meta_datatype( t )
return "CS_VOID_TYPE";
case CS_USHORT_TYPE:
return "CS_USHORT_TYPE";
+#if defined(CS_UNICHAR_TYPE)
+ case CS_UNICHAR_TYPE:
+ return "CS_UNICHAR_TYPE";
+#endif
+#if defined(CS_BLOB_TYPE)
+ case CS_BLOB_TYPE:
+ return "CS_BLOB_TYPE";
+#endif
+#if defined(CS_DATE_TYPE)
+ case CS_DATE_TYPE:
+ return "CS_DATE_TYPE";
+#endif
+#if defined(CS_TIME_TYPE)
+ case CS_TIME_TYPE:
+ return "CS_TIME_TYPE";
+#endif
+#if defined(CS_UNITEXT_TYPE)
+ case CS_UNITEXT_TYPE:
+ return "CS_UNITEXT_TYPE";
+#endif
+#if defined(CS_BIGINT_TYPE)
+ case CS_BIGINT_TYPE:
+ return "CS_BIGINT_TYPE";
+#endif
+#if defined(CS_USMALLINT_TYPE)
+ case CS_USMALLINT_TYPE:
+ return "CS_USMALLINT_TYPE";
+#endif
+#if defined(CS_UINT_TYPE)
+ case CS_UINT_TYPE:
+ return "CS_UINT_TYPE";
+#endif
+#if defined(CS_UBIGINT_TYPE)
+ case CS_UBIGINT_TYPE:
+ return "CS_UBIGINT_TYPE";
+#endif
+#if defined(CS_XML_TYPE)
+ case CS_XML_TYPE:
+ return "CS_XML_TYPE";
+#endif
+#if defined(CS_BIGDATETIME_TYPE)
+ case CS_BIGDATETIME_TYPE:
+ return "CS_BIGDATETIME_TYPE";
+#endif
+#if defined(CS_BIGTIME_TYPE)
+ case CS_BIGTIME_TYPE:
+ return "CS_BIGTIME_TYPE";
+#endif
default:
break;
}
diff --git a/src/sqsh_config.h b/src/sqsh_config.h
index 4d2a047..a4af922 100644
--- a/src/sqsh_config.h
+++ b/src/sqsh_config.h
@@ -148,7 +148,7 @@
/*
* Current version number.
*/
-#define SQSH_VERSION "sqsh-2.2.0"
+#define SQSH_VERSION "sqsh-2.3"
#if !defined(__ansi__)
# if defined(__STDC__) || defined(STDC_HEADERS) || defined(PROTOTYPES)
diff --git a/src/sqsh_global.c b/src/sqsh_global.c
index d342c6c..5ddddd7 100644
--- a/src/sqsh_global.c
+++ b/src/sqsh_global.c
@@ -28,7 +28,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_global.c,v 1.8 2013/02/19 18:06:42 mwesdorp Exp $" ;
+static char RCS_Id[] = "$Id: sqsh_global.c,v 1.9 2013/07/20 16:18:35 mwesdorp Exp $" ;
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -57,3 +57,9 @@ int g_do_ncols = 0;
funcarg_t g_func_args[64];
int g_func_nargs = 0;
int g_interactive = False;
+
+#if defined(HAVE_LOCALE_H)
+ struct lconv *g_lconv = NULL;
+#else
+ void *g_lconv = NULL;
+#endif
diff --git a/src/sqsh_global.h b/src/sqsh_global.h
index 2dc101a..f9e1b09 100644
--- a/src/sqsh_global.h
+++ b/src/sqsh_global.h
@@ -35,6 +35,12 @@
#include "dsp.h"
#include "sqsh_func.h"
+#include "config.h"
+
+#if defined(HAVE_LOCALE_H)
+ #include <locale.h>
+#endif
+
/* g_cs_ver: This is the value of CS_VERSION_xxx. Stored in a global
* because it is needed to figure out the correct BLK_VERSION_xxx
* value to use in cmd_blk.c
@@ -152,4 +158,13 @@ extern char *g_lock;
*/
extern int g_interactive;
+/*
+ * g_lconv: sqsh-2.3 - Do locale conversion of numeric/decimal/money datatypes.
+ */
+#if defined(HAVE_LOCALE_H)
+ extern struct lconv *g_lconv;
+#else
+ extern void *g_lconv;
+#endif
+
#endif
diff --git a/src/sqsh_init.c b/src/sqsh_init.c
index c8f4e02..aa01f39 100644
--- a/src/sqsh_init.c
+++ b/src/sqsh_init.c
@@ -32,6 +32,10 @@
#include "sqsh_readline.h"
#include "sqsh_stdin.h"
#include "sqsh_init.h"
+#include "config.h"
+#if defined(HAVE_LOCALE_H)
+#include <locale.h>
+#endif
/*
* The following defines the tables which are used to inialize the
* variable global variables.
@@ -44,7 +48,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_init.c,v 1.6 2013/05/07 21:18:02 mwesdorp Exp $" ;
+static char RCS_Id[] = "$Id: sqsh_init.c,v 1.7 2013/07/20 16:18:35 mwesdorp Exp $" ;
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -64,8 +68,16 @@ int sqsh_init()
char *histsize ;
varbuf_t *expand_buf ;
+
+ /*
+ * sqsh-2.3 : Initialize locale to the default of C.
+ */
+#if defined(HAVE_SETLOCALE)
+ setlocale ( LC_ALL, "C" );
+#endif
+
/*
- * g_connection: This variable is initiazed to NULL. It is the responsibility
+ * g_connection: This variable is initiazed to NULL. It is the responsibility
* of a user function to actually perform the connection to
* set it. This allows sqsh to be started without actually
* connecting to the database.
@@ -97,7 +109,7 @@ int sqsh_init()
*/
if ((g_funcset = funcset_create()) == NULL)
{
- sqsh_set_error( sqsh_get_error(),
+ sqsh_set_error( sqsh_get_error(),
"cmdset_create: %s", sqsh_get_errstr());
return False;
}
@@ -108,7 +120,7 @@ int sqsh_init()
*/
for( i = 0; i < (sizeof(sg_cmd_entry) / sizeof(cmd_entry_t)); i++ ) {
- if( cmdset_add( g_cmdset,
+ if( cmdset_add( g_cmdset,
sg_cmd_entry[i].ce_name,
sg_cmd_entry[i].ce_func ) == False ) {
sqsh_set_error( sqsh_get_error(), "cmdset_add: %s",
@@ -127,7 +139,7 @@ int sqsh_init()
}
for( i = 0; i < (sizeof(sg_alias_entry) / sizeof(alias_entry_t)); i++ ) {
- if( alias_add( g_alias,
+ if( alias_add( g_alias,
sg_alias_entry[i].ae_name,
sg_alias_entry[i].ae_body ) == False ) {
sqsh_set_error( sqsh_get_error(), "alias_add: %s: %s",
@@ -187,9 +199,9 @@ int sqsh_init()
* environment. This, more-or-less, emulates the behaviour as
* if you had typed it in from the command line.
*/
- if( sqsh_expand( sg_var_entry[i].ve_value, expand_buf,
+ if( sqsh_expand( sg_var_entry[i].ve_value, expand_buf,
EXP_STRIPESC ) == False ){
- sqsh_set_error( sqsh_get_error(), "%s: %s",
+ sqsh_set_error( sqsh_get_error(), "%s: %s",
sg_var_entry[i].ve_value, sqsh_get_errstr());
return False ;
}
@@ -200,7 +212,7 @@ int sqsh_init()
varbuf_getstr(expand_buf), /* Default value */
sg_var_entry[i].ve_set, /* Settor function */
sg_var_entry[i].ve_get ) == False ) {
- sqsh_set_error( sqsh_get_error(), "env_set_valid: %s",
+ sqsh_set_error( sqsh_get_error(), "env_set_valid: %s",
sqsh_get_errstr() ) ;
return False ;
}
@@ -211,7 +223,7 @@ int sqsh_init()
NULL, /* NULL value */
sg_var_entry[i].ve_set, /* Settor function */
sg_var_entry[i].ve_get ) == False ) {
- sqsh_set_error( sqsh_get_error(), "env_set_valid: %s",
+ sqsh_set_error( sqsh_get_error(), "env_set_valid: %s",
sqsh_get_errstr() ) ;
return False ;
}
@@ -231,7 +243,7 @@ int sqsh_init()
* Allocate our global set of sub-processes.
*/
if( (g_jobset = jobset_create( 47 )) == NULL ) {
- sqsh_set_error( sqsh_get_error(), "jobset_create: %s",
+ sqsh_set_error( sqsh_get_error(), "jobset_create: %s",
sqsh_get_errstr() ) ;
return False ;
}
@@ -246,7 +258,7 @@ int sqsh_init()
i = 10 ;
if( (g_history = history_create( i )) == NULL ) {
- sqsh_set_error( sqsh_get_error(), "history_create: %s",
+ sqsh_set_error( sqsh_get_error(), "history_create: %s",
sqsh_get_errstr() ) ;
return False ;
}
@@ -340,7 +352,7 @@ void sqsh_exit( exit_status )
* This is due to the fact that the callback handler did not return
* to CS/CT-Library.
*/
- if (exit_status != 254)
+ if (exit_status != 254)
cs_ctx_drop( g_context );
g_context = NULL;
}
diff --git a/src/sqsh_job.c b/src/sqsh_job.c
index 19339c9..87c0790 100644
--- a/src/sqsh_job.c
+++ b/src/sqsh_job.c
@@ -44,7 +44,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_job.c,v 1.8 2013/05/07 21:18:02 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: sqsh_job.c,v 1.9 2013/07/20 16:18:35 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -1349,7 +1349,7 @@ static job_t* jobset_get( js, job_id )
hval = job_id % js->js_hsize;
/*-- Search for the job --*/
- for( j = js->js_jobs[job_id % js->js_hsize];
+ for( j = js->js_jobs[hval];
j != NULL && j->job_id != job_id; j = j->job_nxt );
/*-- ESTUPID --*/
diff --git a/src/sqsh_readline.c b/src/sqsh_readline.c
index 11e812e..98c8c13 100644
--- a/src/sqsh_readline.c
+++ b/src/sqsh_readline.c
@@ -33,10 +33,11 @@
#include "sqsh_init.h"
#include "sqsh_readline.h"
#include "sqsh_stdin.h"
+#include "sqsh_varbuf.h"
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_readline.c,v 1.10 2013/05/05 19:50:43 mwesdorp Exp $" ;
+static char RCS_Id[] = "$Id: sqsh_readline.c,v 1.11 2013/07/20 16:18:35 mwesdorp Exp $" ;
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -77,6 +78,12 @@ static keyword_t *sg_keyword_end = NULL ;
static keyword_t *sg_colname_start = NULL ;
static keyword_t *sg_colname_end = NULL ;
+/*
+ * sqsh-2.3 - Variable sg_rl_string points to varbuf buffer
+ * to prevent data overflows.
+*/
+static varbuf_t *sg_rl_string = NULL ;
+
#endif /* USE_READLINE */
@@ -138,8 +145,7 @@ int sqsh_readline_init()
if (sqsh_expand (readline_history, exp_buf, 0) != False)
read_history( varbuf_getstr(exp_buf) );
else
- fprintf( stderr, "sqsh: Error expanding $readline_history: %s\n",
- sqsh_get_errstr() );
+ fprintf( stderr, "sqsh: Error expanding $readline_history: %s\n", sqsh_get_errstr() );
varbuf_destroy (exp_buf);
}
@@ -163,6 +169,14 @@ int sqsh_readline_init()
*/
rl_completer_word_break_characters = " \t\n\"\\'`><=;|&{(";
+ /*
+ * sqsh-2.3 - Initialize variable sg_rl_string.
+ */
+ if( (sg_rl_string = varbuf_create (16384)) == NULL ) {
+ sqsh_set_error( sqsh_get_error(), "sg_rl_string: %s", sqsh_get_errstr() ) ;
+ return False ;
+ }
+
#endif /* USE_READLINE */
return True ;
@@ -203,6 +217,15 @@ int sqsh_readline_exit()
sqsh_get_errstr() );
varbuf_destroy (exp_buf);
}
+
+ /*
+ * sqsh-2.3 - Cleanup sg_rl_string.
+ */
+ if( sg_rl_string != NULL) {
+ varbuf_destroy ( sg_rl_string );
+ sg_rl_string = NULL;
+ }
+
#endif /* USE_READLINE */
return True;
@@ -217,9 +240,10 @@ int sqsh_readline_exit()
char* sqsh_readline( prompt )
char *prompt;
{
- static char str[4096];
- char *line;
+ static char str[16384];
+
#if defined(USE_READLINE)
+ char *line;
char *cp;
/* sqsh-2.1.6 - New variable */
char *ignoreeof = NULL;
@@ -229,119 +253,122 @@ char* sqsh_readline( prompt )
int match;
+ sqsh_set_error( SQSH_E_NONE, NULL );
+ if (prompt == NULL)
+ {
+ return ( sqsh_stdin_fgets( str, sizeof( str ) ) );
+ }
+
/* sqsh-2.1.6 feature - Expand color prompt */
prompt = expand_color_prompt (prompt, True);
- if (prompt != NULL)
+
+ /*
+ * sqsh-2.1.6 feature - Obtain environment variable ignoreeof. This will
+ * indicate if we have to ignore ^D yes or no.
+ */
+ env_get( g_env, "ignoreeof", &ignoreeof );
+ if (ignoreeof == NULL || *ignoreeof == '0')
{
/*
- * sqsh-2.1.6 feature - Obtain environment variable ignoreeof. This will
- * indicate if we have to ignore ^D yes or no.
+ * Standard behaviour:
+ * Since we have no way of capturing any real error conditions
+ * from readline, if it returns NULL we just have to assume
+ * that we have hit EOF, and not some error condition. From what
+ * we can tell from the readline library, there is no way to
+ * differentiate the two.
*/
- env_get( g_env, "ignoreeof", &ignoreeof );
- if (ignoreeof == NULL || *ignoreeof == '0')
+ if ((line = readline( prompt )) == NULL)
{
- /*
- * Standard behaviour:
- * Since we have no way of capturing any real error conditions
- * from readline, if it returns NULL we just have to assume
- * that we have hit EOF, and not some error condition. From what
- * we can tell from the readline library, there is no way to
- * differentiate the two.
- */
- if ((line = readline( prompt )) == NULL)
- {
- sqsh_set_error( SQSH_E_NONE, NULL );
- return NULL;
- }
+ return NULL;
}
- else
- {
- /*
- ** If ignoreeof is defined True, continue with readline
- ** as long as NULL is returned (accidentally C-d pressed).
- */
- while ((line = readline( prompt )) == NULL) {
- fprintf (stdout, "\nUse \"exit\" or \"quit\" to leave the sqsh shell.\n");
- fflush (stdout);
- }
+ }
+ else
+ {
+ /*
+ ** If ignoreeof is defined True, continue with readline
+ ** as long as NULL is returned (accidentally C-d pressed).
+ */
+ while ((line = readline( prompt )) == NULL) {
+ fprintf (stdout, "\nUse \"exit\" or \"quit\" to leave the sqsh shell.\n");
+ fflush (stdout);
}
+ }
+ /*
+ * Attempt to find out if there is anything in this line except
+ * for white-space. If there isn't then don't save it to the
+ * history.
+ */
+ for (cp = line; *cp != '\0' && isspace((int)*cp); ++cp);
+ if (*cp != '\0')
+ {
/*
- * Attempt to find out if there is anything in this line except
- * for white-space. If there isn't then don't save it to the
- * history.
- */
- for (cp = line; *cp != '\0' && isspace((int)*cp); ++cp);
-
- if (*cp != '\0')
+ * sqsh-2.2.0 - If $readline_histignore is set, then do not add the line to
+ * the readline history if it matches the provided regular expression or
+ * equals one of the colon separated list of keywords.
+ * if $readline_histignore starts with RE: then it is considered a regular
+ * expression that is evaluated with function regex_match.
+ * Rationale is to filter out the 'go', 'lo', 'mo', quit, etc.
+ * statements from the readline history.
+ */
+ match = False;
+ env_get( g_env, "readline_histignore", &readline_histignore );
+ if (readline_histignore != NULL && *readline_histignore != '\0')
{
/*
- * sqsh-2.2.0 - If $readline_histignore is set, then do not add the line to
- * the readline history if it matches the provided regular expression or
- * equals one of the colon separated list of keywords.
- * if $readline_histignore starts with RE: then it is considered a regular
- * expression that is evaluated with function regex_match.
- * Rationale is to filter out the 'go', 'lo', 'mo', quit, etc.
- * statements from the readline history.
+ * Duplicate the variable to a work buffer so we
+ * can modify it. What we want to do is strip of begin
+ * and end double quotes, if they exists.
*/
- match = False;
- env_get( g_env, "readline_histignore", &readline_histignore );
- if (readline_histignore != NULL && *readline_histignore != '\0')
+ readline_histignore = sqsh_strdup (readline_histignore);
+ cp = readline_histignore;
+ if ( cp != NULL && *cp == '"' && *(cp+strlen(cp)-1) == '"' )
+ {
+ *(cp+strlen(cp)-1) = '\0';
+ cp = readline_histignore + 1;
+ }
+
+ if ( cp != NULL && strncmp (cp, "RE:", 3) == 0 )
{
/*
- * Duplicate the variable to a work buffer so we
- * can modify it. What we want to do is strip of begin
- * and end double quotes, if they exists.
+ * readline_histignore contains an extended regular expression
+ * if the string starts with RE:
*/
- readline_histignore = sqsh_strdup (readline_histignore);
- cp = readline_histignore;
- if ( cp != NULL && *cp == '"' && *(cp+strlen(cp)-1) == '"' )
- {
- *(cp+strlen(cp)-1) = '\0';
- cp = readline_histignore + 1;
- }
-
- if ( cp != NULL && strncmp (cp, "RE:", 3) == 0 )
+ cp = cp + 3;
+ if (regex_match (cp, line) == 0)
+ match = True;
+ }
+ else
+ {
+ for (p1 = cp; p1 != NULL && match == False; p1 = p2)
{
- /*
- * readline_histignore contains an extended regular expression
- * if the string starts with RE:
- */
- cp = cp + 3;
- if (regex_match (cp, line) == 0)
+ if ( (p2 = strchr(p1, ':')) != NULL )
+ *p2++ = '\0';
+ if ( strcmp (line, p1) == 0 )
match = True;
}
- else
- {
- for (p1 = cp; p1 != NULL && match == False; p1 = p2)
- {
- if ( (p2 = strchr(p1, ':')) != NULL )
- *p2++ = '\0';
- if ( strcmp (line, p1) == 0 )
- match = True;
- }
- }
- if ( readline_histignore != NULL )
- free (readline_histignore);
}
- if ( match == False )
- add_history( line );
+ if ( readline_histignore != NULL )
+ free (readline_histignore);
}
-
- /*
- * Since readline mallocs line every time and doesn't append a
- * newline, we make a copy of the current line, adding the newline
- * and free the readline copy.
- */
- sqsh_set_error( SQSH_E_NONE, NULL );
- sprintf( str, "%s\n", line );
- free( line );
-
- return str;
+ if ( match == False )
+ add_history( line );
}
-#endif
+ /*
+ * Since readline mallocs line every time and doesn't append a
+ * newline, we make a copy of the current line, adding the newline
+ * and free the readline copy.
+ * sqsh-2.3 - Use a flexible buffer instead of an array to store
+ * the line. This is to prevent data overflows.
+ */
+ varbuf_strcpy ( sg_rl_string, line );
+ varbuf_strcat ( sg_rl_string, "\n" );
+ free( line );
+ return (varbuf_getstr( sg_rl_string ));
+
+#else /* USE_READLINE */
/*
* If the user supplied a prompt, then print it out. Otherwise
@@ -357,15 +384,10 @@ char* sqsh_readline( prompt )
* Keep trying to read a line until we hit feof(stdin), or while
* we are getting interrupted by signal handlers.
*/
- line = sqsh_stdin_fgets(str, sizeof( str ));
+ return ( sqsh_stdin_fgets( str, sizeof( str )));
- if (line == NULL)
- {
- return(NULL);
- }
+#endif
- sqsh_set_error( SQSH_E_NONE, NULL );
- return line;
}
/*
diff --git a/src/var.h b/src/var.h
index c8d1ce4..bdc3caf 100644
--- a/src/var.h
+++ b/src/var.h
@@ -62,6 +62,7 @@ int var_set_bcp_trim _ANSI_ARGS(( env_t*, char*, char** )) ;
int var_set_maxlen _ANSI_ARGS(( env_t*, char*, char** )) ;
int var_set_datefmt _ANSI_ARGS(( env_t*, char*, char** )) ;
int var_set_timefmt _ANSI_ARGS(( env_t*, char*, char** )) ;
+int var_set_lconv _ANSI_ARGS(( env_t*, char*, char** )) ;
/*-- Retrieval validation functions --*/
int var_get_date _ANSI_ARGS(( env_t*, char*, char** )) ;
@@ -204,6 +205,8 @@ static var_entry_t sg_var_entry[] = {
{ "script", NULL, var_set_nullstr, NULL },
{ "semicolon_hack2", "0", var_set_bool, NULL },
{ "tds_version", NULL, var_set_nullstr, NULL },
+ /* sqsh-2.3 - New variable */
+ { "localeconv", "0", var_set_lconv, NULL },
} ;
#endif /* SQSH_INIT */
diff --git a/src/var_misc.c b/src/var_misc.c
index 9e5cb2e..de80d4d 100644
--- a/src/var_misc.c
+++ b/src/var_misc.c
@@ -29,10 +29,11 @@
#include "sqsh_error.h"
#include "sqsh_stdin.h"
#include "var.h"
+#include "sqsh_global.h"
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: var_misc.c,v 1.1 2004/04/07 12:35:05 chunkm0nkey Exp $" ;
+static char RCS_Id[] = "$Id: var_misc.c,v 1.2 2013/07/20 16:18:35 mwesdorp Exp $" ;
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -124,7 +125,7 @@ int var_set_esc( env, var_name, var_value )
if( *src == '\\' ) {
++src ;
switch( *src ) {
- case 'n' :
+ case 'n' :
*dst++ = '\n' ;
break ;
case 'f' :
@@ -218,7 +219,7 @@ int var_set_bool( env, var_name, var_value )
return True ;
/*-- Map True or Yes to 1 --*/
- if( strcasecmp( *var_value, "True" ) == 0 ||
+ if( strcasecmp( *var_value, "True" ) == 0 ||
strcasecmp( *var_value, "Yes" ) == 0 ||
strcasecmp( *var_value, "On" ) == 0 ) {
*var_value = "1" ;
@@ -226,7 +227,7 @@ int var_set_bool( env, var_name, var_value )
}
/*-- Map False or No to 0 --*/
- if( strcasecmp( *var_value, "False" ) == 0 ||
+ if( strcasecmp( *var_value, "False" ) == 0 ||
strcasecmp( *var_value, "No" ) == 0 ||
strcasecmp( *var_value, "Off" ) == 0 ) {
*var_value = "0" ;
@@ -330,7 +331,7 @@ int var_set_add( env, var_name, var_value )
if( !isdigit((int)*value) )
n = value + 1 ;
- else
+ else
n = value ;
/*-- Check the digits --*/
@@ -411,3 +412,63 @@ int var_set_path_r( env, var_name, var_value )
return True;
}
+
+/*
+ * var_set_lconv() - sqsh-2.3
+ *
+ * Validation function for setting variable localeconv (1/0, True/False, Yes/No)
+ * When set to true, initialize variable g_lconv to localeconv(), NULL otherwise.
+ * Returns True if validation succeed, False otherwise.
+ */
+int var_set_lconv( env, var_name, var_value )
+ env_t *env ;
+ char *var_name ;
+ char **var_value ;
+{
+ /*
+ * Perform simple validations.
+ */
+ if( var_value == NULL || *var_value == NULL || **var_value == '\0' ) {
+ sqsh_set_error( SQSH_E_INVAL, "Invalid boolean value" ) ;
+ return False ;
+ }
+
+ /*-- Map True or Yes to 1 --*/
+ if( strcasecmp( *var_value, "True" ) == 0 ||
+ strcasecmp( *var_value, "Yes" ) == 0 ||
+ strcasecmp( *var_value, "On" ) == 0 ) {
+ *var_value = "1" ;
+ }
+ /*-- Map False or No to 0 --*/
+ else if( strcasecmp( *var_value, "False" ) == 0 ||
+ strcasecmp( *var_value, "No" ) == 0 ||
+ strcasecmp( *var_value, "Off" ) == 0 ) {
+ *var_value = "0" ;
+ }
+
+ if( strcmp( *var_value, "1" ) == 0 )
+ {
+#if defined(HAVE_SETLOCALE) && defined(HAVE_LOCALECONV)
+ setlocale ( LC_ALL, "" );
+ g_lconv = localeconv();
+ return True;
+#else
+ g_lconv = NULL;
+ *var_value = "0" ;
+ sqsh_set_error( SQSH_E_INVAL, "setlocale() and/or localeconv() not available" ) ;
+ return False;
+#endif
+ }
+ else if( strcmp( *var_value, "0" ) == 0 )
+ {
+#if defined(HAVE_SETLOCALE)
+ setlocale ( LC_ALL, "C" );
+#endif
+ g_lconv = NULL;
+ return True;
+ }
+
+ sqsh_set_error( SQSH_E_INVAL, "Invalid boolean value" ) ;
+ return False ;
+}
+