1 Basic Concepts
- In
XSQL
, variables are declared by a set tag and take the name of the name attribute. - The name of the variable is case-sensitive.
- The type of variable is automatic unless declared explicitly by the attribute type.
- The declaration of a variable creates a tag with the variable name, which can be referenced with a tag of the same name on the (function) context. For this reason, variable names cannot collide with previously-defined tag names.
- Variables can also be accessed through the get tag.
<xsql-script> <body> <set name='idx'>10</set> <!-- idx takes the value Integer 10 --> <set name='Pi'>3.14</set> <!-- Pi takes the value Double 3.14 --> <set name='name'>Robert</set> <!-- name takes the value String "Robert" --> <println><idx /></println> <println><Pi /></println> <println><name /></println> <println><get name='idx' /></println> </body> </xsql-script>
10
3.14
Robert
10
By default, variables are always assigned by value. This means that when you assign an expression to a variable, the full value of the original expression is copied into the destination variable. As such, for example, after assigning the value of one variable to another, changes made to one of these variables will not affect the other with the exception of complex types (arrays, maps, etc.) that are assigned by reference.
2 Declaration of Variables
The <set/> tag allows users to declare a variable and perform the assignment of a value in the same statement. To create a variable named 'a' with a string 'test'
<set name='a'>test</set>
or, to be more explicit
<set name='a'><string>test</string></set>
2.1 Declaration of Variables from External Sources (Records)
A very important option in XSQL
is the ability to automatically bind
variables from a database and vice versa.
In the following example, you will see the use of the select tag to automatically declare SQL statement fields m_.
<xsql-script> <body> <!-- create a temp table named tmp1 --> <table name='tmp1' temp='y'> <column name='id' type='int' /> <column name='name' type='char' size='30' /> </table> <!-- insert 1 element --> <insert table='tmp1'> <column name='id'>1</column> <column name='name'>CARS</column> </insert> <!-- insert 1 element --> <insert table='tmp1'> <column name='id'>2</column> <column name='name'>BIKES</column> </insert> <!-- select element 2 with variable prefix m_ --> <select prefix='m_'> <columns>*</columns> <from table='tmp1' /> <where>id=2</where> </select> <println> <m_id />:<m_name /> </println> </body> </xsql-script>
2:BIKES
The declaration of records from a database statement must be accompanied by a prefix to avoid collision with reserved identifiers.
2.2 Declaration of Iterator Variables
Some iteration commands allow you to create and assign values in the process loop. The iterator tag allows the user to go through arrays and maps. The value of an array element, key or map value, is automatically defined in the variable indicated by the name attribute.
<iterator name='a' type='key|entry'> <in> <map|array /> </in> <do> [instructions] </do> </iterator>
3 Scope of Variables
The scope of a variable is the context within which the variable is defined. Most XSQL variables have a simple scope. This simple scope also covers the included files. For example:
<xsql-script> <body> <set name='a'>1</set> <include name='file.xml'/> </body> </xsql-script>
Here, the variable a will be available inside the script including file.xml.
However, within the functions defined by the user, a local scope is introduced for the function. Any variable used within a function is, by definition, limited to the local scope of the function. Moreover, defined functions are opaque to predecessor functions, so that their variables are invisible. For example:
<xsql-script> <body> <function name='sub1'> <body> <set name='a'>2</set> <println>sub1: <a/></println> </body> </function> <set name='a'>1</set> <println>main: <a/></println> <sub1/> <println>main: <a/></println> </body> </xsql-script>
main: 1
sub1: 2
main: 1
In the following example, you can see that the variable a is different in the local function sub1, and therefore, the variable a in the main function is invisible within the local function. Local functions, therefore, have their own variables not shared with predecessor functions. If required, some variables must be in argument form.
3.1 Global Variables
The option exists to declare global variables for the life cycle of the main function and its descendants. Global variables are declared by the global.set tag and, unlike normal variables, do not appear declared as language tags and can only be referenced by global.set and global.get.
<xsql-script> <body> <function name='sub1'> <body> <println>sub1: <global.get name='a'/></println> <global.set name='a'>2</global.set> <println>sub1: <global.get name='a'/></println> </body> </function> <global.set name='a'>1</global.set> <println>main: <global.get name='a'/></println> <sub1/> <println>main: <global.get name='a'/></println> </body> </xsql-script>
main: 1
sub1: 1
sub1: 2
main: 2
4 Reference to Variables
Variables can be referenced in different ways according to the scope of reference.
4.1 References in Context
Within the XML body, variables can be referenced in two ways:
- Using a tag as the name of the variable itself.
- Using the get tag with the name attribute indicating the variable.
<xsql-script> <body> <set name='a'>Hello</set> <println><a/></println> <println><get name='a'/></println> </body> </xsql-script>
Hello
Hello
4.2 References in Attributes
In some cases, it is necessary to use a variable within an attribute. In such cases, there are two ways to reference the variable.
- #var is accepted for compatibility but cannot be used in all cases, such as when using an embedded script or when the script is executed as a code in an SQL object where #var refers to a main cursor field.
- ${var}, which is the recommended and safest way.
<xsql-script> <body> <array name='list'> <string>row 0</string> <string>row 1</string> <string>row 2</string> <string>row 3</string> <string>row 4</string> <string>row 5</string> <string>row 6</string> <string>row 7</string> <string>row 8</string> <string>row 9</string> <string>row 10</string> <string>row 11</string> </array> <set name='pos'>1</set> <!-- classic TAG variable access --> <println><pos/> <array.get> <list /> <pos /> </array.get> </println> <!-- classic ATTRIBUTE variable access --> <!-- PROBLEM: can conflict with wic_jrep_object #variable in XSQL scripts embebed --> <println>#pos <array.getElementAt position='#pos'> <list /> </array.getElementAt> </println> <!-- ANT style ATTRIBUTE combinated variable access --> <println>{$pos} <array.getElementAt position='${pos}'> <list /> </array.getElementAt> </println> <!-- ANT style ATTRIBUTE combinated variable access (access position 11) --> <println>1{$pos} <array.getElementAt position='1${pos}'> <list /> </array.getElementAt> </println> </body> </xsql-script>
<pos>
row 1
#pos
row 1
{$pos}
row 1
1{$pos}
row 11
4.3 Variable Names
It is sometimes useful to have variable names that can be defined and used dynamically. A normal variable is established by a statement as:
<xsql-script> <body> <set name='mes_1'>Enero</set> <set name='mes_2'>Febrero</set> <set name='idx'>2</set> <println><get name='mes_${idx}'/></println> </body> </xsql-script>
February
4.4 Reference in an SQL Statement
4.4.1 Reference Types
In SQL expressions, the reference operator '#' can be used to obtain the value of a variable. The difference between using the reference operator and using a tag with the name of the variable is:
- the first one is transformed before executing the SQL statement.
- the second uses a prepared statement and resolves the value of the variable at that moment.
Normally, it is preferable to use a tag with the name of the variable, but there are cases in which using the reference operator is necessary. The following examples have the same result:
<xsql-script> <body> <!-- create a temp table named tmp1 --> <table name='tmp1' temp='y'> <column name='id' type='int' /> <column name='name' type='char' size='30' /> </table> <!-- insert 1 element --> <insert table='tmp1'> <column name='id'>1</column> <column name='name'>CARS</column> </insert> <!-- insert 1 element --> <insert table='tmp1'> <column name='id'>2</column> <column name='name'>BIKES</column> </insert> <set name='p_id'>2</set> <!-- select element by reference --> <select prefix='m_'> <columns>*</columns> <from table='tmp1' /> <where>id = #p_id</where> </select> <!-- select element by tag --> <select prefix='m_'> <columns>*</columns> <from table='tmp1' /> <where>id = <p_id /></where> </select> <println> <m_id />:<m_name /> </println> </body> </xsql-script>
2:BIKES
SQL Statement with Reference Operator
In the previous example, the first SQL statement is resolved as:
SELECT * FROM tmp1 WHERE id = 2
SQL Statement with Operator Tag
And the second SQL statement is resolved as:
SELECT * FROM tmp1 WHERE id = ?
The second case is much more efficient if the variable will take different values and perform multiple SQL operations, since the same PreparedStatement will always be used.
4.4.2 Quotation Marks
Returning to the previous example, let's assume that we want to select using the name field of the table, which belongs to the character type. It should be written:
<xsql-script> <body> <!-- create a temp table named tmp1 --> <table name='tmp1' temp='y'> <column name='id' type='int' /> <column name='name' type='char' size='30' /> </table> <!-- insert 1 element --> <insert table='tmp1'> <column name='id'>1</column> <column name='name'>CARS</column> </insert> <!-- insert 1 element --> <insert table='tmp1'> <column name='id'>2</column> <column name='name'>BIKES</column> </insert> <set name='p_name'>BIKES</set> <!-- select element by reference --> <select prefix='m_'> <columns>*</columns> <from table='tmp1' /> <where>name = '#p_name'</where> </select> <!-- select element by tag --> <select prefix='m_'> <columns>*</columns> <from table='tmp1' /> <where>name = <p_name /></where> </select> <println> <m_id />:<m_name /> </println> </body> </xsql-script>
2:BIKES
In this case, quotation marks must be used if the reference to the p_name variable is used so that the SQL statement is correctly formed. On the other hand, using the variable tag is not necessary for a PreparedStatement.
SQL Statement with Reference Operator
In the previous example, the first SQL statement is resolved as:
SELECT * FROM tmp1 WHERE name = 'BIKES'
In this case, quotation marks have been added to the reference operator.
SQL Statement with Operator Using Tag
And the second SQL statement is resolved as:
SELECT * FROM tmp1 WHERE name = ?
In some cases, the reference operator must be used explicitly, e.g. if the value of a condition of the "where" clause is placed in a variable. In this case, this part cannot be prepared and, therefore, it is necessary to resolve the SQL expression directly.
Here is an example where it is used: <where>#p_where</where>:
<xsql-script> <body> <!-- create a temp table named tmp1 --> <table name='tmp1' temp='y'> <column name='id' type='int' /> <column name='name' type='char' size='30' /> </table> <!-- insert 1 element --> <insert table='tmp1'> <column name='id'>1</column> <column name='name'>CARS</column> </insert> <!-- insert 1 element --> <insert table='tmp1'> <column name='id'>2</column> <column name='name'>BIKES</column> </insert> <!-- Set a where clause using a variable --> <set name='p_where'>name = 'BIKES'</set> <!-- select element by tag --> <select prefix='m_'> <columns>*</columns> <from table='tmp1' /> <where>#p_where</where> </select> <println> <m_id />:<m_name /> </println> </body> </xsql-script>
5 Deletion of Variables
It is possible to delete variables that have been created previously. A variable can be deleted manually by indicating its name, or several variables can be deleted by indicating the prefix of the name.
locales
<unset name='a' /> <unset>a</unset> <unset><a/></unset> <unset>variable_<a/></unset> <unset><a/><b/></unset> <unset prefix='capuntes_' />
globales
<global.unset name='a' /> <global.unset>a</global.unset> <global.unset><a/></global.unset> <global.unset>variable_<a/></global.unset> <global.unset><a/><b/></global.unset> <global.unset prefix='capuntes_' />
6 Variable Data Types
A variable can contain any supported data type. The variables do not have a predefined type. They acquire the type of data they contain at each moment. Therefore, a variable can be re-assigned to different types of data.
A string is assigned to the variable <set name='a'> <string>HELLO</string> </set> An (integer) number is assigned to the variable <set name='a'> <number>10</number> </set> A decimal number is assigned to the variable <set name='a'> <number type='decimal'>10</number> </set>
Note that the number constructor is the <number> function. This returns the object of some numeric primitive types such as smallint, integer, long, float, double, decimal depending on the size and precision of the number or value of the optional attribute.
Variables take the same data type depending on the means of assignment.
- Assignment with automatic conversion
- Assignment for another variable
- Assignment by function
- Assignment by argument type
6.1 Assignment with Automatic Conversion
A variable declaration with a type omission comes from automatic detection. This system generates string, integer or decimal types depending on the entry data. For example:
<set name='a1'>Hello</set> <!-- String --> <set name='a2'>10</set> <!-- Integer --> <set name='a3'>10.05</set> <!-- BigDecimal(2) --> <set name='a3'>2000000000</set> <!-- Long --> <set name='a4'>2000000000000000000000</set> <!-- BigInt -->
Note
This option is not recommended, as the type must be declared explicitly.
6.2 Assignment by Another Variable
When a variable is assigned to another variable, the latter takes the value and the type of the former.
<set name='a1'>Hello</set> <!-- String --> <set name='a2'>10</set> <!-- Integer --> <set name='a3'><a1/></set> <!-- String(Hello) --> <set name='a4'><a2/></set> <!-- integer(10) -->
Note
Note that if the object to which it refers is an object value, the two variables contain copies of the object. However, if it is a reference, both of them point to the same object.
6.3 Assignment by Function
When a variable is defined by a function call (of the system or a subroutine), it has a value determined by the function.
<set name='a1'><string>Hello</string></set> <!-- String --> <set name='n1'><number>10</number></set> <!-- Integer --> <set name='n2'><number>10.05</number></set> <!-- BigDecimal(2) --> <set name='n3'><number>20000000000</number></set> <!-- Long --> <set name='n4'><number>2000000000000000000000</number></set> <!-- BigInt -->
Note
Note that the '''<number>''' function takes different types of numbers and creates a numeric object size, as well as corresponding precision for the source value.
6.4 Assignment by Type of Argument
After the value of a function has been determined, the argument can define a data type. In this case, the constructor of the function will force the original's conversion to a specified type. If it is omitted, the argument will have the source variable type.
<xsql-script name='args'> <body> <!-- function sin tipos definidos --> <function name='divide1'> <args> <arg name='x' /> <arg name='y' /> </args> <body> <return><div><x/><y/></div></return> </body> </function> <!-- function con tipos definidos --> <function name='divide2'> <args> <arg name='x' type='double' /> <arg name='y' type='double' /> </args> <body> <return><div><x/><y/></div></return> </body> </function> <set name='a'><number>10</number></set> <set name='b'><number>2</number></set> <println><divide1><a/><b/></divide1></println> <!-- 5 --> <println><divide2><a/><b/></divide2></println> <!-- 5.0 --> </body> </xsql-script>
5
5.0
7 Variables by Value or Reference
A variable can be assigned to another variable or passed as an argument to another routine or function. The resulting variable of assignment or function parameter are variables too. The important issue is knowing whether the new variable is:
- a copy of the original variable (different).
- a reference to the original variable, meaning the same variable with a different name.
In the following example, we can see how the modified number value of the function is not reflected in the main function, but the map is modified. This means that the numeric value is a value, while the map is a reference.
<xsql-script> <body> <function name='sub1'> <args> <arg name='p_num' /> <arg name='p_map' /> </args> <body> <set name='p_num'><add><p_num />1</add></set> <map.put name='p_map'><string>TANKS</string><number>2</number></map.put> </body> </function> <set name='n1'>90</set> <map name='m1'> <item><string>CARS</string><number>10</number></item> <item><string>BIKES</string><number>20</number></item> </map> <sub1> <n1/> <m1/> </sub1> <println><n1 /></println> <println><m1 /></println> </body> </xsql-script>
90
{CARS=10, BIKES=20, TANKS=2}
7.1 Pass by Value
When a call is done on a routine or function and variables are passed as arguments, it is said that the variable is passed by value when the modifications made to the routine or function do not affect the variable.
Some variables with types are passed by value. In other words, the variable is not what passes by value, but rather the data type it contains. Types which are passed by value include:
- string
- smallint
- integer
- bigint
- long
- float
- double
- decimal
- date
- time
- timestamp
- dateunits
7.2 Pass by Reference
When a call is done on a routine or function and variables are passed as arguments, the variable is passed by reference when the modifications done on the routine or call function affect the variable which has been passed.
The objects comprise collections or maintain connections with other systems. Types which are passed by reference include:
- byte
- file
- node
- element
- array
- map
- vtable
8 Concatenation of Variables
It is important to keep in mind that tags <set> and <global.set> only receive an argument. For this reason, if the content must be concatenated in two or more variables, an argument must be passed to a function which will be the unique argument <set>. For example, to concatenate two strings, the following code must be used:
c = a + space + b
<xsql-script> <body> <set name="a">Hello</set> <set name="b">world</set> <set name='c'> <string><a /><string.space /><b /></string> </set> <println> <c /> </println> </body> </xsql-script>
Hello world
9 Variable Inspection
To verify if a local variable has been instanced, the <isdefined> tag can be used.
<xsql-script> <body> <println><isdefined name='a' /></println> </body> </xsql-script>
false
The <variable.typeof> tag verifies if a variable type can be used.
<xsql-script> <body> <set name='p_boolean' ><true/></set> <set name='p_integer' >5000</set> <set name='p_long' >20000000000</set> <set name='p_bigint' >20000000000000000000000</set> <set name='p_decimal'>3.14</set> <set name='p_date'><date.today /></set> <set name='p_smallint' type='smallint'>5000</set> <set name='p_float' type='float'>3.14</set> <set name='p_double' type='double'>3.14</set> <println>Automatic</println> <println>p_boolean : <p_boolean /> : <variable.typeof><p_boolean /></variable.typeof></println> <println>p_integer : <p_integer /> : <variable.typeof><p_integer /></variable.typeof></println> <println>p_long : <p_long /> : <variable.typeof><p_long /></variable.typeof></println> <println>p_bigint : <p_bigint /> : <variable.typeof><p_bigint /></variable.typeof></println> <println>p_decimal : <p_decimal /> : <variable.typeof><p_decimal /></variable.typeof></println> <println>p_date : <p_date /> : <variable.typeof><p_date /></variable.typeof></println> <println /> <println>Fixed type</println> <println>p_smallint: <p_smallint /> : <variable.typeof><p_smallint /></variable.typeof></println> <println>p_float : <p_float /> : <variable.typeof><p_float /></variable.typeof></println> <println>p_double : <p_double /> : <variable.typeof><p_double /></variable.typeof></println> </body> </xsql-script>
Automatic
p_boolean : true : java.lang.Boolean
p_integer : 5000 : java.lang.Integer
p_long : 20000000000 : java.lang.Long
p_bigint : 20000000000000000000000 : java.math.BigInteger
p_decimal : 3.14 : java.math.BigDecimal
p_date : 12-09-2016 : java.sql.Date
Fixed type
p_smallint: 5000 : java.lang.Short
p_float : 3.14 : java.lang.Float
p_double : 3.14 : java.lang.Double: java.lang.Float
p_double : 3.14 : java.lang.Double
10 Type Conversion
XSQL language is very flexible in relation to passing arguments. If a relaxed system is chosen, it is not necessary to indicate the argument type of routines or functions. Conversely, if more rigid verificaction is needed at execution time, the data type can be indicated for the arguments.
When an argument does not fulfill the expected type and the conversion fails, an error will be shown at the time of execution. A frequent scenario is to pass a large size number to a routine which expects a smaller numeric data type. For example, if the user passes a value of 40000 to a routine which expects smallint types, whose rank is -32768, an error will be produced.
<xsql-script> <body> <function name='sub1'> <args> <arg name='p_num' type='smallint' /> </args> <body> <set name='p_num'><add><p_num />1</add></set> </body> </function> <sub1> <number>40000</number> </sub1> </body> </xsql-script>
VariableException: unsupported conversion from data='40000' of class='java.lang.Integer' to type='smallint'
In the same way, assign a value to a variable with a strict type
<xsql-script> <body> <set name='p_num' type='smallint'>40000</set> </body> </xsql-script>
VariableException: unsupported conversion from data='40000' of class='java.lang.Integer' to type='smallint'