Concat two variables into new variable - stored-procedures

I want to set privileges to some specific tables. These tablesNames are stored in a variable(tableName) like the schemas (schemaName) aswell. My mission is to concatinate these variables to schemaName.tableName .
I've tried to concatinate these variables, but I'm ending into getting an variable is not defined.
GRANT SELECT ON schemaName || "." || tableName TO roleName;
Is there any way to use variable variables like in PHP? example

You cannot do this using a static statement. The GRANT statement does not allow the use of variables for schema or table name.
In a stored procedure you can use a dynamic statement instead. Something like:
DECLARE stmt VARCHAR(100);
...
SET stmt = 'GRANT SELECT ON ' || schemaName || '.' || tableName ||
' TO ' || rolename;
EXECUTE IMMEDIATE stmt;

Related

Error: Incorrect syntax near '#variable' in stored procedure in azure sql database

I am trying to create a stored procedure with parameters in an Azure SQL Database - Basic Managed Instance, through the Query Editor.
Any time I make reference to any parameter, I get a syntax error, independently of the rest of the SQL code.
I have been successful creating stored procedures without parameters.
Even the simplest code leads to an error:
CREATE PROCEDURE testProcedure
#masterPassword varchar(50)
AS
BEGIN
OPEN MASTER KEY DECRYPTION BY PASSWORD = #masterPassword;
END
I would not expect any errors. However, I still receive this error:
Failed to execute query. Error: Incorrect syntax near '#masterPassword'.
Try this -
CREATE OR ALTER PROCEDURE testProcedure
#masterPassword varchar(50)
AS
BEGIN
DECLARE #SELECT NVARCHAR(MAX);
SELECT #SELECT=N'OPEN MASTER KEY DECRYPTION BY PASSWORD = ''' + #masterPassword + ''' '; --Expecting String
EXEC (#SELECT);
END
--UNIT TESTING-
--error
select ''' + #in + '''
--corrected method
declare #a nvarchar(50),#in varchar(50);
set #in=cast('hi' as varchar(50));
select #a=' select ''' + #in + ''' ';
exec (#a)

Jenkins Pipeline define and set variables

I am using branch name to pass it into build script. $(env.BRANCH_NAME).
I would like to manipulate the value before using it. For example in case we build from trunk I want suffix for the build output be empty but in case of branch I want it to be -branch name.
currently I am doing it by defining environment section.
environment {
OUTPUT_NAME_SUFFIX = ($(env.BRANCH_NAME) == 'trunk') ? '': $(env.BRANCH_NAME)
}
I am getting this error:
WorkflowScript: 4: Environment variable values must either be single quoted, double quoted, or function calls. # line 4, column 62.
(env.BRANCH_NAME) == 'trunk') ? '': $(en
^
What the best way to define variables and eval their values in scope of pipeline.
TIA
You can use string interpolation to evaluate the expression:
environment {
OUTPUT_NAME_SUFFIX = "${env.BRANCH_NAME == 'trunk' ? '': env.BRANCH_NAME}"
}
This will fix the error you're getting, however pipeline does not allow you to have environment variables that are of 0 length, aka empty string (JENKINS-43632).
That means that setting OUTPUT_NAME_SUFFIX to '' is like unseting it. You might want to precalculate the whole name of your output, so that your env variable is never an empty string.
I have solved it by adding following code. So far had no issues with empty strings.
stage('Set Environmnet'){
steps {
script {
if(BRANCH_NAME == 'trunk'){
env.OUTPUT_NAME_SUFFIX = ''
}else if (BRANCH_NAME.startsWith("branches")){
env.OUTPUT_NAME_SUFFIX = "-" + BRANCH_NAME.substring(BRANCH_NAME.lastIndexOf("/")+1)
}else{
env.OUTPUT_NAME_SUFFIX = ''
}
}
}
}

How can I use Firebird's Execute Block with Delphi TSQLQuery?

Using dbExpress TSQLQuery, I can't execute a query with execute block command because that command requires ? notation for parameters, and Delphi uses : for parameters, then, if in the body of that block creates variables and uses them as
select data from table where .... into :var;
that ":var" is interpreted as a parameter by TSQLQuery.
Which is the way for executing an execute block statement with Delphi?
If I write:
execute block(param1 char(1)=:param1)
I can load a value for :param1 from Delphi, but when I execute it with Query.Open or Query.ExecSQL an error returns indicating absence of parameter so ? because in Firebird execute block is written:
execute block(param1 char(1)=?param1)
Is there any way to resolve this with TSQLQuery?
first you can disable the TSQLQuery property for
ParamCheck := False;
Then at the beginning of execute block, remove the parameter path..
execute block (param1 char (1) = :param1)
and your query is passed (%s) instead of :param1.
I did so in my problem and solved it !
":var" is interpreted as a parameter by TSQLQuery
You can turn that off by setting the ParamCheck property to False.
the only way that worked for me was not putting ":" for internal vars in the block.
Ex. select data from table into var; and that's work!, then, as this is a block, evaluate the var with an if!
if (var = 1)
do something;
else
do anotherthing;
and resolved business!

How to handle unexisting variables passed to a proc

I would like to create a procedure like this simple example:
proc name {args} {
foreach val $args {
puts $val
}
}
But I would like the procedure to handle variables that don't exist, something like the code shown below:
proc name {args} {
foreach val $args {
if [info exists $val] {
puts $val
}
}
}
The problem is that the code is not executed because as soon as I call the procedure with an unexisting variable it immediately stalls, prior to go into the code, saying that there is a variable that doesn't exist. Is it probable because the procedure checks argument existance before entering the body?.
I can make it work by changing args by several optional variables with predefined values, but that limits the procedure and makes it look bad.
Can I make a proc able to handle unexisting variables?
You can't pass a variable as an argument: arguments have to be values. You can pass a variable name as an argument and use that as a reference to the variable inside the procedure. Example:
proc name args {
foreach varname $args {
upvar 1 $varname var
if {[info exists var]} {
puts $var
}
}
}
(The call to upvar creates a link between the variable whose name is the value of the variable varname outside the procedure and the variable called var inside the procedure. This is one way to "pass a variable to a procedure".)
Then you can do this:
% set foo 1 ; set baz 3
% name foo bar baz
1
3
Note that if you try to invoke the procedure as
% name $bar
where bar is undefined, the interpreter tries (and fails) to evaluate it before calling the procedure. That might be what you are seeing.
Documentation:
upvar
If we look at the point where you are calling the command (procedures are commands; they're a subclass really) you'll see something like this in your code:
name $a $b $c
That's fine if all those variables exist, but if one doesn't, it will blow up even before name is called. In Tcl, $a means exactly “read the variable a and use its contents here”, unlike in some other languages where $ means “look out language, here comes a variable name!”
Because of this, we need to change the calling convention to be one that works with this:
name a b c
That's going to require the use of upvar. Like this:
proc name {args} {
foreach varName $args {
# Map the caller's named variable to the local name “v”
upvar 1 $varName v
# Now we can work with v in a simple way
if {[info exists v]} {
puts $v
}
}
}
You made a mistake here
if [info exists $val]
When info exists is used it should be checked against variable name, not the variable value.
Lets come to your actual question.
You can pass the arguments to the procedure as a key-value pair, then it is pretty simple.
proc user_info {args} {
#Converting the arguments into array
if {[catch {array set aArgs $args}]} {
puts "Please pass the arguments as key-value pair"
return 1
}
#Assume, we need to ensure these 3 arguments passed for sure.
set mandatoryArgs "-name -age -country"
foreach mArg $mandatoryArgs {
if {![info exists aArgs($mArg)]} {
puts "Missing mandatory argument '$mArg'"
return 1
}
}
}
user_info -name Dinesh

Grails <where> returns DetachedCriteria with all entries

Domain.where {
1 == 0
}.count()
This returned all the elements of the domain class. The more general case:
Domain.where {
false
}.count()
Will return all elements; if I use one of the fields and make a false condition, the result is as expected.
My question is why does this happen (the first case) ? If it is a too naive question, please just suggest some reading material. Thanks!
The version of grails that I use is 2.3.6 (it may be different in newer versions?)
I'm not sure what you are trying to achieve, but here is an explanation (maybe a bit general because of that :).
What you pass to the where method is actually a DSL for specifying SQL criterias, it just uses normal Groovy syntax to pretend to be more natural. But when you do someProperty != 5 && someOtherProperty == 6 that is not evaluated directly, but transformed to end up in an SQL query as select * from Domain where some_property != 5 and some_other_property = 6.
Since you are not passing any reference to a property in your criteria (1 == 0), it gets ignored by the detached criteria DSL evaluator, thus returning the result of select * from domain. You can try to do for example id != id to see how you get an empty list as the result. If you again examine the resulting query, you'll see that a where id<>id is included.
You can learn more about the where method: https://grails.github.io/grails-doc/latest/guide/GORM.html#whereQueries
Bear in mind that what you pass to the where method is a Closure, so the code inside is not executed upfront, and is not necessarily evaluated in the context where it was declared. You can learn more about Groovy Closures. Also about creating DSLs with Groovy, though is a bit of an advanced topic.
(I simplified the SQL queries to make them more undestandable, if you activate the query log of Hibernate or MySQL/other DB you are using, you'll see they are bigger).
To illustrate Deigote's explanation, here's a very crude implementation of a WHERE query builder (actually just the WHERE clause) using the criteria criteria format:
class WhereBuilder {
def conditions = []
def eq(column, value) {
conditions << [
column: column,
operator: '=',
value: value]
}
def ne(column, value) {
conditions << [
column: column,
operator: '!=',
value: value]
}
String toString() {
'WHERE ' <<
conditions.collect {
"${it.column} ${it.operator} '${it.value}'"
}.join(' AND ')
}
}
def builder = new WhereBuilder()
builder.with {
1 == 0
false
eq 'firstName', 'John'
ne 'lastName', 'Smith'
}
assert builder.toString() == "WHERE firstName = 'John' AND lastName != 'Smith'"
As you can see, the expressions 1 == 0 and false have no effect.

Resources