Skip to content

Conversation

@MohamedM216
Copy link

@MohamedM216 MohamedM216 commented Nov 22, 2025

  • The Jira issue number for this PR is: MDEV-36269

Description

This PR provides a descriptive error message when users accidentally use a directory with the source command instead of getting an ambiguous error message: Can't initialize batch_readline.

Release Notes

How can this PR be tested?

Create a local branch tracking the upstream branch 10.6.

git checkout -b 10.6 upstream/10.6

Then build and start the server as mentioned here

And after running these commands you will get the desired output (descriptive error message):

MariaDB [(none)]> source /tmp/test_source_dir;
ERROR: '/tmp/test_source_dir' is a directory, not a file
MariaDB [(none)]> source /tmp/nonexistent_file;
ERROR: Failed to open file '/tmp/nonexistent_file', error: 2
MariaDB [(none)]> exit
Bye

Basing the PR against the correct MariaDB version

  • This is a new feature or a refactoring, and the PR is based against the main branch.
  • This is a bug fix, and the PR is based against the earliest maintained branch in which the bug can be reproduced.

PR quality check

  • I checked the CODING_STANDARDS.md file and my PR conforms to this where appropriate.
  • For any trivial modifications to the PR, I am ok with the reviewer making the changes themselves.

@CLAassistant
Copy link

CLAassistant commented Nov 22, 2025

CLA assistant check
All committers have signed the CLA.

@MohamedM216
Copy link
Author

The only unit test that fails here: buildbot/amd64-windows passes successfully locally.

@svoj svoj added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Nov 22, 2025
client/mysql.cc Outdated
char buff[FN_REFLEN+60];
sprintf(buff, "'%s' is a directory, not a file", source_name);
return put_info(buff, INFO_ERROR, 0);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you look in client/readline.cc at the batch_readline_init its almost doing the same check.

If you look at the other call of batch_readline_init in this fine where stdin is passed, it just errors based on the return result of the batch_readline_init.

I recommend doing the same, just handle batch_readline_init the same way. Extend message to include potential memory allocation failure.

For tests - recommend adding someting in mysql-test/main/mysql_client_test.test. Something with -e "source $MASTER_MYSOCK" perhaps.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes addressed here

For .test and .result files I tried to use the environment variable I found here:

${CMAKE_SOURCE_DIR}/cmake ${CMAKE_SOURCE_DIR}/cmake/Internal/CPack)

like this $CMAKE_SOURCE_DIR, but the test handled /client directory as a file and threw this error: ERROR at line 1: Failed to open file '/server/client', error: 2. So I will use my local relative path just for now.

For the current implementation of .test and .result files I would be grateful if you take a look at them and help me figure out how to solve this error:

mohammad@mohammad:~/open-source/mariaDB/build-mariadb-server-debug$ mysql-test/mtr mysql-test/main/mysql_client_test-mysql-source-errors.test
Logging: /home/mohammad/open-source/mariaDB/server/mysql-test/mariadb-test-run.pl  mysql-test/main/mysql_client_test-mysql-source-errors.test
VS config: 
vardir: /home/mohammad/open-source/mariaDB/build-mariadb-server-debug/mysql-test/var
Checking leftover processes...
Removing old var directory...
Creating var directory '/home/mohammad/open-source/mariaDB/build-mariadb-server-debug/mysql-test/var'...
Checking supported features...
MariaDB Version 10.6.25-MariaDB-debug
 - SSL connections supported
 - binaries are debug compiled
 - binaries built with wsrep patch
Collecting tests...
Installing system database...

==============================================================================

TEST                                      RESULT   TIME (ms) or COMMENT
--------------------------------------------------------------------------

worker[01] Using MTR_BUILD_THREAD 300, with reserved ports 19000..19029
main.mysql_client_test-mysql-source-errors [ fail ]
        Test ended at 2025-11-24 13:56:06

CURRENT_TEST: main.mysql_client_test-mysql-source-errors
ERROR at line 1: Failed to read from '/home/mohammad/open-source/mariaDB/server/client': it is a directory, or memory allocation failed
--- /home/mohammad/open-source/mariaDB/server/mysql-test/main/mysql_client_test-mysql-source-errors.result      2025-11-24 13:55:59.185361398 +0200
+++ /home/mohammad/open-source/mariaDB/server/mysql-test/main/mysql_client_test-mysql-source-errors.reject      2025-11-24 13:56:06.678022007 +0200
@@ -5,4 +5,3 @@
 #
 # Try to SOURCE the /client directory (should fail)
 #
-ERROR: Failed to read from '/home/mohammad/open-source/mariaDB/server/client': it is a directory, or memory allocation failed

Result length mismatch

 - saving '/home/mohammad/open-source/mariaDB/build-mariadb-server-debug/mysql-test/var/log/main.mysql_client_test-mysql-source-errors/' to '/home/mohammad/open-source/mariaDB/build-mariadb-server-debug/mysql-test/var/log/main.mysql_client_test-mysql-source-errors/'
--------------------------------------------------------------------------
The servers were restarted 0 times
Spent 0.000 of 4 seconds executing testcases

Failure: Failed 1/1 tests, 0.00% were successful.

Failing test(s): main.mysql_client_test-mysql-source-errors

The log files in var/log may give you some hint of what went wrong.

If you want to report this error, MariaDB's bug tracker is found at
https://jira.mariadb.org

mysql-test-run: *** ERROR: there were failing test cases
mohammad@mohammad:~/open-source/mariaDB/build-mariadb-server-debug$

Copy link
Contributor

@svoj svoj Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source . is probably going to be simplest solution. But your test won't work on Windows anyway, since the check for file type is under #ifndef _WIN32.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source . is probably going to be simplest solution.

Should it look like this:
in .test

--exec $MYSQL -e "source ."

and in .result

ERROR: Failed to read from '.': it is a directory, or memory allocation failed

?

I tried that but it still fails although I have ubuntu installed on my machine.

Copy link
Contributor

@svoj svoj Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. How it fails?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the issue is caused by the test framework expecting a strict match between the error message in the .result file and the actual error message produced during the test. You can see this in the following output:

worker[01] Using MTR_BUILD_THREAD 300, with reserved ports 19000..19029
main.mysql_client_test-mysql-source-errors [ fail ]
        Test ended at 2025-11-24 17:30:54

CURRENT_TEST: main.mysql_client_test-mysql-source-errors
ERROR at line 1: Failed to read from '.': it is a directory, or memory allocation failed
--- /home/mohammad/open-source/mariaDB/server/mysql-test/main/mysql_client_test-mysql-source-errors.result      2025-11-24 15:25:50.676723768 +0200
+++ /home/mohammad/open-source/mariaDB/server/mysql-test/main/mysql_client_test-mysql-source-errors.reject      2025-11-24 17:30:54.452501704 +0200
@@ -5,4 +5,3 @@
 #
 # Try to SOURCE the current directory (should fail)
 #
-ERROR: Failed to read from '.': it is a directory, or memory allocation failed

Result length mismatch

However, when I run the server and test the changes, it displays the intended error message!

Copy link
Author

@MohamedM216 MohamedM216 Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is that when we use --exec $MYSQL -e "source .", the error message goes to stderr, but the mtr framework is only capturing stdout in the result comparison. So it should look like this: --exec $MYSQL -e "source ." 2>&1

new changes addressed here

Copy link
Contributor

@svoj svoj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check #3935, specifically #3935 (review). This code should be slightly refactored to look good.

@MohamedM216
Copy link
Author

Thank you both for the feedback. @svoj, I appreciate the refactoring suggestion. @grooverdan, since you initially reviewed this, I'd value your input on which approach to take before proceeding.

@MohamedM216 MohamedM216 requested a review from svoj November 24, 2025 12:39
Copy link
Member

@grooverdan grooverdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you move the test to the end of mysql-test/main/mysql_client_test.test this will resolve the embedded test failure (there's no client/server in embedded mode).

Rebase all commits onto the 10.11 branch, and squash them, include a commit message saying why these changes occurred. When finished git push --force and edit the github PR title to have 10.11 as the target branch.

At the end of the tests in mysql-test/main/mysql_client_test.test, put a --echo End of 10.11 tests. This is a standard practice to make it easier to resolve merge conflicts where multiple branches added tests. mtr --record mysql_client_test will update the result file in case you haven't discovered this, it doesn't need to be a manual edit (though do verify the contents).

--echo # Try to SOURCE the current directory (should fail)
--echo #

--error 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To resolve the difference in output on Windows:

Suggested change
--error 1
--replace_regex /(ERROR at line 1: Failed to).*/\1 REPLACED/
--error 1

client/mysql.cc Outdated
my_fclose(sql_file,MYF(0));
return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
char buff[FN_REFLEN+200];
sprintf(buff,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use a snprintf(sizeof(buff),...

client/mysql.cc Outdated
return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
char buff[FN_REFLEN+200];
sprintf(buff,
"Failed to read from '%s': it is a directory, or memory allocation failed",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a modifier on %s to restrict the message to the right most portion of the source_name. Adjust buffer size accordingly.

Message should be ".. it is a directory, block device, or memory allocation failed". Adjust the other batch_readline_init error message to be consistent with this.

@grooverdan
Copy link
Member

Please check #3935, specifically #3935 (review). This code should be slightly refactored to look good.

Works for me too. Duplicating error message isn't productive.

@MohamedM216 MohamedM216 changed the title MDEV-36269: Improve error handling for source command with directories MDEV-36269: Improve error handling for source command Nov 25, 2025
@MohamedM216 MohamedM216 changed the base branch from 10.6 to 10.11 November 25, 2025 12:20
Copy link
Contributor

@svoj svoj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice. Some minor polishing left.


static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,
ulong max_size);
bool init_line_buffer(LINE_BUFFER *buffer, File file, ulong size, ulong max_size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line, it shouldn't be needed anymore.


--echo #
--echo # Try to SOURCE the current directory (should fail)
--echo #
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant, you already say "Test that SOURCE on an existent directory returns a clear error" a few lines above.


--replace_regex /(ERROR at line 1: Failed to).*/\1 REPLACED/
--error 1
--exec $MYSQL -e "source ."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot 2>&1? There's no error in the result file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I misunderstood @grooverdan 's review.

--echo # Try to SOURCE the current directory (should fail)
--echo #

--replace_regex /(ERROR at line 1: Failed to).*/\1 REPLACED/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to think more about it. Ideally the same error should be returned on Windows. No action needed at the moment.

} LINE_BUFFER;

extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file);
extern LINE_BUFFER *batch_readline_init(ulong max_size, const char *path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line.

client/mysql.cc Outdated
return -1;
}

LINE_BUFFER *batch_readline_init(ulong max_size, const char *path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be static.

client/mysql.cc Outdated
if (path)
my_close(file, MYF(0));
put_info(buff, INFO_ERROR, 0);
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid code duplication, MariaDB common practice would be to use something like this:

...
goto err;

err1:
  put_info(buff, INFO_ERROR, 0);
err:
  if (path)
    my_close(file, MYF(0));
  return 0;

These labels should be after return line_buff.

Copy link
Contributor

@svoj svoj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More issues outlined.

client/mysql.cc Outdated
{
my_snprintf(buff, sizeof(buff), "Failed to open file '%.*s', error: %d",
FN_REFLEN, path, my_errno);
goto err1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't goto err1 from this point, as it will have to issue close(-1). Just do put_info() here.

client/mysql.cc Outdated
my_snprintf(buff, sizeof(buff), "Failed to stat file '%.*s', error: %d",
FN_REFLEN, path ? path : "stdin", my_errno);
goto err1;
goto err;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and everywhere else, remove second goto.

Copy link
Author

@MohamedM216 MohamedM216 Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean replace it with :

if (path)
      my_close(file, MYF(0));
    return 0;

or remove it totally?

EDIT: yeah I think I understand now. goto err1 will lead to run err:.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Second goto is never reachable anyway.

Copy link
Contributor

@svoj svoj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few more issues. Please also fix commit message according to https://github.com/MariaDB/server/blob/main/CODING_STANDARDS.md.

Specifically lines must be under 72 characters.

--echo # Test that SOURCE on an existent directory returns a clear error
--echo #

# --replace_regex /(ERROR at line 1: Failed to).*/\1 REPLACED/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line.

client/mysql.cc Outdated
{
my_fclose(sql_file,MYF(0));
return put_info("Can't initialize batch_readline", INFO_ERROR, 0);
return 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be return ignore_errors ? -1 : 1;

client/mysql.cc Outdated
}

#ifdef _WIN32
#else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, please do #ifndef _WIN32.

@MohamedM216 MohamedM216 requested a review from svoj November 26, 2025 14:30
@MohamedM216 MohamedM216 force-pushed the bugfix/mdev-36269 branch 4 times, most recently from dfb9afe to 82ed328 Compare November 27, 2025 10:48
@svoj
Copy link
Contributor

svoj commented Nov 27, 2025

@MohamedM216 I pushed 056e85f with coding style fixes to your branch. Please get it "fixup"-ed if you agree. Or I can do that myself.

Also we need to sort out failure on Windows. It looks like some sort of segmentation fault or stack overflow due to our Windows specific code. I have no idea how to debug it effectively at the moment. So I slightly modified the code, let's see how it works.

With these things completed, I think I can approve this pr.

@svoj
Copy link
Contributor

svoj commented Nov 27, 2025

@MohamedM216 it appears I broke your last force push with my force push. Sorry for the mess. Feel free to update it now.

@svoj
Copy link
Contributor

svoj commented Nov 27, 2025

I think I found a bug: it calls my_close() against failed my_open() on Windows. Well, uhm... what if we do something like this:

    if ((file= my_open(path, O_RDONLY | O_BINARY, MYF(0))) < 0)
    {
#ifdef _WIN32
      if (my_errno == EACCES && my_stat(path, &input_file_stat, MYF(0)) &&
          MY_S_ISDIR(input_file_stat.st_mode))
        my_snprintf(buff, sizeof(buff), "Can't read from a directory '%.*s'",
                    FN_REFLEN, path ? path : "stdin");
      else
#endif
      my_snprintf(buff, sizeof(buff), "Failed to open file '%.*s', error: %d",
                  FN_REFLEN, path, my_errno);
      put_info(buff, INFO_ERROR, 0);
      return 0;
    }

@MohamedM216 MohamedM216 force-pushed the bugfix/mdev-36269 branch 2 times, most recently from 528a18e to 84e21da Compare November 27, 2025 23:29
@MohamedM216
Copy link
Author

@svoj new changes addressed here

Copy link
Contributor

@svoj svoj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

client/mysql.cc Outdated
if (my_errno == EACCES && my_stat(path, &input_file_stat, MYF(0)) &&
MY_S_ISDIR(input_file_stat.st_mode))
my_snprintf(buff, sizeof(buff), "Can't read from a directory '%.*s'",
FN_REFLEN, path ? path : "stdin");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here path is always set, no need to path ? path : "stdin", missed this when copy-pasting.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svoj
Copy link
Contributor

svoj commented Nov 28, 2025

@grooverdan will you want to have another look?

@MohamedM216 MohamedM216 force-pushed the bugfix/mdev-36269 branch 2 times, most recently from 589115b to 7cd2cea Compare November 28, 2025 13:35
- refactor batch_readline_init to mysql.cc for proper error handling
- add unit test and move it to the end of main/mysql_client_test.test
to resolve embedded test failures
- remove unnecessary code and duplicates to clean up implementation
- redirect error message from stderr to stdout in .test file
- use labels to avoid code duplication
- handle windows check for block device
- ensure file failing to open in windows because being a directory
 is different from any other reason for clear error message
@MohamedM216
Copy link
Author

@grooverdan will you want to have another look?

@grooverdan just a gentle ping on this when you have a moment. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

5 participants