diff --git a/src/isql/extract.epp b/src/isql/extract.epp index cc0ba7a7a5..69c4048030 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -494,7 +494,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, if (!RFR.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf(" "); - SHOW_print_metadata_text_blob (isqlGlob.Out, &RFR.RDB$DEFAULT_SOURCE); + SHOW_print_metadata_text_blob(isqlGlob.Out, &RFR.RDB$DEFAULT_SOURCE, false, true); } if (!RFR.RDB$GENERATOR_NAME.NULL) @@ -801,7 +801,7 @@ static void get_procedure_args(const char* proc_name) if (!prm_default_source_null) { isqlGlob.printf(" "); - SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source); + SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source, false, true); } } } @@ -852,12 +852,12 @@ static void get_procedure_args(const char* proc_name) if (!prm_default_source_null) { isqlGlob.printf(" "); - SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source); + SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source, false, true); } else if (!FLD.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf(" "); - SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE); + SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE, false, true); } } } @@ -1020,7 +1020,7 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg) if (!prm_default_source_null) { isqlGlob.printf(" "); - SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source); + SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source, false, true); } } } @@ -1072,12 +1072,12 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg) if (!prm_default_source_null) { isqlGlob.printf(" "); - SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source); + SHOW_print_metadata_text_blob(isqlGlob.Out, &prm_default_source, false, true); } else if (!FLD.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf(" "); - SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE); + SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE, false, true); } } } @@ -2262,7 +2262,7 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i if (!FLD.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf("%s%s ", NEWLINE, TAB_AS_SPACES); - SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE); + SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE, false, true); } if (!FLD.RDB$VALIDATION_SOURCE.NULL) { @@ -2384,7 +2384,7 @@ static void list_domains(SSHORT default_char_set_id) if (!FLD.RDB$DEFAULT_SOURCE.NULL) { isqlGlob.printf("%s%s ", NEWLINE, TAB_AS_SPACES); - SHOW_print_metadata_text_blob (isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE); + SHOW_print_metadata_text_blob(isqlGlob.Out, &FLD.RDB$DEFAULT_SOURCE, false, true); } // Validation moved to listDomainConstraints(). if (FLD.RDB$NULL_FLAG == 1) @@ -3270,7 +3270,7 @@ static void list_indexes() { isqlGlob.printf(" COMPUTED BY "); if (!IDX.RDB$EXPRESSION_SOURCE.NULL) - SHOW_print_metadata_text_blob (isqlGlob.Out, &IDX.RDB$EXPRESSION_SOURCE); + SHOW_print_metadata_text_blob(isqlGlob.Out, &IDX.RDB$EXPRESSION_SOURCE, false, true); isqlGlob.printf("%s%s", isqlGlob.global_Term, NEWLINE); } else if (ISQL_get_index_segments (collist, sizeof(collist), IDX.RDB$INDEX_NAME, true)) diff --git a/src/isql/isql.epp b/src/isql/isql.epp index 4b4db43596..4d46b1171a 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -575,7 +575,7 @@ static bool M_Transaction() { if (DB && !M__trans && setValues.KeepTranParams) { - M__trans = DB->execute(fbStatus, NULL, + M__trans = DB->execute(fbStatus, NULL, TranParams->length(), TranParams->c_str(), isqlGlob.SQL_dialect, NULL, NULL, NULL, NULL); @@ -1390,6 +1390,123 @@ processing_state ISQL_fill_var(IsqlVar* var, } +// Check if statement ends with single-line comment. +bool ISQL_statement_ends_in_comment(const char* statement) +{ + const char* const statementStart = statement; + const char* commentStart = NULL; + const char* commentEnd = NULL; + const char* altQuoteStart = NULL; + char altQuoteChar = '\0'; + + enum + { + normal, + in_single_line_comment, + in_block_comment, + in_single_quoted_string, + in_double_quoted_string + } state = normal; + + while (char c = *statement++) + { + char lastChar = statement - 1 == statementStart ? '\0' : statement[-2]; + + switch (c) + { + case '\n': + if (state == in_single_line_comment) + state = normal; + break; + + case '-': + // Could this the be start of a single-line comment. + if (state == normal && lastChar == '-') + state = in_single_line_comment; + break; + + case '*': + // Could this the be start of a comment. We can only look back, not forward. + // Ignore possibilities of a comment beginning inside quoted strings. + if (state == normal && lastChar == '/' && statement - commentEnd > 3) + { + state = in_block_comment; + commentStart = statement - 2; + } + break; + + case '/': + // Perhaps this is the end of a comment. + // Ignore possibilities of a comment ending inside quoted strings. + // Ignore things like /*/ since it isn't a block comment; only the start of it. Or end. + if (state == in_block_comment && lastChar == '*' && statement - commentStart > 3) + { + state = normal; + commentEnd = statement - 2; // mark start of non-comment to track this: /**/* + } + break; + + case SINGLE_QUOTE: + switch (state) + { + case normal: + if (lastChar == 'q' || lastChar == 'Q') + { + altQuoteStart = statement - 2; + + if (!(altQuoteChar = *statement++)) + return false; + + switch (altQuoteChar) + { + case '{': + altQuoteChar = '}'; + break; + case '(': + altQuoteChar = ')'; + break; + case '[': + altQuoteChar = ']'; + break; + case '<': + altQuoteChar = '>'; + break; + } + } + else + altQuoteChar = '\0'; + + state = in_single_quoted_string; + break; + + case in_single_quoted_string: + if (!altQuoteChar || lastChar == altQuoteChar) + state = normal; + break; + } + break; + + case DBL_QUOTE: + switch (state) + { + case normal: + state = in_double_quoted_string; + break; + case in_double_quoted_string: + state = normal; + break; + } + break; + + default: + break; + } + } + + return state == in_single_line_comment; +} + + void ISQL_get_default_source(const TEXT* rel_name, TEXT* field_name, ISC_QUAD* blob_id) @@ -1951,6 +2068,7 @@ void ISQL_print_validation(FILE* fp, bool issql = false; bool firsttime = true; TEXT buffer[BUFFER_LENGTH512]; + Firebird::string fullText; do { @@ -1988,6 +2106,7 @@ void ISQL_print_validation(FILE* fp, } IUTILS_printf(fp, buffer); + fullText += buffer; } while (true); // CVC: If firsttime == true, then it didn't write the "/*" or the "(". @@ -1998,6 +2117,9 @@ void ISQL_print_validation(FILE* fp, ISQL_errmsg(fbStatus); blob->close(fbStatus); + + if (ISQL_statement_ends_in_comment(fullText.c_str())) + fputc('\n', fp); } diff --git a/src/isql/isql_proto.h b/src/isql/isql_proto.h index 670ee71828..d9931317b6 100644 --- a/src/isql/isql_proto.h +++ b/src/isql/isql_proto.h @@ -66,5 +66,6 @@ void ISQL_ri_action_print(const TEXT*, const TEXT*, bool); //void ISQL_win_err(const char*); processing_state ISQL_print_item_blob(FILE*, const IsqlVar*, Firebird::ITransaction*, int subtype); processing_state ISQL_fill_var(IsqlVar*, Firebird::IMessageMetadata*, unsigned, UCHAR*); +bool ISQL_statement_ends_in_comment(const char* statement); #endif // ISQL_ISQL_PROTO_H diff --git a/src/isql/show.epp b/src/isql/show.epp index fe5452b0ca..a779a174e9 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -1853,7 +1853,7 @@ void SHOW_grant_roles2 (const SCHAR* terminator, } -void SHOW_print_metadata_text_blob(FILE* fp, ISC_QUAD* blobid, bool escape_squote) +void SHOW_print_metadata_text_blob(FILE* fp, ISC_QUAD* blobid, bool escape_squote, bool avoid_end_in_single_line_comment) { /************************************** * @@ -1876,6 +1876,7 @@ void SHOW_print_metadata_text_blob(FILE* fp, ISC_QUAD* blobid, bool escape_squot if (ISQL_errmsg(fbStatus)) return; + string fullText; SCHAR buffer[BUFFER_LENGTH512]; bool endedWithCr = false; @@ -1907,29 +1908,51 @@ void SHOW_print_metadata_text_blob(FILE* fp, ISC_QUAD* blobid, bool escape_squot } if (prevEndedWithCr && buffer[0] != '\n') - fputc('\r', fp); + { + fputc('\r', fp); + if (avoid_end_in_single_line_comment) + fullText += "\r"; + } if (escape_squote) { for (const UCHAR* p = (UCHAR*) buffer; *p; ++p) { if (*p == SINGLE_QUOTE) - fputc(*p, fp); - fputc(*p, fp); + { + fputc(*p, fp); + if (avoid_end_in_single_line_comment) + fullText += *p; + } + + fputc(*p, fp); + if (avoid_end_in_single_line_comment) + fullText += *p; } fflush(fp); } else + { IUTILS_printf(fp, buffer); + if (avoid_end_in_single_line_comment) + fullText += buffer; + } } if (endedWithCr) - fputc('\r', fp); + { + fputc('\r', fp); + if (avoid_end_in_single_line_comment) + fullText += "\r"; + } if (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS) ISQL_errmsg(fbStatus); blob->close(fbStatus); + + if (avoid_end_in_single_line_comment && ISQL_statement_ends_in_comment(fullText.c_str())) + fputc('\n', fp); } diff --git a/src/isql/show_proto.h b/src/isql/show_proto.h index 95073774ad..ca7053dbb1 100644 --- a/src/isql/show_proto.h +++ b/src/isql/show_proto.h @@ -33,7 +33,8 @@ processing_state SHOW_grants (const SCHAR*, const SCHAR*, USHORT); processing_state SHOW_grants2 (const SCHAR*, const SCHAR*, USHORT, const TEXT*, bool); void SHOW_grant_roles (const SCHAR*, bool*); void SHOW_grant_roles2 (const SCHAR*, bool*, const TEXT*, bool); -void SHOW_print_metadata_text_blob(FILE*, ISC_QUAD*, bool escape_squote = false); +void SHOW_print_metadata_text_blob(FILE*, ISC_QUAD*, bool escape_squote = false, + bool avoid_end_in_single_line_comment = false); processing_state SHOW_metadata(const SCHAR* const*, SCHAR**); void SHOW_read_owner(); const Firebird::string SHOW_trigger_action(SINT64);