diff options
author | mwesdorp <mwesdorp> | 2013-07-20 16:18:35 +0000 |
---|---|---|
committer | mwesdorp <mwesdorp> | 2013-07-20 16:18:35 +0000 |
commit | 401914fae46f2c9d8b20e2fcf806f69844a20d12 (patch) | |
tree | a156be6fa3242a43105e2a1324aff96a80e4095a /src | |
parent | 85624b6169eee1219ce692d75bdea94ff526be44 (diff) |
sqsh-2.3 new features and bugfixes
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd_connect.c | 10 | ||||
-rw-r--r-- | src/cmd_do.c | 41 | ||||
-rw-r--r-- | src/cmd_func.c | 8 | ||||
-rw-r--r-- | src/cmd_input.c | 128 | ||||
-rw-r--r-- | src/config.h.in | 7 | ||||
-rw-r--r-- | src/dsp_conv.c | 246 | ||||
-rw-r--r-- | src/dsp_desc.c | 368 | ||||
-rw-r--r-- | src/dsp_html.c | 32 | ||||
-rw-r--r-- | src/dsp_meta.c | 70 | ||||
-rw-r--r-- | src/sqsh_config.h | 2 | ||||
-rw-r--r-- | src/sqsh_global.c | 8 | ||||
-rw-r--r-- | src/sqsh_global.h | 15 | ||||
-rw-r--r-- | src/sqsh_init.c | 36 | ||||
-rw-r--r-- | src/sqsh_job.c | 4 | ||||
-rw-r--r-- | src/sqsh_readline.c | 224 | ||||
-rw-r--r-- | src/var.h | 3 | ||||
-rw-r--r-- | src/var_misc.c | 71 |
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; } /* @@ -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 ; +} + |