Sqitch deploy of stored procedure with ampersand in code causes failure - snowflake-cloud-data-platform

The Sqitch deploy fails on a stored procedure script that is for snowflake and contains JavaScript code for the stored procedure which has a double ampersand (&&) in an IF...THEN conditional block. Sqitch thinks it is a variable and fails as far as I can tell.
Please advise how to treat ampersands (&) in comments or in the code of a stored procedure to get sqitch to ignore the &.

From the Snowflake docs:
To use an ampersand sign without using substitution, escape the ampersand sign with a second ampersand sign: &&variable
https://docs.snowflake.com/en/user-guide/snowsql-use.html
AFAIK, sqitch doesn't support variables, other than the ones native to the database:
https://groups.google.com/g/sqitch-users/c/zYuEYT44OgM/m/WglAw5eDCAAJ

Related

Using SqlCmd variable in PostDeploy DACPAC script

I have a variable stipulated in my SqlCmd.exe:
/v:PipelineUser=$(user)
I'm wanting to reference this from a DACPAC/Post Deploy script, but I'm not entirely sure how. The chat on the script template itself says this:
/*
Post-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be appended to the build script.
Use SQLCMD syntax to include a file in the post-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the post-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
But, that looks to be physically assigning a value to variable rather than referencing a release variable.
How do I reference the PipelineUser variable passed by SqlCmd within the Post Deploy script?
Found the solution. We need to reference the variable in the DACPAC/SSDT project properties.
Then when the deploy script is created as part of SqlCmd, it just gets substituted in.
Then we can reference however we want in our post-deploy script by using $(variablename)
This is an actual object name, and not simply a string. We can make it a string though by 'quoting' it.
Example usages:
DECLARE #userVARCHAR(100) = '$(user)';
ALTER AUTHORIZATION ON SCHEMA::[Staging] TO [$(user)];

SQLCMD - Capture output from Operating System Command as variable

I would like to capture the output of an sqlcmd !! (operating system command) call into a variable that I can use in an insert statement. Or, just read the contents of a file into a variable.
The general idea is something like this:
:SETVAR version !! "type version.txt"
insert into dbo.DeployVersion ([Version],[Date],[User]) values ('$(version)',getdate(),'$(SQLCMDUSER)')
But it doesn't seem that I can chain SQLCMD calls in that way. Any ideas?
type version.txt just prints the content of version.txt file to the console, like cat in linux.
The best I could find was this approach, which seemed really silly.
:setvar quot "'"
declare #versionString nvarchar(300)
set #versionString =
$(quot)
:r .\version.txt
$(quot)
insert into dbo.DeployVersion ([Version],[Date],[User]) values ('$(version)',getdate(),'xyz')
This works in purely SQLCMD and is an answer to the original question.
However, this is being used in an sqlpackage deploy and I don't see a way to externally reference a version.txt file from outside of the dacpac. So instead I added a variable to the dacpac project and I specify that value on the commandline using sqlpackage ... /Variables:Version=%someValueReadFromBatFile%

bq tool, bat file | escaping characters not working when CALL

Using bq tool I have no problem escaping the > operator with a caret ^:
bq query "SELECT x FROM [presentation_dim.dim_events] WHERE event^>1"
However, when I CALL the exact same command through a bat file whe whole thing breaks down.
call bq query "SELECT x FROM [presentation_dim.dim_events] WHERE event^>1"
I understand call is the problem here. I can't remove it, since I need to run additional commands after it (bq extract and gsutil cp). I've tried adaptations of what is shown on Escape user input in windows batch file, to no avail.
What's wrong here?
Thanks in advance.
I suppose bq.cmd itself contains something like this
set param1=%1
set SQL=%~2
python bigQuery.py --%param1% "%SQL%"
So the line set SQL=%1 requires escaping the special characters.
But when you use CALL, the batch parser has an additional phase of escaping but before it also has a phase of doubling all carets!
So your string in call bq query "SELECT x FROM [presentation_dim.dim_events] WHERE event^>1" is converted to
"SELECT x FROM [presentation_dim.dim_events] WHERE event^^>1"
I think there is no solution with only carets to solve this problem.
But you can avoid this by simply defining a variable containing one caret
set "caret=^"
call bq query "SELECT x FROM [presentation_dim.dim_events] WHERE event%%CARET%%>1"
Excuse me. I think there is a confusion here.
When a parameter is enclosed in quotes, it may include special Batch characters with no need to escape they; the only problematic case is when Delayed Expansion is enabled and the parameter include an exclamation-mark or caret. For example, this line works correctly:
bq query "SELECT x FROM [presentation_dim.dim_events] WHERE event>1"
This way, the same line with a CALL command also works correctly:
call bq query "SELECT x FROM [presentation_dim.dim_events] WHERE event>1"
If you escape the greater-than sign this way ^> and don't use CALL, the character passed is the same ^> that is processed as a single > in bq.bat. However, if you use CALL, then the escape is duplicated and ^^> is passed.
Conclusion: Don't escape the > character.

Setting sqlcmd variable using tsql variable

It seems like this approach for setting sqlcmd variable does not work so I am wondering if there is another way?
DECLARE #d varchar(max);
SET #d = 'foobar';
:setvar database #d
USE $(database)
Note: I realized that using :setvar in this manner works but I want to set it using a variable in the T-SQL script instead of explicitly setting it.
:setvar database "foobar"
This makes no logical sense, from the perspective of SQLCMD. :setvar is a command that lives outside the T-SQL script; it can't "see" anything the T-SQL script does at runtime. You can set the variable through any number of means, including environment variables, options and :setvar itself, but you can't mix in runtime T-SQL execution.
Rethink your script so the SQLCMD script lives "outside" the T-SQL script, and the T-SQL script does the necessary runtime actions. Since you can execute dynamic statements in T-SQL, there shouldn't be any need for setting an SQLCMD variable through T-SQL rather than the other way around.

sql server - setting variables at runtime

In Oracle you can use &&VAR_NAME in a script and then the script will ask you for that value when you run it.
In SQLSERVER you can use $(VAR_NAME) and reference a property file using:
:r c:/TEMP/sqlserver.properties
And in the property file you have something like:
:setvar VAR_NAME_some_value
Can you do the equivalent of &&VAR_NAME so the script asks you for the value when you run it instead of having the value predefined in a script.
If I've understood correctly, you're talking about variable substitution with the SQLCMD utility.
I don't see that SQLCMD supports the behaviour you describe.
An alternative would be to exploit the fact that SQLCMD will substitute the values of system or user environment variables (see the link above), and create a wrapper CMD script which prompts the user for the variable value(s) using SET with the /P flag.
There is nothing in sql server like this, you should predefine all parameters values before using them, like this:
DECLARE #i SMALLINT
SET #i = 1
The problem with having a form pop up and ask you for the parameter is that you normally want rather more control over the nature of the form, even for an admin script. I'd use the variable substitution in SQLCMD, from within a Powershell or Python script so you can provide the guy running the script a better and more helpful form. That would make a very powerful combination.
You can do quite a lot with template variable substitution in SSMS, but that would only go so far as formulating the correct SQL to execute. you'd then have to bang the button. It would be a bit clunky outside the development environment!

Resources