Server Variables (Shared Variables)

When programming a single user database, you can store values (text or numbers) that you want to keep in one or more permanent variables. These values will be saved when you save the database. Permanent values can be used with shared databases, but they aren’t shared. Each local copy of the database has its own private copy of the permanent variables. There is no way that one user can find out what another user’s permanent variables contain, and no way to change what values are stored in another user’s variables.

If you want to share a variable across the network, you have to use a new kind of variable, a server variable. As you might guess, server variables are kept on the server. Panorama has several statements and functions that allow a procedure to create, modify and access server variables.

### Creating and Assigning a Value to a Server Variable

The simplest way to create a server variable is to use the letservervariable statement. This statement works just like an assignment, but the destination of the assignment is a server variable associated with the current database (which must be a shared database). For example, this statement creates a server variable named pageCount and assigns the value 23 to it.

    letservervariable pageCount=23

The value can be any data type, for example a text value will also work:

    letservervariable userName="Bob"

Another way to create, but not modify, a server variable is to use the defineservervariable statement. This statement defines the value of a permanent variable on the server associated with the current shared database – but if the variable already exists, it is not touched. The defineservervariable statement is useful when you want to initialize a server variable if it has not already been set up, but leave it alone if it has already been set up before. This example initializes the shared variable defaultAreaCode with the text 714.

    defineservervariable defaultAreaCode,"714"

Later, the value could be modified by using the letservervariable, assignservervariable or adjustservervariable statements, but using the defineservervariable statement again will not modify the variable’s value.

A third way to create a server variable is to use the assignservervariable statement. This is similar to the letservervariable statement but allows you to specify a different database (instead of the current database), and allows you to specify the variable name with a formula. See the help page for the assignservervariable statement for further details.

If you ever want to get rid of a server variable, use the undefineservervariable statement. To find out what server variables have been set up for a database, use the servervariables( function.

### Accessing the Value of a Server Variable

To find out the current value of a server variable, use the servervariable( function. This function has two parameters — the name of the database (which may be omitted if the variable is in the current database) and the name of the variable (which must be in quotes). This procedure calculates the sales tax based on the shared TaxRate server variable.

    SalesTax=SubTotal*(servervariable("TaxRate")/100)

If the TaxRate server variable is associated with a different database, you can specify that. In this example the TaxRate server variable is in the Accounting database:

    SalesTax=SubTotal*(servervariable("Accounting","TaxRate")/100)

### Adjusting the Value of a Server Variable (Performing an Atomic Operation)

To adjust the value of an existing server variable, for example to increment or decrement the value, you need to use the adjustservervariable statement to make sure that the adjustment is coordinated properly across all the users of the database. This is called an “atomic” operation because no other change is allowed to happen until the operation is complete, ensuring that the calculation is correct even if multiple users try to adjust the same value at the same time.

To illustrate this, suppose you want to keep track of how many times invoices have been printed to a PDF file – keeping track of the count no matter what computer was used to do the printing. This example shows how this can be done.

     adjustservervariable "InvoicePrintCount",1
     printtopdf "invoices.pdf","Form","Invoice Template"

Each time this code runs, the InvoicePrintCount server variable is incremented by one (1, 2, 3, 4, etc.). This calculation is done on the server and stored on the server; the new value isn’t even available on the local computer (if you want that value, you can use the adjustservervariable( function).

You might wonder why a special statement is needed for this – why can’t you simply use the letservervariable statement and servervariable( function, and do the math with the + operator, something like this:

    let count = servervariable("InvoicePrintCount")
    letservervariable "InvoicePrintCount",count+1

This two step code will work fine when only one user is using the database. But if multiple people are using the database at the same time, there is always the chance that they will run this code at exactly the same time. Suppose the count is set to 2, and Bob and Frank both run this code at the exact same time. Both with get a count value of 2 from the servervariable( function. Then both will add 1 and the new count will be 3. But that’s wrong, the count should be 4, since both Bob and Frank have printed.

By using the adjustservervariable statement, you make sure that each user gets their own unique number (in this case one gets 3, the other 4), and that the final count is correct (in this case 4). Since the math is actually happening on the server, accesses is gated so that only one user can actually get access at a time. This is called an “atomic” operation because it can’t be split.

In addition to the adjustservervariable statement, there is also an adjustservervariable( function. This works just the same, however it also returns the new, updated value of the server variable to the local computer. If you don’t care what the new value is, the adjustservervariable statement is fine, but if you do need that value (for example to print it on your report), use the function version of this operation.

If the variable name contains spaces or punctuation, or begins with any character except a letter or underscore, you must surround the variable name with chevrons (Option-`«` and Shift-Option-`»`), like this:

    adjustservervariable «Base Tyre Size»,"25"

Normally the variable name is “hard coded” into the code as shown in the examples above, but you can also calculate the variable name with a formula instead. This example will create a different variable depending on the day of the week – MondayClose, TuesdayClose, WednesdayClose, etc. This example extends today’s closing time by 30 minutes.

    adjustservervariable datepattern( today(),"DayOfWeek")+"Close",time("30")

The adjustservervariable statement normally modifies a server variable belonging to the current database, but you can specify a different database if you want. The specified database must be a shared database, and it must be currently open. Here is a revised version of the previous example that modifies the server defaultAreaCode variable in the Contacts database instead of the current database.

    adjustservervariable "Contacts",completedCallCount,1

### Destroying a Server Variable

If we’re done with a web server variable it can be destroyed with the undefineservervariable function, like this.

    undefine "flagURL"

This removes the variable from the server, so no one will be able to access it or its contents any more. So take care with this statement. Note: This statement can only destroy one server variable at a time, if you want to destroy many variables, you’ll have to use this statement over and over.

### Getting Information about Server Variables

To get a list of all the server variables belonging to a database, use the servervariables( function.

    servervariables()

This function returns a carriage return delimited list of the available server variables. You could use this list to see if a particular server variable has even been created yet.

To get both the list of variables and the contents themselves, use the servervariables( function. This returns a dictionary that contain all of the server variable names and their values. For example, if you are not sure what server variables belong to the Contacts database, you can use this code to access and display all of the variables.

    dumpdictionary(servervariables("Contacts"))

Or you could grab the dictionary and then extract values from individual items, like this.

    let vars = servervariables("Contacts")
    let city = getdictionaryvalue(vars,"CITY")
    let state = getdictionaryvalue(vars,"STATE")
    let salesrep = getdictionaryvalue(vars,"REPRESENTATIVE")

Keep in mind when you do this that these values immediately start going stale. If a user on another computer updates the CITY server variable 5 minutes from now, you’re copy will still have the old copy. So it’s best not to hold on to these values for very long, unless you’re not worried about them being stale.

### Accessing Server Variables in Web Publishing Code

Server variables allow different Panorama clients to share variables. All of the code examples above illustrate how server variables can be used in code that runs on client computers.

However, server variables can also be accessed and modified on the server itself, in web publishing code. All of the functions and statements described above will also work in web publishing code on the server. For example, web publishing code could use the formula:

    servervariable("TaxRate")

to access the shared TaxRate variable, or the code:

    letservervariable TaxRate = 6.75

to modify this variable. The only difference is that since this code is already running on the server, there is no delay when accessing or modifying server variables. When running web publishing code, server variables are just as fast as regular variables. However, you do still have to use the special functions and statements described above to access these variables – you can’t simply reference them by name as you would with regular variables.

### The SetServerVariable Statement (Deprecated)

Panorama 6.0 and earlier versions included a SetServerVariable statement that combined the capabilities of the letservervariable, defineservervariable and adjustservervariable statements into one complicated mess. This statement caused so much confusion that it was removed from Panorama X. If you have existing code that uses this statement, you’ll need to rewrite that code using the letservervariable, defineservervariable and adjustservervariable statements.

### Learn More

For more information about specific functions and statements that manipulate server variables, see:

- adjustservervariable( -- The adjustservervariable( function adjusts the value of a server variable. This is an "atomic" operation, so it is multi-user friendly.
- adjustservervariable -- The adjustservervariable statement adjusts the value of a server variable. This is an "atomic" operation, so it is multi-user friendly.
- assignservervariable -- The assignservervariable statement assigns a value to a permanent variable on the server. If the server variable does not already exist, it will be created.
- defineservervariable -- The defineservervariable statement defines the value of a permanent variable on the server. If the variable already exists, it is not touched.
- letservervariable -- The letservervariable statement creates a server variable and assigns a value to it.
- servervariable( -- The servervariable( function returns the value of a server variable (a permanent variable on the server).
- servervariablenames( -- The servervariablenames( function returns the names of all server variables associated with a database.
- servervariables( -- The servervariables( function returns the names and values of all server variables associated with a database. The names and values are returned in a dictionary.
- undefineservervariable -- The undefineservervariable statement destroys a server variable.

See Also

- Bulk Data Transformations on Shared Databases -- using formulafill, propagate, etc. in a shared environment.
- Controlling and Monitoring the Server Connection -- overriding automatic server connection behavior.
- Looking up Data Directly from the Server -- local in-memory vs. server lookups.
- Record Locking in Procedure Code -- implicit and explicit management of record locking.
- Synchronizing in Procedure Code -- customizing the data synchronization process.

History

Version | Status | Notes
10.2 | New | New in this version.