Skip to main content

Useful Skills to Learn

This page briefly describes some specific tasks that are useful for programmers to know how to perform. If you are familiar with how, when, and why to perform the tasks described here, you will be able to save yourself some time and effort.

Defining Databases

To create a local database:

  1. Log in to the Management Portal.

  2. Select System Administration > Configuration > System Configurations > Local Databases.

  3. Select Create New Database to open the Database Wizard.

  4. Enter the following information for the new database:

    • Enter a database name in the text box. Usually this is a short string containing alphanumeric characters; for rules, see Configuring Databases.

    • Enter a directory name or select Browse to select a database directory. If this is the first database you are creating, you must browse to the parent directory in which you want to create the database; if you created other databases, the default database directory is the parent directory of the last database you created.

  5. Select Finish.

For additional options and information on creating remote databases, see Configuring System-Wide Settings.

Defining Namespaces

To create a namespace that uses local databases:

  1. Log in to the Management Portal.

  2. Select System Administration > Configuration > System Configurations > Namespaces.

  3. Select Create New Namespace.

  4. Enter a Name for the namespace. Usually this is a short string containing alphanumeric characters; for rules, see Configuring Namespaces.

  5. For Select an existing database for Globals, select a database or select Create New Database.

    If you select Create New Database, the system prompts you with similar options as given in the create a database.

  6. For Select an existing database for Routines, select a database or select Create New Database.

    If you select Create New Database, the system prompts you with similar options as when you create a database.

  7. Select Save.

For additional options, see Configuring System-Wide Settings.

Mapping a Global

When you map a global to database ABC, you configure a given namespace so that InterSystems IRIS writes this global to and reads this global from the database ABC, which is not the default database for your namespace. When you define this global mapping, InterSystems IRIS does not move the global (if it already exists) to the designated database; instead the mapping instructs InterSystems IRIS where to read and write the global in the future.

To map a global:

  1. If the global already exists, move it to the desired database. See Moving Data from One Database to Another.

  2. Log in to the Management Portal.

  3. Select System Administration > Configuration > System Configurations > Namespaces.

  4. Select Global Mappings in the row for the namespace in which you want to define this mapping.

  5. Select New Global Mapping.

  6. For Global database location, select the database that should store this global.

  7. Enter the Global name (omitting the initial caret from the name). You can use the * character to choose multiple globals.

    The global does not have to exist when you map it (that is, it can be the name of a global you plan to create).

    Note:

    Typically you create mappings for data globals for persistent classes, because you want to store that data in non-default databases. Often you can guess the name of the data globals, but remember that InterSystems IRIS automatically uses a hashed form of the class name if the name is too long. It is worthwhile to check the storage definitions for those classes to make sure you have the exact names of the globals that they use. See Storage.

  8. Select OK.

  9. To save the mappings, select Save Changes.

For more information, see the System Administration Guide.

You can also define global mappings programmatically; see the Globals entry in the InterSystems Programming Tools Index.

The following shows an example global mapping, as seen in the Management Portal, which does not display the initial caret of global names:

generated description: global mapping example temp

This mapping means the following:

  • Within the namespace DEMONAMESPACE, if you set values of nodes of the global ^MyTempGlobal, you are writing data to the CACHETEMP database.

    This is true whether you set the nodes directly or indirectly (via object access or SQL).

  • Within the namespace DEMONAMESPACE, if you retrieve values from the global ^MyTempGlobal, you are reading data from the CACHETEMP database.

    This is true whether you retrieve the values nodes directly or indirectly (via object access or SQL).

Mapping a Routine

When you map a routine to database ABC, you configure a given namespace so that InterSystems IRIS finds this routine in the database ABC, which is not the default database for your namespace. When you define this routine mapping, InterSystems IRIS does not move the routine (if it already exists) to the designated database; instead the mapping instructs InterSystems IRIS where to find the routine in the future.

To map a routine:

  1. If the routine already exists, copy it to the desired database by exporting it and importing it.

  2. Log in to the Management Portal.

  3. Select System Administration > Configuration > System Configurations > Namespaces.

  4. Select Routine Mappings in the row for the namespace in which you want to define this mapping.

  5. Select New Routine Mapping.

  6. For Routine database location, select the database that should store this routine.

  7. Enter a value for Routine name. You can use the * character to choose multiple routines.

    Use the actual routine name; that is, do not include a caret (^) at the start.

    The routine does not have to exist when you map it (that is, it can be the name of a routine you plan to create).

  8. Select the Routine type.

  9. Select OK.

  10. Select OK.

  11. To save the mappings, select Save Changes.

For more information, see the System Administration Guide.

You can also define this kind of mapping programmatically. You can also define routine mappings programmatically; see the Routines entry in the InterSystems Programming Tools Index.

Important:

When you map one or more routines, be sure to identify all the code and data needed by those routines, and ensure that all that code and data is available in all the target namespaces. The mapped routines could depend on the following items:

  • Include files

  • Other routines

  • Classes

  • Tables

  • Globals

Use additional routine, package, and global mappings as needed to ensure that these items are available in the target namespaces.

Mapping a Package

When you map a package to database ABC, you configure a given namespace so that InterSystems IRIS finds the class definitions of this package in the database ABC, which is not the default database for your namespace. The mapping also applies to the generated routines associated with the class definitions; those routines are in the same package. This mapping does not affect the location of any stored data for persistent classes in these packages.

Also, when you define this package mapping, InterSystems IRIS does not move the package (if it already exists) to the designated database; instead the mapping instructs InterSystems IRIS where to find the package in the future.

To map a package:

  1. If the package already exists, copy the package to the desired database by exporting and importing the classes.

  2. Log in to the Management Portal.

  3. Select System Administration > Configuration > System Configurations > Namespaces.

  4. Select Package Mappings in the row for the namespace in which you want to define this mapping.

  5. Select New Package Mapping.

  6. For Package database location, select the database that should store this package.

  7. Enter a value for Package name.

    The package does not have to exist when you map it (that is, it can be the name of a package you plan to create).

  8. Select OK.

  9. Select OK.

  10. To save the mappings, select Save Changes.

For more information, see the System Administration Guide.

You can also define this kind of mapping programmatically. You can also define package mappings programmatically; see the Packages entry in the InterSystems Programming Tools Index.

Important:

When you map a package, be sure to identify all the code and data needed by the classes in that package, and ensure that all that code and data is available in all the target namespaces. The mapped classes could depend on the following items:

  • Include files

  • Routines

  • Other classes

  • Tables

  • Globals

Use additional routine, package, and global mappings as needed to ensure that these items are available in the target namespaces.

Generating Test Data

InterSystems IRIS includes a utility for creating pseudo-random test data for persistent classes. The creation of such data is known as data population, and the utility for doing this is known as the populate utility. This utility is especially helpful when testing how various parts of an application will function when working against a large set of data.

The populate utility consists of two classes: %Library.PopulateOpens in a new tab and %Library.PopulateUtilsOpens in a new tab. These classes provide methods that generate data of different typical forms. For example, one method generates random names:

 Write ##class(%Library.PopulateUtils).Name()

You can use the populate utility in two different ways.

Extending %Populate

In this approach, you do the following:

  1. Add %PopulateOpens in a new tab to the superclass list of your class.

  2. Optionally specify a value for the POPSPEC parameter of each property in the class.

    For the value of the parameter, specify a method that returns a value suitable for use as a property value.

    For example:

    Property SSN As %String(POPSPEC = "##class(MyApp.Utils).MakeSSN()");
  3. Write a utility method or routine that generates the data in the appropriate order: independent classes before dependent classes.

    In this code, to populate a class, execute the Populate() method of that class, which it inherits from the %PopulateOpens in a new tab superclass.

    This method generates instances of your class and saves them by calling the %Save() method, which ensures that each property is validated before saving.

    For each property, this method generates a value as follows:

    1. If the POPSPEC parameter is specified for that property, the system invokes that method and uses the value that it returns.

    2. Otherwise, if the property name is a name such as City, State, Name, or other predefined values, the system invokes a suitable method for the value. These values are hardcoded.

    3. Otherwise, the system generates a random string.

    For details on how the %PopulateOpens in a new tab class handles serial properties, collections, and so on, see Populate Utility.

  4. Invoke your utility method from the Terminal or possibly from any applicable startup code.

This is the general approach used for Sample.Person in the SAMPLES database.

Using Methods of %Populate and %PopulateUtils

The %PopulateOpens in a new tab and %PopulateUtilsOpens in a new tab classes provide methods that generate values of specific forms. You can invoke these methods directly, in the following alternative approach to data population:

  1. Write a utility method that generates the data in the appropriate order: independent classes before dependent classes.

    In this code, for each class, iterate a desired number of times. In each iteration:

    1. Create a new object.

    2. Set each property using a suitable random (or nearly random) value.

      To do so, use a method of %PopulateOpens in a new tab or %PopulateUtilsOpens in a new tab or use your own method.

    3. Save the object.

  2. Invoke your utility method from the Terminal.

This is the approach used for the two DeepSee samples in the SAMPLES database, contained in the DeepSee and HoleFoods packages.

Removing Stored Data

During the development process, it may be necessary to delete all existing test data for a class and then regenerate it (for example, if you have deleted the storage definition).

Here are two quick ways to delete stored data for a class (additional techniques are possible):

  • Call the following class method:

    ##class(%ExtentMgr.Util).DeleteExtent(classname)
    

    Where classname is the full package and class name.

  • Delete the globals in which the data for the class and the indexes for the class are stored. You may be more comfortable doing this through the Management Portal:

    1. Select System Explorer > Globals.

    2. Select Delete.

    3. On the left, select the namespace in which you are working.

    4. On the right, select the check box next to the data global and the index global.

    5. Select Delete.

      The system prompts to confirm that you want to delete these globals.

These options delete the data, but not the class definition. (Conversely, if you delete the class definition, that does not delete the data.)

Resetting Storage

Important:

It is important to be able to reset storage during development, but you never do this on a live system.

The action of resetting storage for a class changes the way that the class accesses its stored data. If you have stored data for the class, and if you have removed, added, or changed property definitions, and you then reset storage, you might not be able to access the stored data correctly. So if you reset storage, you should also delete all existing data for the class and regenerate or reload it, as appropriate.

To reset storage for a class in your IDE:

  1. Display the class.

  2. Scroll to the end of the class definition.

  3. Select the entire storage definition, starting with <Storage name= and ending with </Storage>. Delete the selection.

  4. Save and recompile the class.

Browsing a Table

To browse a table, do the following in the Management Portal:

  1. Select System Explorer > SQL.

  2. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

  3. Optionally select an SQL schema from the Schema drop-down list. This list includes all SQL schemas in this namespace. Each schema corresponds to a top-level class package.

  4. Expand the Tables folder to see all the tables in this schema. For example:

    generated description: smp sql browse samples

  5. Select the name of the table. The right area then displays information about the table.

  6. Select Open Table.

    The system then displays the first 100 rows of this table. For example:

    generated description: smp sql browse sampleperson

    Note the following points:

    • The values shown here are the display values, not the logical values as stored on disk.

    • The first column (#) is the row number in the display.

    • The second column (ID) is the unique identifier for a row in this table; this is the identifier to use when opening objects of this class. (In this class, these identifiers are integers, but that is not always true.)

      These numbers happen to be the same in this case because this table is freshly populated each time the SAMPLES database is built. In a real application, it is possible that some records have been deleted, so that there are gaps in the ID values and the numbers here do not match the row numbers.

Executing an SQL Query

To run an SQL query, do the following in the Management Portal:

  1. Select System Explorer > SQL.

  2. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

  3. Select Execute Query.

  4. Type an SQL query into the input box. For example:

    select * from sample.person
    
  5. For the drop-down list, select Display Mode, Logical Mode, or ODBC Mode.

    This controls how the user interface displays the results.

  6. Then select Execute. Then the Portal displays the results. For example:

    generated description: smp sql query logical

Examining Object Properties

Sometimes the easiest way to see the value of a particular property is to open the object and write the property in the Terminal:

  1. If the Terminal prompt is not the name of the namespace you want, then type the following and press return:

    ZN "namespace"
    

    Where namespace is the desired namespace.

  2. Enter a command like the following to open an instance of this class:

    set object=##class(package.class).%OpenId(ID)
    

    Where package.class is the package and class, and ID is the ID of a stored object in the class.

  3. Display the value of a property as follows:

    write object.propname
    

    Where propname is the property whose value you want to see.

Viewing Globals

To view globals in general, you can use the ObjectScript ZWRITE command or the Globals page in the Management Portal. If you are looking for the global that stores the data for a class, it is useful to first check the class definition to make sure you know the global to view.

  1. If you are looking for the data global for a specific class and you are not sure which global stores the data for the class:

    1. In your IDE, display the class.

    2. Scroll to the end of the class definition.

    3. Find the <DefaultData> element. The value between <DefaultData> and </DefaultData> is the name of the global that stores data for this class.

      InterSystems IRIS uses a simple naming convention to determine the names of these globals; see Globals Used by a Persistent Class. However, global names are limited to 31 characters (excluding the initial caret), so if the complete class name is long, the system automatically uses a hashed form of the class name instead.

  2. In the Management Portal, select System Explorer > Globals.

  3. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

    The Portal displays a list of the globals available in this namespace (notice that this display omits the initial caret of each name). For example:

    generated description: smp globals

    Usually most non-system globals store data for persistent classes, which means that unless you display system globals, most globals will have familiar names.

  4. Select View in the row for the global in which you are interested.

    The system then displays the first 100 nodes of this global. For example:

    generated description: smp global sampleperson

  5. To restrict the display to the object in which you are interested, append (ID) to the end of the global name in the Global Search Mask field, using the ID of the object. For example:

    ^Sample.PersonD(45)
    

    Then press Display.

As noted earlier, you can also use the ZWRITE command, which you can abbreviate to ZW. Enter a command like the following in the Terminal:

 zw ^Sample.PersonD(45)

Testing a Query and Viewing a Query Plan

In the Management Portal, you can test a query that your code will run. Here you can also view the query plan, which gives you information about how the Query Optimizer will execute the query. You can use this information to determine whether you should add indexes to the classes or write the query in a different way.

To view a query plan, do the following in the Management Portal:

  1. Select System Explorer > SQL.

  2. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

  3. Select Execute Query.

  4. Type an SQL query into the input box. For example:

    select * from sample.person
    
  5. For the drop-down list, select Display Mode, Logical Mode, or ODBC Mode.

    This controls how the user interface displays the results.

  6. To test the query, select Execute.

  7. To see the query plan, select Show Plan.

Viewing the Query Cache

For InterSystems SQL (except when used as embedded SQL), the system generates reusable code to access the data and places this code in the query cache. (For embedded SQL, the system generates reusable code as well, but this is contained within the generated INT code.)

When you first execute an SQL statement, InterSystems IRIS optimizes the query and then generates and stores code that retrieves the data. It stores the code in the query cache, along with the optimized query text. Note that this cache is a cache of OBJ code, not of data.

Later when you execute an SQL statement, InterSystems IRIS optimizes it and then compares the text of that query to the items in the query cache. If InterSystems IRIS finds a stored query that matches the given one (apart from minor differences such as whitespace), it uses the code stored for that query.

The Management Portal groups the items in the query cache by schema. To view the query cache for a given schema, do the following in the Management Portal:

  1. Select System Explorer > SQL.

  2. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

  3. Expand the Cached Queries folder.

  4. Select the Tables ulink in the row for the schema.

  5. At the top of the page, select Cached Queries.

    The Portal displays something like this:

    generated description: smp cached queries

    Each item in the list is OBJ code.

By default, InterSystems IRIS does not save the routine and INT code that it generates as a precursor to this OBJ code. You can force InterSystems IRIS to save this generated code as well. See Settings for InterSystems SQL.

You can purge cached queries (which forces InterSystems IRIS to regenerate this code). To purge cached queries, use Actions > Purge Cached Queries.

Building an Index

For InterSystems IRIS classes, indexes do not require any maintenance, with one exception: if you add an index after you already have stored records for the class, you must build the index.

To do so:

  1. Select System Explorer > SQL.

  2. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

  3. In the left area, select the table.

  4. Select Actions > Rebuild Indices.

Using the Tune Table Facility

When the Query Optimizer decides the most efficient way to execute a specific SQL query, it considers, among other factors, the following items:

  • How many records are in the tables

  • For the columns used by the query, how nearly unique those columns are

This information is available only if you have run the Tune Table facility with the given table or tables. This facility calculates this data and stores it with the storage definition for the class, as the <ExtentSize> value for the class and the <Selectivity> values for the stored properties.

To use the Tune Table facility:

  1. Select System Explorer > SQL.

  2. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

  3. In the left area, select the table.

  4. Select Actions > Tune Table.

For <Selectivity> values, it is not necessary to do this again unless the data changes in character. For <ExtentSize>, it is not important to have an exact number. This value is used to compare the relative costs of scanning over different tables; the most important thing is to make sure that the relative values of ExtentSize between tables are correct (that is, small tables should have a small value and large tables a large one).

Moving Data from One Database to Another

If you need to move data from one database to another, do the following:

  1. Identify the globals that contain the data and its indexes.

    If you are not certain which globals a class uses, check its storage definition. See Storage.

  2. Export those globals. To do so:

    1. In the Management Portal, select System Explorer > Globals.

    2. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

    3. Select the globals to export.

    4. Select Export.

    5. Specify the file into which you wish to export the globals. Either enter a file name (including its absolute or relative pathname) in the field or select Browse and navigate to the file.

    6. Select Export.

    The globals are exported to a file whose extensions is .gof.

  3. Import those globals into the other namespace. To do so:

    1. In the Management Portal, select System Explorer > Globals.

    2. If needed, select the name of the current namespace displayed in the header area to select the namespace in which you are interested.

    3. Select Import.

    4. Specify the import file. Either enter the file name or select Browse and navigate to the file.

    5. Select Next to view the contents of the file. The system displays a table of information about the globals in the specified file: the name of each global, whether or not it exists in the local namespace or database, and, if it does exist, when it was last modified.

    6. Choose those globals to import using the check boxes in the table.

    7. Select Import.

  4. Go back to the first database and delete the globals, as described in Removing Stored Data.

FeedbackOpens in a new tab