Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: retrieving result-code and output -- howto? #2487

Closed
sdonovanuk opened this issue Aug 9, 2024 · 4 comments
Closed

Question: retrieving result-code and output -- howto? #2487

sdonovanuk opened this issue Aug 9, 2024 · 4 comments
Assignees
Labels
Question Used when a question is asked, as opposed to an issue being raised

Comments

@sdonovanuk
Copy link

sdonovanuk commented Aug 9, 2024

Greetings. Please consider the following T/SQL:

exec xp_cmdshell 'robocopy path1 path2 file'

That call actually has two pieces of output: (i) the result-code from robocopy, and (ii) output -- which is the stdout from the call, returned as 1x column.

Question/Problem: I cannot find JDBC calls (or Spring's JdbcTemplate) that allow me to extract both pieces of data.

You can either (i) use a CallableStatement:

jdbcTemplate.execute("{? = call xp_cmdshell(?)}",
    (CallableStatement cs) -> {
        cs.registerOutParameter(1, Types.INTEGER);
        cs.setString(2, "robocopy " +
            filenames.getSourcePath() + " " +
            filenames.getTargetPath() + " " +
            filenames.getSourceFile() + " /mt");
        cs.execute();
        final var returnCode = cs.getInt(1);
        if (returnCode != 0 && returnCode != 1) {
            throw new ApplicationException("robocopy failed (code " + returnCode + ")");
        }
        return 0;
    });

. . . . to get the return-code (and any output parameter(s)), or, (ii) you can issue a regular query (e.g. jdbcTemplate.queryForList(..)) to get the stdout.

I cannot find a way of retrieve both sets of data. It's possible I haven't looked hard enough, or it's also possible the JDBC spec doesn't deal with this case. I'm not sure what the correct answer would be: multiple result-sets?

Any ideas? Thank you!

@sdonovanuk sdonovanuk changed the title [QUESTION] Question: retrieving result-code and output -- howto? Aug 9, 2024
@barryw-mssql barryw-mssql added the Question Used when a question is asked, as opposed to an issue being raised label Aug 9, 2024
@barryw-mssql
Copy link
Contributor

Hi sdonvanuk,

I would proceed with your option #1 to get the return code as you have currently identified in your code example. The stdout is a little more problematic as JDBC does not recognize stdout. stdout is an OS feature and so the best way to capture that data is to modify your T-SQL to use the Windows command prompt redirection operator (i.e. ">") to redirect to a file. Once the CallableStatement completes, the OS should have completed writing stdout to a file which you can read into your application like any other file:

    EXEC xp_cmdshell 'robocopy path1 path2 file > robocopy_out.txt';

It should be noted that ROBOCOPY has it's own logging to file feature that you can use in addition to stdout or to complement the stdout log file. You can find details here:

   https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy

Please let us know if this helps.

Thx,
Barry

@barryw-mssql barryw-mssql self-assigned this Aug 9, 2024
@Jeffery-Wasty
Copy link
Contributor

Hi @sdonovanuk,

Please let us know if you have any further questions. If not, we will move forward with closing this issue.

@sdonovanuk
Copy link
Author

sdonovanuk commented Aug 13, 2024

Greetings. Sorry for the slow response. I was a little confused by the comment "as JDBC does not recognize stdout". Again, if I use jdbcTemplate.queryForList(..) or similar, the result-set comes back (1x column, called "output"). What @barryw-mssql gave was a workaround. What I was hoping to find out was: is there a variant of some JDBC method that doesn't require the workaround, and can expose both the (i) return-code, and (ii) the result-set (with the "output" column)?

I should add: I'm 100% aware <cough, cough> that we shouldn't be using xp_cmdshell, and we're working to fix that. However, the challenge is that each call to xp_cmdshell takes, minimum, around 120-150ms, so we're trying to avoid round-trips to retrieve results.

Thank you!

@barryw-mssql
Copy link
Contributor

According to the docs for xp_cmdshell the data directed to stdout is returned in the stored proc result set (https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/xp-cmdshell-transact-sql?view=sql-server-ver16#arguments). In the example code you provided you did not attempt to read the callable statement result set. Please give this a try.

We will be closing this question now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question Used when a question is asked, as opposed to an issue being raised
Projects
Status: Closed Issues
Development

No branches or pull requests

3 participants