Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
CapStorm applications connect to Salesforce using several supported OAuth login types. This section covers the available options:
Each flow offers a different approach to authentication depending on how your Salesforce org is configured.
CaseMilestone is an example of a Salesforce table that contains formula columns whose values may change even when other fields of a CaseMilestone record do not change. In fact, the CaseMilestone table contains both types of Salesforce formula columns difficult to include in an incremental backup:
A formula field whose value changes when the value in another record (in the same table or a different table) changes.
A formula field whose value is computed using the current date or time.
To identify Salesforce formulas in a Salesforce standard table look for non-reference field columns where the API does not have update access. Knowing whether a formula field value will change even when the corresponding fields in the record do not change is a bit more difficult.
The solution to this problem is to periodically run the CopyStorm/Medic Refresh Columns tool to bring the problem formula columns back in sync with Salesforce.
The following table lists Salesforce defined formula fields that are known to have the issue described above:
To connect to Salesforce using the OAUTH CLIENT CREDENTIALS flow, CopyStorm can be configured with:
The OAuth Client ID
The OAuth Client Secret
OAuth Client Credentials can be enabled in Salesforce by following this tutorial.
OAuth Client Credential logins can be enabled in CopyStorm by navigating to the Advanced Parameters dialog on the Main tab:
After selecting the OAuth 2.0 Client Credentials login type, provide the credentials needed to authenticate with Salesforce:
To connect to Salesforce using the OAUTH CLIENT CREDENTIALS flow, CopyStorm can be configured with:
OAuth Client ID
OAuth Client Secret
Username
Password
OAuth Client Credentials can be enabled in Salesforce by following .
OAuth Client Credential logins can be enabled in CopyStorm by navigating to the Advanced Parameters dialog on the Main tab:
After selecting the OAuth 2.0 Username-Password login type, provide the credentials needed to authenticate with Salesforce:
When connecting to S3, by default, CapStorm applications will:
Read Permanent Credentials provided using the AWS Provider Chain
Use these credentials to request temporary session credentials via the AWS STS (Security Token Service).
Periodically refresh the temporary credentials for continued access.
This approach minimizes the use of permanent credentials by keeping them off the wire during ongoing operations.
Note: For CopyStorm versions 10.56.6 and higher, Java memory parameters can be provided without modifying the CopyStorm start script. For more details, please see .
CopyStorm uses the default settings for Java heap space. Most of the times this works well, but if you are seeing an Out of Memory error referencing Java Heap Space you may need to increase the memory allowance for CopyStorm. Settings can be adjusted as described in the “CopyStorm.bat” file, but the exact settings will depend on the size needed for the data in your Salesforce instance.
The most common reason to adjust the default memory settings is that a large content item (usually an Attachment, Document, or ContentVersion) is too large to fit in available CopyStorm memory. CopyStorm requires 3 to 4 times the size of the largest content item. Here are the steps to find the largest content items in your Salesforce:
In the management menu found by clicking on your name in the upper right-hand corner, go to:
Setup -> Data Management -> Storage Usage -> Overall Top Files by Storage Utilization
Though CopyStorm keeps a data in sync with Salesforce, there are a few cases where the data can become out of sync:
A new column is created and populated in Salesforce, but the Salesforce credentials used by CopyStorm cannot see the column.
When permissions are changed and CopyStorm can see the column, any data populated prior to CopyStorm having visibility will be null and the data will need to be propagated.
A column contains a formula whose value changes without the timestamp on the row changing.
By default, CopyStorm will use the Salesforce REST API for Attachments and other tables which contain BASE64 columns. REST is used by default because it minimizes the amount of memory needed by CopyStorm (See the technical details section at the end of this document is you are interested in the details).
If using the REST API is a problem then a simple CopyStorm configuration file change can force the SOAP API to be used instead. The primary need we have seen for this is when a local virus checker or network filter is blocking attachment downloads from Salesforce.
Open the file [CopyStorm]/config/TableRuleRegistry.xml and change:
<TableRule name="Attachment" predicate="bodyLength<800000000" />
to
<TableRule name="Attachment" predicate="bodyLength<800000000" useRestAPI="false"/>
Alternatively, if you are using a custom directory of CopyStorm configuration files, simply add the following rule to your private TableRuleRegistry.xml file.
<TableRule name="Attachment" useRestAPI="false"/>
Since Salesforce SOAP API returns an entire attachment in a single response, the amount of memory required to parse the response and send the attachment to a target database can be huge (for huge attachments). The Salesforce REST API can be used to avoid loading an entire attachment into memory. Here is why:
The REST API returns an attachment BODY as a hyperlink.
CopyStorm downloads the hyperlink to a temporary file (taking very little memory).
The temporary file is loaded directly into the target database without ever being loaded into CopyStorm memory. No all database support this feature but those that do minimize CopyStorm memory usage.
There are a handful of tables where CopyStorm uses database views rather than tables. A good example is ActivityHistory (a view combining the Task and Event tables). If Salesforce makes a change which alters the type of length of a column in a table and the column is used in an existing view, PostgreSQL will throw an error like the following when CopyStorm tries to make the change in the database.
org.postgresql.util.PSQLException: ERROR: cannot alter type of a column used by a view or rule Detail: rule _RETURN on view openactivity depends on column “status”
The process to fix the issue is to:
Drop the views that depend on the table that needs modification
Yes you can — CopyStorm supports log4j2. This article contains the instructions you will need.
CopyStorm comes packaged with log4j2 — configuring configuring CopyStorm to use it is a two-step process:
Select the “Use Apache Logging” option on the configuration section of CopyStorm’s Configuration tab.
When checked, CopyStorm will use the Apache Commons Logging system rather than the default.
All programming languages, databases, and most applications have limits on the maximum size of values they can store or manipulate. For example, Salesforce has a 2 GB limit the size of an uploaded file, and PostgreSQL has a 1 GB limit on the size of a column value.
When CopyStorm downloads large files from Salesforce, CopyStorm streams the Base64-encoded file body to the file system (which has no size limits other than available disk space). Without using CopyStorm’s Base64 Chunking feature the Base64-encoded file body will be written directly to the database, subject to the size limitations (e.g. 1 GB in PostgreSQL).
The CopyStorm Base64 Chunking feature allows large files to be broken apart into chunks, storing these chunks in a separate table named CopyForceTableFieldChunk. By default, files will be broken into 100 MB chunks – but this is configurable. For example, if the Body field of a ContentVersion record is 500 MB, and the Base64 Chunking feature is enabled, then the 500 MB file will be broken into 5 parts that are stored as 5 separate entries in the CopyForceTableFieldChunk table.
With Base64 Chunking enabled, there are no practical database storage limits to the size of field values in SalesForce objects that can be brought into the CopyStorm database, and CopyStorm is not subject to the maximum size limitations of the database.
The Base64 Chunking feature is disabled by default when CopyStorm is initially configured – to enable this feature, check the
CaseMilestone
IsViolated
ElapsedTimeIn.*
Client ID
The unique identifier issued by Salesforce when you register a connected app. Required for all OAuth flows to identify the requesting application.
Client Secret
A confidential key generated by Salesforce for your connected app. Used alongside the Client ID to authenticate the application during OAuth flows.


Password
The Salesforce password for the specified user. Note: If your org requires it, append the user’s security token directly to the end of the password, with no spaces.
Client ID
The unique identifier issued by Salesforce when you register a connected app. Required for all OAuth flows to identify the requesting application.
Client Secret
A confidential key generated by Salesforce for your connected app. Used alongside the Client ID to authenticate the application during OAuth flows.
Username


The Salesforce username (email address) of the user the application will authenticate as. This must match a valid, active user in the connected Salesforce org.
Increase the amount of heap space available by setting the JVM_ARGS parameter as showing in the CopyStorm.bat file. This file can be edited.
The following example sets the min and max memory allocations to 300 and 1000 megabytes, respectively: set JVM_ARGS=-Xms300m -Xmx1000m
Use a 64-bit Java JRE if possible.
Increase the amount of heap space by modifying the last line of the CopyStorm.sh script, adding memory allocation rules immediately after the “$JAVA”.
The following example sets the min and max memory allocations to 300 and 1000 megabytes, respectively: “$JAVA” -Xms300m -Xmx1000m -cp (… see the file for the rest of the command)
When this checkbox is:
Unchecked, then Base64 field values are always stored in-line in the primary CopyStorm data tables.
Checked, then Base64 field values that are larger than the chunk size will be stored in the CopyForceTableFieldChunk table.
In this case, a pointer value will be stored in the primary CopyStorm data table.
The pointer is the string representation of a JSON object containing field metadata. For example:
All chunked values will be prefixed with the value “#AAA:”. Inlined Base64 values will never begin with this value because the “#” character is not valid in Base64 strings.
All of the Base64 chunking information within this page also applies to CopyStorm Snapshots, with two differences:
CopyStorm Snapshots store Base64 values in a secondary chunked data table named CopyForceArchiveFieldChunk.
CopyStorm Snapshots will always chunk Base64 values, regardless of whether Base64 chunking is enabled in the primary CopyStorm database.
To override the system default chunk size, create a Base64ChunkParameters.xml file and place it in the [CopyStorm]/config/ directory. This file is used to provide the chunk size to CopyStorm. In the example below, the default chunk size has been changed to 5 MB (5000000):
All chunks created after updating this file will be created using the newly provided chunk size.
CopyStorm will automatically delete records from the CopyForceTableFieldChunk table as parent records are deleted from the primary CopyStorm data tables. If the CopyStorm tables are truncated, or if records are deleted from the CopyStorm tables without CopyStorm performing the deletions, then the CopyStorm/Medic Delete Orphaned Base64 Chunks tool can be used to scan for and delete any CopyForceTableFieldChunk records that point to records that are no longer present in the primary CopyStorm data tables.
Snapshot chunked records contained in the CopyForceArchiveFieldChunk table will be automatically cascade-deleted when their parent records are deleted.
This article describes how to configure CapStorm applications to connect to S3 using permanent credentials directly.
To configure CopyStorm to use permanent AWS credentials when communicating with S3:
Create an XML file called CapStormAWSCredentialsProvider.xml
Place the XML file in the config directory of the CopyStorm base installation.
Note: If External Configuration is being used, this file can instead be placed in the designated External Configuration location.
An example CapStormAWSCredentialsProvider.xmldisabling temporary credentials is shown below:
#AAA:{
"numChunks": "5",
"chunkSize": "100000000",
"contentSize": "500000000",
"salesforceId": "0686300000190d9AAA",
"hash": "bcfc403cba99fda2224395a843d9397b"
}<Base64ChunkParameters>
<DataSourceType name="SQLServer" chunkSize="5000000" />
<DataSourceType name="Oracle" chunkSize="5000000" />
<DataSourceType name="MySQL" chunkSize="5000000" />
<DataSourceType name="H2" chunkSize="5000000" />
<DataSourceType name="PostgreSQL" chunkSize="5000000" />
<DataSourceType name="RedShift" chunkSize="5000000" />
<DataSourceType name="Snowflake" chunkSize="5000000" />
<DataSourceType name="Unknown" chunkSize="5000000" />
</Base64ChunkParameters><CapStormAWSCredentialProvider>
<EnableSessionToken value="false"/>
</CapStormAWSCredentialProvider>If you know the specific columns that need to be updated, the fastest approach is to use the CopyStorm/Medic RefreshColumns tool. However, if you are not sure which columns are out of sync or if you want to check all columns, the fastest approach is to use CopyStorm.
The fundamental operation that needs to be performed is to force CopyStorm to scan a specific range of records and update columns in the target database, even if the timestamps in CopyStorm and Salesforce are the same. This can be done by modifying your existing CopyStorm job for a one-time run using the following parameters:
Verify that the “Optimize Update SQL” option is checked (it is by default).
When this option is checked columns whose values differ between CopyStorm and Salesforce will be updated in the database.
Enable the “Force Updates” option.
When this option is checked, CopyStorm will do a field-by-field comparison between CopyStorm and Salesforce records even when the two timestamps match.
Enter a date into the Modified Since parameter that is earlier in time than when the data sync problem is believe to have occurred.
For example, if a new column was introduced on 16-Mar-2017 and permissions were fixed on 21-Mar-2017 then only records modified after 15-Mar-2017 need to be scanned.
Now run CopyStorm — any fields that do not match will be updated and matching fields will be left untouched.
Do not save changes to your CopyStorm configuration file.
This example will scan all records in nearly all tables and fix any data mismatches:
Run CopyStorm — it will make the table modification and automatically recreate the views.
In Summer’20 Salesforce increased then length of the column Task.Status. Since the Task.Status column is used in CopyStorm views the update to Task.Status failed with:
org.postgresql.util.PSQLException: ERROR: cannot alter type of a column used by a view or rule Detail: rule _RETURN on view openactivity depends on column “status”
Here are the steps to fix this problem.
The next time CopyStorm runs it will:
Successfully ALTER the Task.Status column because the dependent views no longer exist.
Recreate the views after detecting they have been deleted.



When CopyStorm adds a new column to an existing database table or indexes a new column the operation may have timeout issues if the table has a large number rows. This article describes how to solve this problem by increasing the amount of time CopyStorm will wait for a DDL operation to complete.
The parameter that controls how long CopyStorm will wait for an ALTER TABLE ADD/ALTER COLUMN, CREATE INDEX, or any other DDL type operation is kept in the section of the Configuration tab.
The default DDL Timeout Parameter is 3600 seconds so set the value to a much larger value.

This article provides information on how to capture CopyStorm job execution log data that is output via Standard Error/Out in a text file. This approach is useful for doing advanced troubleshooting in order to capture error symptoms that may not appear within the application GUI or within the logged exceptions of the job history entry found on the “History” tab.
The general approach is as follows:
Open a headless CopyStorm script for editing.
This is the script that is scheduled using CRON or Windows Task Scheduler, and is created using the “Batch File” tab of CopyStorm.
Create a directory that will be used to save the application logs.
Edit the batch script to create a log file with the appropriate name in the established directory and write all job execution output to the file.
Here is an unedited example of a Windows batch script generated by CopyStorm. This script will be modified to output CopyStorm job logs to a file:
The following code is added after the line that begins with “SET CopyStormConfigFile”
This code sets a local script variable that establishes the path to the directory where the log files will be stored.
The “C:\Capstorm\CopyStormLogs” path should point to your desired CopyStorm log directory path.
Next, the second to last line (starting with “CALL %CopyStormCmd%”) will need to be modified to write to the logfile. The final line will look like this:
This code creates a logfile and redirects stderr and stdout to the file, capturing all job execution logs.
The “CopyStorm_Log_” prefix is used to identify the type of logfile – if you have multiple scheduled jobs, it is best practice to use a different prefix for each scheduled job. For example, “CopyStorm_Hourly_Data_” and “CopyStorm_Daily_Metadata_” if there is an hourly job for data and a separate daily job for metadata.
The example above will create log files with names like:
CopyStorm_Log_2023-02-21T19-45-32.txt
Here is an edited version of the batch script shown above:
Here is an unedited example of a Linux sh script generated by CopyStorm. This script will be modified to output CopyStorm job logs to a file:
The following code is added after the line that begins with “CopyStormConfigFile=”
This code sets a local script variable that establishes the path to the directory where the log files will be stored.
The “/opt/Capstorm/CopyStormLogs” path should point to your desired CopyStorm log directory path.
Next, the second to last line (starting with “sh $CopyStormRootDir”) will need to be modified to write to the logfile. The final line will look like this:
This code creates a logfile and redirects stderr and stdout to the file, capturing all job execution logs.
The “CopyStorm_Log_” prefix is used to identify the type of logfile – if you have multiple scheduled jobs, it is best practice to use a different prefix for each scheduled job. For example, “CopyStorm_Hourly_Data_” and “CopyStorm_Daily_Metadata_” if there is an hourly job for data and a separate daily job for metadata.
The example above will create log files with names like:
CopyStorm_Log_2023-02-21T19:45:32.txt
Here is an edited version of the batch script shown above:
Since CopyStorm keeps a copy of Salesforce metadata in local database tables it is a fairly trivial task to compare metadata from multiple CopyStorm backups.
The key CopyStorm tables required to perform table and field comparisons are CopyForceTable and CopyForceTableField. These are the tables CopyStorm uses to keep the CopyStorm database structure in sync with Salesforce. Rather than bore you with details, download the following SQL script for an example of how to exhaustively search for table and field differences.
This solution compares elements like Apex Classes, Page Layouts, Settings, etc. from two difference CopyStorm backups. The key table in CopyStorm is SFMetaFileProperties since this table contains the most recently backed version of each metadata type. Note that the companion table, SFMetaFilePropertiesHistory, contains historical values for each metadata type. Download the following script for an example of how to exhaustively compare metadata.
There are a number of Salesforce quirks that make creating incremental backup software more difficult than a person might expect. The content of this article will help you understand some of the quirks and give you information that makes you happy that Capstorm backs up Salesforce for you. Note, the text may look familiar to an article published originally on — that’s OK since the blogspot author is one of the founders of Capstorm.
This article is not about how to be a better SOQL programmer. It is about pitfalls in SOQL that are obscure and often difficult to diagnose and understand when encountered.
The SOQL WHERE clause cannot be trusted.
The SOQL LIMIT parameter is not always optional.
SQL/Server 2016 and later will sometimes complain about adding or altering table columns with a error like:
SQLServerException: Cannot create a row of size 8063 which is greater than the allowable maximum row size of 8060
If you do not understand what this means then google the message. To fix this issue keep reading.
The simplest fix is to drop the table and let CopyStorm rebuild it automatically during the next backup. SQL/Server will examine the columns in the CREATE TABLE statement and avoid the problem.
The technique for fixing a table without rebuilding it involves converting the longest NVARCHAR(n) columns to NVARCHAR(MAX). This will cause a SQL/Serve table to have a bit more row space for each column that is converted and thus allow the addition of new columns.
If you want to perform the fix by hand, here are the specific steps:
If your CopyStorm database was created before Database Views were introduced then are likely many database tables in your backup that could be represented as database views instead. For safety, CopyStorm will not convert an existing table to a view UNLESS you follow the instructions in this article.
The technique to force CopyStorm to switch to a database view for a table is simple:
Manually drop the table in the CopyStorm database that should be a view. The next time CopyStorm runs it will create the view.
For example:
DROP TABLE AccountFeed
ALTER a few of the longer NVARCHAR2 columns to be NVARCHAR2(MAX)
DBCC CLEANTABLE (databaseName, ‘TableName’, 0 )
ALTER TABLE tableName REBUILD
If you would prefer a computer to do the analysis for you and generate a script that will fix the problem then:
Paste the following script into SQL Server Management Studio
Change the values for @catalog, @schema, @column, and @cutoff to match the table your want to fix.
Run the script
Take the output of the script and paste into a new SQL Server Management Studio window and run it.
— — Find all NVARCHAR columns longer than a specified cutoff and generate a script that changes them to NVARCHAR(MAX) — — This can be helpful if an alter to a table is causing the table to exceed the maximum page size. — — Note: those code generates a script that would make the column changes — it does not make the changes — BEGIN DECLARE @catalog VARCHAR(128) DECLARE @schema VARCHAR(128) DECLARE @table VARCHAR(128) DECLARE @column VARCHAR(128) DECLARE @cutoff INTEGER DECLARE @sql VARCHAR(MAX)
SELECT @catalog = ‘gsmithfarmer’ — look in this database SELECT @schema = ‘dbo’ — look in this schema SELECT @table = ‘account’ — change columns in this table. SELECT @cutoff = 200 — ALTER NVARCHAR columns that are longer than this to NVARCHAR(MAX)
DECLARE @candidates TABLE (table_catalog VARCHAR(128), table_schema VARCHAR(128), table_name VARCHAR(128), column_name VARCHAR(128), character_maximum_length INTEGER );
INSERT INTO @candidates(table_catalog, table_schema, table_name, column_name, character_maximum_length ) SELECT table_catalog, table_schema, table_name, column_name, character_maximum_length FROM INFORMATION_SCHEMA.columns WHERE TABLE_CATALOG=@catalog AND TABLE_SCHEMA=@schema AND TABLE_NAME=@table AND DATA_TYPE=’nvarchar’ AND CHARACTER_MAXIMUM_LENGTH>@cutoff
;
DECLARE candCursor CURSOR FOR SELECT table_catalog, table_schema, table_name, column_name FROM @candidates ORDER BY character_maximum_length DESC ;
OPEN candCursor FETCH NEXT FROM candCursor INTO @catalog, @schema, @table, @column WHILE @@FETCH_STATUS=0 BEGIN SET @sql = ‘ALTER TABLE ‘ + @catalog + ‘.’ + @schema + ‘.’ + @table + ‘ ALTER COLUMN ‘ + @column + ‘ NVARCHAR(MAX) NULL;’
PRINT @sql FETCH NEXT FROM candCursor INTO @catalog, @schema, @table, @column END CLOSE candCursor DEALLOCATE candCursor PRINT ‘DBCC CLEANTABLE (‘ + @catalog + ‘,’ + @table + ‘,0)’ PRINT ‘ALTER TABLE ‘ + @catalog + ‘.’ + @schema + ‘.’ + @table + ‘ REBUILD;’
END
DROP TABLE ActivityHistory
will cause CopyStorm to recreate AccountFeed and ActivityHistory to views the next time CopyStorm runs.
The CopyStorm/Medic Table Editor tool provides a simple GUI for dropping tables from a CopyStorm database.
Go to the documentation for the CopyStorm/Medic Table Editor
All tables ending with Feed. Examples:
AccountFeed
MyCustomObject__Feed
ActivityHistory
AccountUserTerritory2View
You do not need to change any of this code, just copy and paste it directly.
You do not need to change any of this code, just copy and paste it directly.
@ECHO OFF
REM
REM This script runs CopyStorm and relies on the notification system built into CopyStorm
REM to report the success/failure of a job. Log file information is written to stdout
REM in addition to the logging tables in the CopyStorm database.
REM
REM CopyStormRootDir - the directory in which CopyStorm is installed.
REM CopyStormConfigFile -- the name of the CopyStorm configuration file to run.
SET CopyStormRootDir=C:\Capstorm\CopyStorm
SET CopyStormConfigFile=C:\Capstorm\CapstormConfig\config.copyStorm
SET CopyStormCmd="%CopyStormRootDir%\CopyStorm.bat" -run "%CopyStormConfigFile%"
CALL %CopyStormCmd% 2>&1
EXIT /B %ERRORLEVEL%SET LOGDIR=C:\Capstorm\CopyStormLogsSET TIMESTAMP=%date:~10,4%-%date:~7,2%-%date:~4,2%T%TIME::=-%
SET TIMESTAMP=%TIMESTAMP: =0%CALL %CopyStormCmd% >> %LOGDIR%\CopyStorm_Log_%TIMESTAMP%.txt 2>&1
@ECHO OFF
REM
REM This script runs CopyStorm and relies on the notification system built into CopyStorm
REM to report the success/failure of a job. Log file information is written to stdout
REM in addition to the logging tables in the CopyStorm database.
REM
REM CopyStormRootDir - the directory in which CopyStorm is installed.
REM CopyStormConfigFile -- the name of the CopyStorm configuration file to run.
SET CopyStormRootDir=C:\Capstorm\CopyStorm
SET CopyStormConfigFile=C:\Capstorm\CapstormConfig\config.copyStorm
SET LOGDIR=C:\Capstorm\CopyStormLogs
SET TIMESTAMP=%date:~10,4%-%date:~7,2%-%date:~4,2%T%TIME::=-%
SET TIMESTAMP=%TIMESTAMP: =0%
SET CopyStormCmd="%CopyStormRootDir%\CopyStorm.bat" -run "%CopyStormConfigFile%"
CALL %CopyStormCmd% >> %LOGDIR%\CopyStorm_Log_%TIMESTAMP%.txt 2>&1
EXIT /B %ERRORLEVEL%
#!/bin/sh
#############################################################################
# This script runs CopyStorm and relies on the notification system built into CopyStorm
# to report the success/failure of a job. Log file information is written to stdout
# in addition to the logging tables in the CopyStorm database.
#
# CopyStormRootDir - the directory in which CopyStorm is installed.
# CopyStormConfigFile -- the name of the CopyStorm configuration file to run.
#
#############################################################################
CopyStormRootDir="/opt/Capstorm/CopyStorm"
CopyStormConfigFile="/opt/Capstorm/CopyStormConfig/configFile.copyStorm"
sh $CopyStormRootDir/CopyStorm.sh -run $CopyStormConfigFile 2>&1
exit $?
LOGDIR="/opt/Capstorm/CopyStormLogs"TIMESTAMP=$(date +"%Y-%m-%dT%H:%M:%S")
sh $CopyStormRootDir/CopyStorm.sh -run $CopyStormConfigFile >> "$LOGDIR/CopyStorm_Log_$TIMESTAMP.txt" 2>&1#!/bin/sh
#############################################################################
# This script runs CopyStorm and relies on the notification system built into CopyStorm
# to report the success/failure of a job. Log file information is written to stdout
# in addition to the logging tables in the CopyStorm database.
#
# CopyStormRootDir - the directory in which CopyStorm is installed.
# CopyStormConfigFile -- the name of the CopyStorm configuration file to run.
#
#############################################################################
CopyStormRootDir="/opt/Capstorm/CopyStorm"
CopyStormConfigFile="/opt/Capstorm/CopyStormConfig/configFile.copyStorm"
LOGDIR="/opt/Capstorm/CopyStormLogs/"
TIMESTAMP=$(date +"%Y-%m-%dT%H:%M:%S")
sh $CopyStormRootDir/CopyStorm.sh -run $CopyStormConfigFile >> "$LOGDIR/CopyStorm_Log_$TIMESTAMP.txt" 2>&1
exit $?Timestamps returned by SOQL believe in time travel.
SOQL can return field data that is invalid based on the field definition.
SOQL has a love/hate relationship with tables containing lots of custom fields.
SOQL does not treat all table equally – not knowing the exceptions can take down your org.
SOQL chokes on tables with lots of functional columns.
Here is a trick question. Will the following SOQL statement return any records that were modified today?
SELECT id, name FROM Account WHERE systemModStamp < LAST_YEAR
The answer is……usually not. However it will return a record modified today when:
The record fit the WHERE criteria when the record set to return was determined.
The record is modified before it was fetched from Salesforce.
This “sin” is easy to reproduce with a Python script and a web browser.
In the web browser open the Salesforce GUI on the record that will be the most recent one to match the LAST_YEAR criteria.
Start a Python script that fetches records using:
SELECT id,name,systemModStamp FROM Account WHERE systemModStamp < LAST_YEAR ORDER BY systemModStamp ASC
Modify the record in the Salesforce GUI after the Python script starts fetching records.
One of the last records you read from Salesforce will have a modification date of today
Though the SOQL documentation says that the LIMIT parameter is optional there are a handful of Salesforce tables where it is nearly impossible to run a large query without the dreaded Query Timeout error. If you are not a believer then try running these queries on a mature Salesforce instance.
SELECT id, accountId, description FROM Task ORDER BY SystemModStamp ASC
SELECT application,browser,loginTime FROM LoginHistory ORDER BY loginTime ASC
Short of begging Salesforce for a max timeout value longer than the default, a solution has to “know” good limit values for problem tables. Here are good values for a handful of the more troublesome table.
Table Name (or name pattern)
Good LIMIT Value
.*History
5000
.*History__c
5000
.*Feed
Here’s another SOQL quiz. In the following code snippet, is it possible for the Exception to be thrown? For the quiz assume that all Account records have unique timestamp values and no records are deleted.
Account accts1[] = [SELECT id, systemmodstamp FROM Account ORDER BY systemmodstamp ASC;
Account maxAcct = accts1[acct1.size() – 1]
Account accts2[] = [SELECT id, systemmodstamp FROM Account WHERE systemmodstamp <=:maxAcct.systemmodstamp ORDER BY systemmodstamp ASC;
if( accts2.size() > accts2.size()) {
throw new Exception(‘Timewarp – new account created in the past!’);
}
The answer….usually no. However, Salesforce does not guarantee that records are committed in timestamp order.
It is possible for a record with a SystemModStamp of 2014-12-31T00:12:12.000Z to be committed to Salesforce after a record in the same table with a SystemModStamp of 2014-12-31T00:13:12.000Z.
This is a hard “sin” to reproduce because it depends on the current load of the Salesforce servers. We discovered the problem by monitoring a high volume production instance for three weeks – the problem occurred just a couple of times during this period. It was sort of like searching for a Higgs particle.
The moral: Do not assume that the MAX(SystemModStamp) or MAX(LastModifiedDate) value is a good constraint to find all values that are older.
The solution: Do not rely on timestamps that are fresh. Give Salesforce a little while to commit all recent transactions. In practice this odd state seems to settle out on Salesforce servers after 10-120 seconds.
This quiz should be easy for experienced SOQL users.
Is it possible for an invalid email address to be stored and returned in a Salesforce Email field?
Is is possible to store a 132 character string in a 128 character Salesforce field?
The answer to #1 is, of course, possible. Check out contact Ms. Barbara Levy in any developer force instance. Her email is: b.levy@expressl&t.net Try saving the record and Salesforce will tell you that the email format is invalid (using the API will throw the same error).
The answer to #2 is also “possible.” In fact Salesforce creates an email template with an invalid length subject when Sites is enabled.
There is other “invalid” data (related to currency values) lurking in the developer force instance – you will have to find this one yourself.
Thing to remember:
Just because Salesforce meta data says a field is 80 characters long does not mean it may have a longer value.
Just because Salesforce meta data says a number is DECIMAL(5,2) do not trust it. An API program may have inserted data that does not match the spec.
Do not be surprised if you read data from one Salesforce instance and it fails to upsert into another instance – the source data may be bad.
Though Salesforce allows many custom fields to be created on a table, using too many columns in a SOQL statement will cause a QUERY_TOO_COMPLICATED error. At least this “sin” is one Salesforce documents but after 10 years one would assume they would have a work-around in the back-end.
If you really need to do the equivalent of “SELECT * FROM Account” and SOQL will not allow the read in a single statement what needs to be done? There are two problem to solve.
Figure out the minimum number of SOQL queries to run. If none of the columns are formulas then this can usually be done by using 500 columns for each query. If formula columns are involved the problem is much harder – in this case see Sin #7.[
Join the results of multiple queries together.
Realistically, grab the data from a Salesforce dump file or use a tool like Capstorm’s CopyStorm to extract the table into a relational database. Doing it yourself is hard.
The transaction cost of querying a table with SOQL varies a lot. The first time you query a high cost table and cause your production org to run out of transactions will probably be the last time.
Here a SOQL quiz. How many Salesforce transactions does it take to run the following SOQL statement?
SELECT id, name FROM TableName LIMIT 2000
The answer, of course, depends on TableName and is either 2000, 200, 40, 20, 10, 4, 2, or 1.
The “1 transaction per record” rule for Attachment records is documented. The same rule applies to QuoteDocument and ContentVersion but we have learned this from experience rather than documentation. In general 2000 and 1000 are the common number of records per transaction but the only way to know for certain is the write a bit of code and see how many come back in a bunch.
When Salesforce runs a SOQL query it turns it into SQL first. Once in SQL there is a 64K character query limit. If the 64K SQL query limit is passed then SOQL will return a QUERY_TOO_COMPLICATED exception.
Here a SOQL quiz: Given a SOQL statement how can you accurately (or inaccurately even) guess that it will generated a SQL statement less than 64 characters?
The answer is……if table has a lot of formula columns you probably cannot guess accurately.
In practice, the addition of formula columns in a SOQL statement can cause the size of the resultant SQL to explode – sometimes. It all depends on the complexity and number of tables referenced by the formula.
The complexity of the formula seems to matter. My guess is that Saleforce is in-lining the formula calculation into the generated SQL.
A formula that references other tables likely causes the table expression and predicate portion of the generated SQL to grow rapidly.
The solution to this problem is nearly the same as Sin #5 but the first step, determining the minimum number of SOQL query to run can difficult. The only solution we have found that works reliably is iterative.
Sort column in ascending order by the length of their name or length of their corresponding formula.
Set maxColumn = total # of columns
Run a query run using columns 1 thru maxColumn with a LIMIT 1.
If the query succeeds then save the query, remove the query’s columns from the list of available columns.
If the query fails then set maxColumn = maxColumn – 1 and start step 3 again.
Set maxColumn = # remaining columns
If maxColumn > 0 goto Step #3, otherwise all queries have been determined.
The “SOQL Sins” described in this article were accumulated over a number years while developing:
CopyStorm – keep a hot backup of your Salesforce instance in SQL/Server, Oracle, MySQL, PostgreSQL, and H2
CopyStorm/Restore – restore a backup to any production, development, or sandbox instance. This is a restore tool even your manager could use.
SQLForce – a standard Python module for Salesforce. Works with Python 2.8. 3.3, and 3.4. Use SQLForce when Apex is just too hard.
For more information see www.capstorm.com
This page provides instructions for connecting to Salesforce using certificate-based / JWT authentication.
To connect to Salesforce using JWT authentication it is necessary configure an External Client App with a certificate, and to provide the certificate and OAUTH Client Id to CapStorm.
Create a certificate using CapStorm by selecting the JWT credential type and exporting the certificate file.
To select the JWT credential type:
Click on the Edit button for Advanced Parameters.
Select Oauth 2.0 JWT in the dropdown.
To Save the certificate:
This will create two files:
The certificate and private key are stored in a file CapStorm_JWT.jks in the CapstormConfig folder.
The CapstormConfig folder is a folder next to the application folder.
For example, if CopyStorm is installed in C:\CapStorm\CopyStorm
Then the CapstormConfig folder will be C:\CapStorm\CapstormConfig
Create an External Client App using the PEM file exported in Step 1.
Login to Salesforce and go to Setup. Search for External Client App Manager in the Quick Find box, and click on New External Client App.
Enter app details:
External Client App Name
API Name
Contact Email
Callback URL
Then, click on “Create”.
After creating the External Client App, configure app policies to allow access.
Click on “Edit” for App Policies, and update the policy to enable appropriate users. In this example, a Permission Set is used to grant access to the app:
Under OAuth Policies, change Permitted Users to:
Admin approved users are pre-authorized.
Under Select Profiles and Select Permission Sets:
Select the Permission Set(s) or Profile(s) that should be granted access to the External Client App.
To configure CapStorm, the Oauth Client Id (Consumer key) from the External Client App will be needed.
Go to the Settings tab of the External Client App.
Under OAuth Settings, click on Consumer Key and Secret.
In the Consumer Details page, copy the Consumer Key.
Copy the Consumer Key:
Now, to finish configuring CapStorm:
Copy the Consumer Key value into the OAuth Client Id text box.
Enter the Salesforce User’s username into the Username text box.
The user must be a member of the Permission Set or Profile configured in the OAuth policy.
Enter the Salesforce instance’s host name into the Salesforce Host text box.
To verify the connection, click on the “Test Salesforce Connection” button. If successful, the below window will appear:
The custom certificate checkbox allows users to create and use their own custom java keystore file, separate from the built-in Java JRE keystore. By enabling this checkbox, several new fields will appear in the login form:
The process of configuring OAuth JWT login with a custom certificate is largely similar to the above steps, the main differences being:
OAuth Public and Private keys will need to be generated manually
The Certificate will need to be generated manually from the public and private keys
The certificate will need to be added to a java keystore file or a PKCS12 file
Keystore info (file path, keystore password, key password, and name) must be entered manually into CopyStorm
After manually generating the above keys and files, the rest of the setup is largely similar to the non-custom certificate flow. Create an external client app, upload the certificate to the external client app, configure the external client app, and finally configure CopyStorm.
For more information on generating keys and certificates for use in Salesforce OAuth JWT, see this .
The Salesforce API presents all SObjects (Account,Contact, etc.) as tables to the outside world even though quite a number of SObjects are really subsets/views of other SObjects. The most common example is Salesforce feed tables — there are dozens of feed tables (AccountFeed, ContactFeed, etc.) that are simply views of the table that contains all feeds: FeedItem.
The AccountFeed table is really a view on the base table FeedItem.
SELECT * FROM FeedItem WHERE parentId IS an Account Record.
There are also cases where the Salesforce API does not support a direct query on an SObject but the SObject can be constructed from other SObjects.
The ActivityHistory table is a union of the Event and Task SObjects but cannot be queried directly using SOQL.
There are other issues of this kind, but lets get to the important part. When Database Views are enabled in CopyStorm, then CopyStorm will use views in the target database rather than copying a table. This can lead to much faster backups for each table that can be represented as a view.
Database Views are enabled by default in CopyStorm and when enabled:
If a Salesforce table does not exist in the target database and can be represented as a view, then CopyStorm will create it as a view.
If a Salesforce table already exists in the target database, then CopyStorm will not re-create it as a view but will continue to treat it as a table.
If Database Views are disabled in CopyStorm:
Database Views will not be created for new tables.
If a Database View already exists in the target database, then CopyStorm will not change it.
The toggle that enables/disables Database Views is found in the configuration section of the CopyStorm Configuration tab.
This section is for anyone wanting to know exactly how the logic for determining whether a Database View should be used works.
5000
.*Share
5000
FeedComment
5000
Task
5000
EmailMessage
5000
CaseComment
50
FieldPermissions
2000
LoginHistory
2000



The exported PEM file.
NOTE: This field is required, but the value for Callback URL is not used for JWT Apps.
Enter https://localhost/ as the Callback URL.
OAuth Scopes
At a minimum, the following scopes must be selected:
Access the identity URL service (id, profile, email, address, phone).
Manage user data via APIs (api).
Perform requests at any time (refresh_token, offline_access).
Enable OAuth
This checkbox must be checked.
Enable JWT Bearer Flow
This checkbox allows JWT access.
Certificate Upload
Upload the PEM file that was saved in Step 1.
Click on “Create” to create the External Client App.
CapStorm recommends configuring a Permission Set to limit App access.
Click on “Save” to save the App policies.
Sandboxes will have host names like:
mycompany–mysandboxname.sandbox.my.salesforce.com
Production orgs will have host names like:
mycompany.my.salesforce.com
Click on Test Connection to verify.
Yes
Password used to access the Keystore (blank if the Keystore does not have a password).
Key Name
Yes
The name of the private key used to sign JWT requests.
Key Password
Yes
The password used to access the private key.
OAUTH Client Id
Yes
The Salesforce-generated Client Id for the Connected Application.
Username
Yes
The login Id of the CopyStorm Salesforce user.
Custom Certificate
Unchecked
No
Check this box to use a custom-made Java keystore file (.jks). Leaving the box unchecked will cause the application to use the default Java key store.
Token Validity (minutes)
240
Yes
The lifetime of JWT access tokens. If the token expires during the CopyStorm run, CopyStorm will re-authenticate and get a new token.
Keystore
Yes
Path to a JKS or PKCS12 Keystore containing the private key used to sign JWT requests.












Keystore Password
CopyStorm always stores timestamp value using UTC — exactly like Salesforce. This article demonstrates how to convert a UTC datetime column to a timestamp in your local timezone.
select
AA.systemmodstamp
, CONVERT_TZ( AA.systemmodstamp, '+00:00', '-06:00')
from Account AA;SELECT
AA.systemmodstamp
, (FROM_TZ(AA.systemmodstamp,'+00:00') AT TIME ZONE 'US/Eastern') localtime
FROM Account AAselect
AA.systemmodstamp
, AA.systemmodstamp at time zone 'utc' at time zone 'pst' as localtime
from Account AA;SELECT AA.systemmodstamp, CONVERT(datetime,
SWITCHOFFSET(CONVERT(datetimeoffset,
AA.systemmodstamp),
DATENAME(TzOffset, SYSDATETIMEOFFSET())))
AS ColumnInLocalTime
FROM Account AAWith any backup solution an organization will want to know how their data is secured. Common questions include:
Where is my data stored?
How securely is my data transferred over the internet?
When and where is my data at rest?
For CopyStorm the Salesforce backup security answers are simple and complete:
Your Salesforce data is stored in a relational database that is created by you and is totally under your control.
CopyStorm neither knows nor cares where the data is stored — the database can be in your data center or in a cloud provider like Amazon.
The choice and level of security is entirely up to you.
CopyStorm runs on your computers and transfers all data from Salesforce using HTTPS.
Another common question is:
What Salesforce and database privileges are required by CopyStorm?
For Salesforce, the only absolutely required privileges are API Access and View Setup and Configuration. The Salesforce API ensures that CopyStorm always respects the privileges of the Salesforce credentials used by CopyStorm to connect. This means that CopyStorm will backup exactly what the privileged credentials would see if they were used with a web browser.
Full details are described in the .
For the target relational database CopyStorm needs to own a schema and does not need visibility outside of its assigned schema. No general DBA privileges are necessary.
While the CopyStorm Batch File can be configured to send email, the best practice is generally to use CopyStorm’s built-in notification settings.
The CopyStorm Batch File tab will generate a script that is useful for running CopyStorm in batch mode. Although the script generator asks for email addresses to notify on CopyStorm success and failure, some installation configurations may cause the generated script to not successfully send a Salesforce backup notification email.
The Batch File tab will generate scripts in a variety of languages. Some of these languages have a built-in way to send email in an operating system independent way, but some do not. When a scripting language (like BAT) does not have a built-in way to send an email then it is the responsibility of the script to implement the behavior.
See the following sections for help with each batch script type.
There is no standard way to send an email from a Windows BAT file, and CopyStorm does not try to guess the technique used by your organization. Generated BAT scripts isolate the “email sending” code to a small subroutine that must be implemented according to your company standard. At the end of a BAT script generated by CopyStorm you will see code that looks like:
:SendEmail REM REM Code your site specific email rule procedure here. REM REM %1 is the email subject REM %2 is the email address that should receive the mail REM %3 is a file containing the body of the email REM
ECHO TODO: Send email to %2 with subject %1 EXIT /B
This code is a subroutine that the script will call each time it attempts to send a Salesforce backup notification email. To finish the script, you need to implement your organization’s email sending logic. BAT file emailing is accomplished using a number of techniques, varying by organization:
Copying the log file to a directory using a name that indicates when the job completed.
Using the open source tool to email the status.
The following screenshot indicates where the script changes must be made:
Windows VBS has a built-in way to send an email if the name of an email server is specified. The default email server is GOING TO BE WRONG all of the time, and CopyStorm has no way to guess the correct server. The aspmx.l.google.com server name must be replaced by the name of your company’s email server.
aspmx.l.google.com is a well-known server that will process email addressed to gmail accounts.
The following screenshot indicates the values that must be changed to match your environment:
The rules for using a BASH script are the same as those for a VBS script — two values must be changed before generating the script:
EMail Server
EMail From
See the screenshot under the VBS section above for an example.
The rules for using a Python script are the same as those for a VBS script — two values must be changed before generating the script:
EMail Server
EMail From
See the screenshot under the VBS section above for an example.
A common question is “How do I connect to a database running on Amazon (or Azure) from my local laptop?” The answer often is:
Create an SSH tunnel that will allow you to treat the remote database as if it was local.
We have an instance of MySQL running on an Amazon EC2 instance and want to access it from our local network. Technically what we want to do is:
Pretend that there is a MySQL instance listening on port 3307 on our local network.
Have magic forward all communication on localhost port 3307 to a MySQL instance living on Amazon EC2.
The secret sauce requires setting up a forwarding port using ssh. Example:
ssh -L 3307:127.0.0.1:3306 myuser@myhost
This statement will open a terminal prompt on capstormlabs.com and a tunnel listening on 127.0.0.1 that forwards traffic on local port 3307 to port 3306 (e.g. MySQL) on capstormlabs.com. With any CopyStorm product the remote MySQL instance can be reference with a connection string like:
//localhost:3307/myDatabaseName
If you are hungry for more information then see for all the details.
A CopyStorm Snapshot is a database store containing tamper resistant snapshots of records from any Salesforce table where the snapshots are captured based on rules provided by a user. This section explores the architecture and implementation of the CopyStorm Snapshot subsystem and contains recipes for common snapshot tasks.
Good places to start include:
The minimum Salesforce backup permissions needed for CopyStorm to copy data from Salesforce to a database are:
API Enabled
View Setup and Configuration
Almost all of the time, the following permissions should be granted:
View All Data — this permission bypasses sharing rules and often increases performance.
When CopyStorm runs it tries to find a license on the local machine. If a valid license is not found then it requests one from license.capstorm.com.
If CopyStorm cannot get a license and fails with an error like “Connection Refused” then your firewall is blocking access to license.capstorm.com.
There are two common solutions to this problem:
If your browser is using a proxy to connect to the internet then CopyStorm may have to use the same proxy. See for help setting proxy parameters.
If your company firewall is blocking access to license.capstorm.com, the problem can be fixed by asking your network staff to open port 443 to license.capstorm.com (75.2.67.235).
If the CapstormCustomerKey.txt file is not installed correctly, move the file to a .
In all cases the connection to the Capstorm license server can be validated by following the instructions on .
If your organization will not allow communication with license.capstorm.com, the solution is to send an email to with the following information and we will email you a license file:
On Linux systems the Oracle JDBC driver has a login dependency on the random number generator “/dev/random”. Under certain circumstances, the “/dev/random” generator can take an inordinate amount of time to generate a random number — this can cause unpredictable timeouts when logging into Oracle.
See for the technical details.
CopyStorm releases after 8.40.1 patch 28-Nov-2017 have fixed this problem internally. If you are on an earlier release, this article describes how to fix the issue.
Open the CopyStorm.sh script in a text editor and add the flag “-Djava.security.egd=file:/dev/./urandom” to the command that launches CopyStorm.
For example, in our tests we added this flag using the following changes to the CopyStorm.sh script:
RAND= if [ -e “/dev/urandom” ]; then RAND=”-Djava.security.egd=file:/dev/./urandom” fi
“$JAVA” -cp “$MYROOT/lib/*” $RAND -Dcopystorm.root=”$MYROOT” -Dhttps.protocols=”$MYPROTOCOLS” $MYAPPLICATION -license $MYLICENSE $*
There are a number of situations where you may want to review Salesforce backup debug logs from CopyStorm — usually this is because something is “wrong” with the Salesforce infrastructure and the problem needs to be narrowed down enough to encourage Salesforce support to rapidly take ownership. Here are a few examples Capstorm has encountered:
A customer had a table where a query would always time out — even when a single row was selected. The problem was a formula column causing problems with the Salesforce infrastructure. Using CopyStorm’s debug information a sample query exhibiting the behavior (even in the Salesforce Workbench) was quickly found:
SELECT id, customFormulaColumnName FROM Contact LIMIT 1
CopyStorm Snapshots are designed so a user can set up new snapshots for a variety of purposes. This tutorial describes a realistic scenario and then walks thru the steps to setup the associated CopyStorm Snapshot Policy.
The legal team for the ACME Beach Club has informed the Salesforce administrator that all Account, Contact, Case, and EMail records related to the account Evil Empire need to be retained and any future changes also need to be retained. To prepare for this situation the Salesforce administrator has already added a formula column in Salesforce, LegalArchivalSet__c, that will evaluate to the string “EvilEmpire” for all of the records the legal team wants to be retained.
The next few sections walk to the steps to setup a CopyStorm snapshot for “Evil Empire” records.
The first step is to create a new snapshot that will only include tables that the legal department indicated.
Set up the top level parameters for the snapshot including a snapshot policy name and description
CopyStorm supports a number of authentication mechanisms, including:
Salesforce Username & Password (default)
The OAuth JWT flow
SFDX
If Salesforce is using SSO to authenticate users, the Username & Password may not work. If this is happening, there are two options to fix authentication:
CopyStorm includes logic specific to Daylight Savings or Summer Time changeovers.
This logic accommodates both time changes and Salesforce record commit latency issues.
When a CopyStorm job finishes within a few hours of a time change, the next job will re-query for records modified before the time change.
The next job will re-scan an extra 90 minutes of record changes prior to the time change. This ensures that Salesforce commit latency issues and time change issues do not cause missing records in the database.
Jobs that run near a time change will take longer to complete.
This is because the job intentionally reads extra data to ensure that all records are copied. As a result, you will likely see a higher number of “Skipped” records – the job is re-checking data that is already up to date in the CopyStorm database.
Use JWT or SFDX to authenticate.
Manually set the User’s password in Salesforce.
This causes Salesforce to bypass SSO and use its default Username & Password authentication when logging in via the API.
All data is encrypted and the strength of the encryption is controlled by Salesforce.
The only time data is at rest is when it is written to your database.
Product Name
Product Version
IP Address of your computer
Salesforce Org Id
If you are not familiar with Linux scripting, the changes say:
Set the local RAND variable to blank.
If the system has the faster “/dev/urandom” character device:
Set the RAND variable to the Java setting which will make Java’s random number generator use “/dev/urandom”.
Add the RAND variable to the Java command that launches CopyStorm.


Suppose a company has five Salesforce production instances and needs to backup all of them with CopyStorm. How many computers or virtual machines are needed?
This question is a lot like asking “How long is a piece of string?”. Though running many CopyStorm jobs on the same computer will work, the maximum number depends on a lot of factors. Here are a few key questions to ask:
What is the largest record each job will need to back up?
The primary determining factor in the amount of memory required by CopyStorm is the size of the largest record that must be retrieved from Salesforce.
For example, if your Salesforce contains a 500MB Attachment then CopyStorm will need around 1300MB of memory at runtime (500MB for the record from Salesforce, 500MB for the prepared database record, and a bit more for overhead).
Except for Attachments and ContentVersions, CopyStorm can usually run in 100-120MB (you will see larger usage in most cases because the system allows it and the application uses more memory to avoid frequent garbage collection).
You can discover the size of your largest record in the Salesforce GUI and use this information to estimate CopyStorm memory usage.
How often will each backup run?
To backup multiple Salesforce instances, where CopyStorm jobs are scheduled to run at the same or overlapping times the total amount of memory required on your computer may need to be increased.
Though running two jobs may not double memory usage, the difference will be material.
What is the throughput to/from the internet on the computer?
The #1 performance bottleneck for CopyStorm is typically the rate at which Salesforce responds to queries.
For a single CopyStorm job it is unlikely that throughput to/from the internet will be a problem, but running many CopyStorm jobs simultaneously may swamp a computer’s Ethernet capabilities.
What is the throughput to/from the database where CopyStorm backups will be stored?
The #2 performance bottleneck for CopyStorm is the rate at which data can be written to the target database.
The short answer is that you can keep adding scheduled CopyStorm jobs until you are unhappy with the performance. Running several jobs at the same time will rarely be an issue, but running dozens at the same time may require revisiting your computer’s memory and Ethernet performance.
To create a schema-only CopyStorm backup, you can:
Start with an empty database.
Go to the “Configuration” tab.
Select the “Guardrails” configuration section.
Check the “Schema Only Backup” option.
Press “Start Copy”.
This will cause CopyStorm to start a new backup, create tables in the database, and copy no table data!
After the CopyStorm backup has completed, the backup database will contain an empty Salesforce schema that is compatible with CopyStorm/Restore.
If new tables or fields are added to the Salesforce instance, running CopyStorm again with the same configuration will update the database with the new or modified tables and fields.
Read Encrypted Data — this permissions returns the plain text value for encrypted fields.
Query All Files — this permission allows files in private folders to be read.
Knowledge User — this license allows draft knowledge articles to be read.
There are also several tables that have a restricted syntax, and will not be backed up unless the Salesforce user is an administrator. These tables include:
NewsFeed
EntitySubscription
If the source Salesforce instance uses Chatter, or has the Chatter setting “Enable Unlisted Groups” feature enabled, the following permissions should be granted:
Manage Unlisted Groups — this permission bypasses Unlisted Groups access checks for Feed records.
In the scenario where “Forecasting” objects such as “ForecastingQuota” are desired to be backed up and optionally restored, the following user permission is required:
Allow Forecasting — this permission grants a user the ability to access and utilize the forecasting features within Salesforce.
Many people assume that a Salesforce Administrator automatically has permission to access all data. Wrong! Even some core Salesforce tables and fields are hidden from administrators by default. Fortunately, the CopyStorm/Medic Permission Checker tool will find all tables and fields inaccessible for any Salesforce user with the permissions API Enabled and View Setup and Configuration.
A customer had a handful of records in a table where the SOAP API provided invalid XML. CopyStorm’s debug tools gave a trace of the request and response envelopes sent to/from Salesforce. In this case the problem was caused by security middleware that was rewriting part of the response from Salesforce.
A customer had a table where every query would return a Salesforce UNKNOWN_EXCEPTION exception. CopyStorm’s debug tools identified the problem query and a short time in Workbench crafted a two column query that reproduced the problem every time.
A customer had a table where a query on several records would return a Salesforce UNKNOWN_EXCEPTION exception, though most records could be queried. CopyStorm’s debug tools isolated the records and queries and allowed something short to be given to Salesforce support:
SELECT id, customColumn WHERE id IN (‘……’)
To view the SOQL generated by CopyStorm, run CopyStorm in command line mode with the “-debug” flag.
CopyStorm.bat -debug -run myFile.copyStorm
sh CopyStorm.sh -debug -run myFile.copyStorm
That’s it — you will see the SOQL statements in the command line window.
To capture the SOAP generated by CopyStorm, run CopyStorm in command line mode with the “-apiTraceFile” parameter.
Note: The “-apiTraceFile” flag ALWAYS takes a file name as an argument (this is good because the SOAP envelopes tend to be large).
CopyStorm.bat -apiTraceFile mytrace.txt -run myFile.copyStorm
sh CopyStorm.sh -apiTraceFile mytrace.txt -run myFile.copyStorm
Change the filter type to use a column expression and only grab records where the LegalArchiveType__c value is “EvilEmpire”
Check the “active” box, save changes and the snapshot rule will automatically include “Evil Empire” records that are modified in the future. The next step will force a snapshot of all historical “Evil Empire” records.
At this point the “Evil Empire” snapshot policy is active and will automatically include future activity in Salesforce. For addition information see:
By default, CopyStorm does not store Salesforce or database passwords. To enable this option, select the “Store Passwords” option when saving a configuration file. When checked, CopyStorm will maintain Salesforce password security by encrypting Salesforce and database passwords in the save file.
CopyStorm includes an extensible system which allows the usage of third-party password managers to store Salesforce passwords. The default password storage locations include:
Directly within the CopyStorm save file (this is the default).
Within a KeePass file named “passwords.kdbx” located in any of:
The user’s home directory.
The CopyStorm installation directory.
A subdirectory of the CopyStorm installation directory named “config”.
Any directory adjacent to the CopyStorm installation directory.
To use your own password manager, please see our tutorial titled .
To enforce Salesforce password security using the KeePass password manager to authenticate with Salesforce, you will need:
A kdbx (KeePass v2.x) formatted password file containing the username and password of the Salesforce user.
For more information on the KeePass password manager, see
The user’s Security Token may be either:
Appended to the user’s password.
After installing Perl with the kpcli dependencies:
Put the passwords.kdbx file in one of the locations referenced above.
Put the kpcli.pl script in one of the locations referenced above (make sure the file is named “kpcli.pl”).
Make sure the script is installed correctly by running the command:
When running on Windows using Java 1.9 or higher, you may see popups within CopyStorm and CopyStorm/Restore displaying incorrectly. This can occur when using multiple monitors that are configured to use different display scaling settings – a common configuration when running on a laptop computer that is connected to an external display.
The underlying issue that causes this behavior has to do with how Windows displays applications at different scaling settings. To fix the issue, you can:
CopyStorm may be launched by either javaw.exe or java.exe – if using the Windows version, they will be located at:
[CopyStorm]/jre/bin/javaw.exe
[CopyStorm]/jre/bin/java.exe
If there is no jre folder in the CopyStorm installation, then you will need to find the system-installed Java executables.
Right-click on the executables and select ‘Properties’.
Select “Compatibility”
Select “Change high DPI settings”
Check “Override high DPI scaling behavior.”
Set “Scaling performed by:” to “System”
After saving / applying the settings (and restarting CopyStorm), the application should display everything correctly!
Salesforce stores the Attachment and ContentVersion bodies as BASE64 strings — a common question is “How can I turn a database Attachment into a file my application can read?”. Since the data is stored as a BASE64 string, this is equivalent to “How do I convert a BASE64 string into its binary equivalent?”.
The answer to this question is database dependent.
To perform BASE64 to binary conversion in Oracle:
Download the base64decode() function from the link on oracle-base.com.
Use SQL to convert the body of Attachments to their binary format:
SELECT id, BASE64DECODE(body) AS rawbody FROM Attachment
You may want to use the BASE64DECODE() function to create a permanent view to the Attachment or ContentVersion table.
To convert a BASE64 column to a text column in SQL/Server:
To convert a BASE64 column to a binary column in SQL/Server:
CopyStorm copies both active and deleted records from Salesforce to the target database by inspecting the Salesforce recycle bin. When a deleted record is discovered its “isDeleted” column is set to true in the target database.
The retention policy for deleted records in the target database is set using the Advanced tab parameter “Delete Older Than”. Available values can range from:
Remove deleted records immediately.
Remove deleted records after they have been deleted in Salesforce for 7 days.
Never remove deleted records.
There are also situations where a record is deleted in Salesforce but is not discovered by CopyStorm. This situation may occur when:
A user deletes records in Salesforce and empties the recycle bin BEFORE CopyStorm has run.
A system administrator empties the global recycle bin.
A Salesforce API program does a hard delete on Salesforce records.
A hard delete bypasses the Salesforce recycle bin mechanism.
When a Salesforce record is hard-deleted it is usually wise to use the CopyStorm/Medic Fix IsDeleted tool to mark the appropriate records as deleted in the target database. For information on when and how the CopyStorm/Medic tool should be used see .
While the brave at heart will export data from the CopyStorm Snapshot subsystem using raw database SQL queries, most people will want some help from a GUI. If you happen to be a “brave at heart database person” then jump to the article on CopyStorm Snapshot Data Storage.
The CopyStorm Snapshot Explorer tool is designed to find and export data from a CopyStorm Snapshot. The tool is launched using a hyperlink next to the snapshot of interest in the CopyStorm GUI.
For this tutorial we will:
Launch the Snapshot Explorer
Search for Contacts in a snapshot that match specific criteria.
Export the found contacts to a CSV file.
See the following articles for additional help.
For developers, a useful way to provide CopyStorm with Salesforce credentials is via a SFDX username or alias. When an SFDX username is provided, CopyStorm calls out to SFDX to create the a Salesforce session token, relying on SFDX to do all of the OAuth dirty work!
Step 1: Change the CopyStorm credential type to SFDX Username or Alias.
Step 2: Enter an SFDX username or alias.
As a final step, optionally test the connection using the Test Salesforce Connection button.
As a best practice, we recommend using an SFDX alias rather than a username in order to support easier reuse when new scratch orgs are created.
Upgrading CopyStorm can be a simple task if you follow one rule:
Do not store site specific customizations or configuration files in the CopyStorm distribution directory.
If you have set up your Capstorm software by following our Best Practice Guide, you should be ready to continue with the upgrade. If you have included site specific files in the CopyStorm distribution directory then move them into their own directory before starting the upgrade.
To upgrade a CopyStorm installation:
Download the latest CopyStorm release from https://www.capstorm.com/download
Rename the existing CopyStorm root directory to a new name.
Unzip the CopyStorm distribution archive.
Move the unzipped CopyStorm directory to the same location as your previous CopyStorm installation.
Copy any site-specific configuration files from the previous installation directory to the newly moved installation directory.
Be sure to include the file, if it is installed in the CopyStorm product directory.
You’re finished! CopyStorm distributions have always been backwards compatible with configuration files from previous versions so there is nothing else to change.
WARNING: DO NOT unzip a CopyStorm distribution over an existing installation of CopyStorm.
Metadata tables in a CopyStorm database are primarily copies of the equivalent Salesforce metadata calls plus mappings from Salesforce to CopyStorm names for tables and fields. These tables are the “CopyForce” tables found in the CopyStorm database.
CopyForceTable maps the Salesforce API table name to the CopyStorm created database table name. It contains the same fields as a Salesforce DescribeSObjectResult. Where possible CopyStorm uses the same name, but there are several reasons why CopyStorm may use a different table name:
Names that are the same as reserved words in the target database will be modified.
For example, User is renamed to User2 in SQL/Server.
Table and column name size limitations in Oracle dictate shortening longer names.
For more information, see
CopyForceTableField maps table field names to CopyStorm created field names. It contains the same fields as a Salesforce field.
For more information, see:
CopyForceTableChildRelationship maps parent table names to child table names. It contains the same fields as a Salesforce ChildRelationship.
For more information, see:
CopyStorm does its best to keep column definitions in the target database exactly the same as the corresponding definitions in Salesforce. Normally this happens automatically as CopyStorm performs required ALTER TABLE/COLUMN statements on the target database. This article describes what to do when an ALTER fails. An ALTER may fail for several reasons:
A column data type in Salesforce changes. Few databases support this conversion automatically.
For example, changing a String to a Number.
CopyStorm’s Snapshot System creates tamper resistant snapshots of Salesforce records under conditions that are specified by a customer. Examples:
Snapshot all deleted records.
Snapshot modifications to closed Opportunity records.
Snapshot modifications to Case records where the custom file archiveStatus__c is set to Active or Continuous.
When a new version of CopyStorm is released, adjustments to the internal CopyStorm data model may be required. By default, CopyStorm automatically handles database version upgrades. To disable automatic schema upgrades, refer to the .
CopyStorm’s default behavior is to display a Schema Upgrade Notice dialog to the user:
From this dialog, you can:
View all pending schema upgrades.
View specific details about a schema upgrade, including the underling SQL to be executed.
In Salesforce all Date/Time data is stored in UTC — . UTC is not a time zone but rather a time standard used commonly around the world.
For practical purposes, we can assume that UTC is the same as the older GMT (Greenwich Mean Time) standard and is the current time in London, UK.
CopyStorm also stores all Date/Time values in UTC and it is up to an application to convert UTC values to the timezone of each application using the data. This makes a lot of sense for systems with users accessing the same data from wildly different timezones. Each user expects to see Date/Time values displayed in their local time zone!
This section lists a few techniques for converting from UTC to the local timezone of the computer hosting the CopyStorm database.
Example query:
SELECT systemmodstamp ,DATEADD(hh,((DATEDIFF(ss,systemmodstamp,GETDATE())-DATEDIFF(ss,systemmodstamp,GETUTCDATE()))/3600), systemmodstamp) AS LocalTimestamp FROM Account
There are two things to note with this solution:
In general, CopyStorm uses the minimal number of API calls possible to do a backup.
Detailed information can be found in this table:
Salesforce has recently announced their plans to deprecate the SOAP API login method. The purpose of this article is to outline the impact to the CapStorm applications that will result from this change to the Salesforce platform. More information about this change to the Salesforce platform can be found .
When using CopyStorm, the only Salesforce credential type that uses the Soap API login is the "Username and password" option. Note: This does not include OAuth Username and Password.
This change to the Salesforce platform will have a few noteworthy impacts on the CapStorm family of applications. These changes will only affect version 10.65.1 (V5.4 of the CapStorm Container) and newer:
CapStorm applications using the Username and Password Salesforce login type will fallback to Salesforce API version 64.
The first time a programmer brings a CopyStorm database into ERwin (or another data modeling tool) one of the first questions asked is:
Where are the relationships between tables?
The “database equivalent” question is:
Why doesn’t CopyStorm generate FOREIGN KEY constraints?
The short answer to this question is:
The addition of Foreign Key constraints would dramatically increase the complexity and cost of extracting data from Salesforce without improving the performance of database queries.
To connect to Salesforce using the , CopyStorm can be configured with:
The OAUTH Consumer Key and Certificate.
The username and endpoint for the Salesforce instance.
JWT Authentication can be enabled in Salesforce by following . The overall process is to:
Create a Connected Application.
The CopyStorm Snapshot subsystem stores record data in database XML column types and many database professionals may not be familiar with how to write SQL queries to read snapshot data. Though we do not expect many people to write their own SQL queries against CopyStorm snapshots, we have include a query generator to help a programmer to get started.
The basic procedure is:
Open the Snapshot Explore for the snapshot you want to query.
Select a table and the columns you want in the query.
For normal tables, SQL/Server has a hard limit of 1024 columns. This article explains what to do if your Salesforce table has more than 1024 columns.
SQL/Server will support up to 30,000 columns per table but to achieve this columns above the 1024 limit must be created as SPARSE columns. A sparse column is a column whose value is stored in a special column that contains an XML document. Naturally, sparse columns are more expensive to search and update than regular columns but they do provide a way to get past the 1024 limit.
The produced to fix a problem table is:
Turn a table into a wide table by adding a new column to hold sparse column values.
Identify which columns to change to sparse columns.
Having multiple CopyStorm jobs run on the same database at the same time is perfectly OK if the two jobs are processing different Salesforce tables. However, what if two CopyStorm jobs are running at the same time on the same set of tables? How can this happen?
CopyStorm is scheduled to run every 30 minutes.
A CopyStorm job starts at 12:00.
At 12:30 the first CopyStorm job is still running because there were a LOT of updates in Salesforce.
Since, in nearly all cases, Salesforce is a live system that is always changing, it can be difficult to prove that a CopyStorm backup is complete. There are, however, techniques that can be used to gain confidence that a backup is “complete.”
One common approach sites take is to compare record counts reported by Salesforce with record counts in the CopyStorm backup. This approach works pretty well as long as the following facts are understood.
Salesforce does not include archived or deleted records in reported record counts. CopyStorm backs up both of these record types and may report more records than indicated by Salesforce.
By default, CopyStorm will not back up a record until it is unchanged for approximately 2 minutes. There is a good reason for this default behavior and it is because of the “” feature. This means that Salesforce may report slightly more records than CopyStorm
To connect to Salesforce using a Time-Base One-Time-Pad (TOTP) Authenticator code, CopyStorm can be configured with:
A TOTP Authenticator App Code.
The username and password for the Salesforce instance.
TOTP authentication can be enabled in CopyStorm by selecting the “One-Time Password Authenticator” credential type:













Salesforce performs a hard delete.
There are a few tables that Salesforce hard deletes by default.
0
Any deleted records copied from Salesforce are immediately deleted from the target database.
7
Deleted records are removed from the target database after they have been deleted in Salesforce for 7 days.
A blank value means that deleted records are never removed from the target database.
Snapshot all changes to Account and Contact records.
Snapshot all changes made to Contact records by User myuser@demo.capstorm.com
As you may suspect, the conditions that can be specified to trigger the snapshot of a record can be quite rich.
There are several broad situations where a CopyStorm Snapshot is a great choice.
By default, CopyStorm creates one snapshot — the Default Recycle Bin. The CopyStorm recycle bin is similar to the Salesforce recycle bin but with many features unavailable within Salesforce.
Any type of record can be snapshot — even those not supported by the Salesforce recycle bin.
The recycle bin can keep deleted records forever (or any other specified duration)
Data retention policies can be applied on per table basis. For example, it is easy to tell the system that Accounts, Contacts, Cases, and Opportunities should be snapshot forever while other snapshot records should be deleted after 90 days.
In addition to a record’s data, the snapshot system will remember the field definitions in place at the time that the record version is added to the snapshot.
Sometimes it makes sense to delete old records from Salesforce but the records still need to be kept around “just in case”. This is easily achievable with a CopyStorm snapshot.
Define a new CopyStorm snapshot with a filter describing the records that should be snapshot.
Run the snapshot by hand. This will scan existing Salesforce records and snapshot those that meet the filter.
Delete the snapshot records in Salesforce.
The snapshot data can be retrieved using the CopyStorm Snapshot Explorer or by running your own SQL queries.
Once records have been stored in a CopyStorm Snapshot, a common use case is to display the snapshot records in the Salesforce GUI. If you have technical staff with the required skills, this is a fairly simple task.
Create REST Web Services for querying a CopyStorm Snapshot. You can host the web services in the container of your choice.
Craft a handful of Salesforce lightning components that use the web services.
Add the lightning components to Salesforce pages.
If this sounds too complex, our reference implementation based on Apache/Tomcat can get you started (contact support@capstorm.com for the status of our reference implementation).
The original motivation for CopyStorm Snapshot came from a customer:
We have hundreds of active lawsuits at any given point in time and we need to snapshot all changes to related Salesforce records.
A CopyStorm snapshot can be used to solve this problem by creating a new snapshot that contains a filter to define the criteria under which records should be snapshot. If this snapshot is activated, CopyStorm will automatically apply the filter to records as they are backed up and snapshot them if they meet the filter criteria. Examples:
Snapshot all changes to Contracts associated with Account “Acme Industries” that occur after 2019-01-01.
Snapshot all email communications with Contacts working for “Acme Industries” and any emails to the domain “acme.com”.
To assist compliance, snapshot records will be tamper resistant. Any tampering will be detectable because it will cause the computed fingerprint associated with a record to change. Records can be made tamper proof if an snapshot’s database protections are set to write-only.
CopyStorm Snapshot is implemented as a set of documentation tables that are automatically created and maintained by CopyStorm. There is nothing a user has to do to create or maintain the tables — they are created on first use of the snapshot system and maintained by CopyStorm.
Like other other CopyStorm tables, the schema is documented and the tables are directly queryable by customers. However, unlike other CopyStorm tables, you may need a little help constructing queries since most of the data for snapshot records is stored as XML. The good news: CopyStorm’s Snapshot Explorer can be used to easily generated base SQL queries which a customer can modify for their specific needs (We have a hard time remembering how to construct XML based queries for databases too!).
SQL/Server 2016 has a direct solution to this problem (see this article).
This example does not take daylight savings time into consideration.
See this script for a solution that takes daylight savings time into consideration.
Example query:
SELECT systemmodstamp, systemmodstamp + (systimestamp – SYS_EXTRACT_UTC(systimestamp)) LocalTime FROM Account
Example query:
SELECT systemmodstamp, systemmodstamp + INTERVAL (TIMESTAMPDIFF(SECOND, UTC_TIMESTAMP() , NOW())) SECOND FROM Account
Example query:
SELECT systemmodstamp, systemmodstamp AT TIME ZONE ‘UTC’ FROM Account
This means that Username and Password login type will still be functional for the near future.
It should be noted that Salesforce objects and fields made available in Salesforce API v65 and newer will not be available for backup/restore when using Username and Password login.
CapStorm applications using the Username and Password Salesforce login type will display a warning when using the "Test Salesforce Connection" button, informing the user that using this login method is causing the application to fall back to API version 64.
CapStorm applications using the Username and Password Salesforce login type will report an exception to notify the user that SOAP API login is being deprecated. This exception is purely informative, and does not indicate any errors in the application.
CapStorm applications making use of any of the supported OAuth login options will be unaffected by these changes.
We recommend that users migrate to using any of the available OAuth login methods in order to stay up to date with Salesforce's best practices and make use of the latest CopyStorm supported Salesforce API version. Please see the following pages for more info on configuring CopyStorm to make use of OAuth login:
Records MUST be inserted/updated in an order that maintains referential integrity — 100% of the time.
Bi-directional relationships must be backed up in two passes. This type of relationship occurs frequently in Salesforce.
Let’s look at one simple referential integrity example. Salesforce’s Account table contains a “Parent Account” field. If there are three accounts in Salesforce (A, B, and C), and A is the parent of B and B is the parent of C then the records have to be written to the database in the order:
A then B then C
Any other order will cause a referential integrity error in the database. Add a few dozen tables and their cross relationships and the complexity of this problem explodes (along with the runtime)!
Let’s look at a simple bi-directional relationship where it is impossible to copy the records in the proper order.
Each User record in Salesforce references a Profile record.
Each Profile record in Salesforce references the User table via the Profile.ownerId field.
This is a problem because it makes it impossible to copy the “correct record first” due to the mutual dependency. Any restore approach (if Foreign Key constraints are enabled) would require an approach like:
Copy the User record, leaving the ProfileId field null.
Copy the Profile record.
Update the User record’s ProfileId field with the id of the Profile record restored in the previous step.
Does this sound like a lot of data retrieval and graph theory to make a backup work? In practice the problem is much harder than these examples when the reality of hundreds of tables and their interrelationships are added.
Though CopyStorm does not declare Foreign Key constraints, it does create indexes on all columns that are involved in foreign key relationships. This means that JOINs will run fast (even though ERwin will not display a nice picture of the relationships).
When you need to know the key relationships there are several good sources:
Salesforce publishes ERDs of their data models.
CopyStorm maintains tables of all relationships in several tables included in every CopyStorm backup.
ALTER the definition of the identified columns to be sparse.
The following example code creates a regular table and then turns it into a wide table and changes most of its columns to be sparse.
CREATE TABLE SparseExample (
id BIGINT IDENTITY
,name VARCHAR(50)
,address VARCHAR(255)
,other VARCHAR(MAX)
);
ALTER TABLE SparseExample ADD sparseColumns XML COLUMN_SET FOR ALL_SPARSE_COLUMNS;
ALTER TABLE SparseExample ALTER COLUMN name VARCHAR(50) SPARSE;
ALTER TABLE SparseExample ALTER COLUMN address VARCHAR(255) SPARSE;
ALTER TABLE SparseExample ALTER COLUMN other VARCHAR(MAX) SPARSE;
INSERT INTO SparseExample(name,address,other) VALUES(‘Capstorm’, ‘Florida’, ‘Now is the time for all good men…’);
SELECT name, address,other, sparseColumns FROM SparseExample
Google SQL Server Wide Table and you will find many helpful articles.
The CopyStorm/Medic Scan Timestamps tool will do an exhaustive comparison between records in Saleforce and the CopyStorm database and report both on records that do not match, records that will be made to match in a future backup, and records that will be inserted in a future backup.
The CopyStorm/Medic Count Records tool will count records both in Salesforce and CopyStorm and compare the results. This technique works until a Salesforce table becomes too large to count records (e.g. a SELECT COUNT() always times out).
When the backup is missing a column the problem is nearly always because the Salesforce credentials given to CopyStorm do not have permission to see the column. It is common for a person so assume that a Salesforce Admin user can see everything — unfortunately this assumption is commonly wrong.
When the backup is missing a table then it either has been explicitly excluded in CopyStorm or the Salesforce credentials given to CopyStorm do not have permission to see the table. Include the table and/or change permissions then then table will appear in the backup.
This root cause to this problem is almost always one of two issues:
The XYZ column is a formula. Formula columns are not updated on a record unless a non-formula column changes because CopyStorm relies on record timestamps to efficiently perform incremental backups and timestamps do not change when a formula value changes. If you want specific formula columns to always match Salesforce then use the CopyStorm/Medic Refresh Columns tool periodically to update formula columns.
The permissions on column XYZ were changed to make it visible. When CopyStorm first sees a column it assumes that it is a brand new column and creates a corresponding column in the backup database. As a new column, any values for the column are then picked up an incremental backup. If column XYZ is not really a new column but rather a column newly made visible then older records containing XYZ will have a null value until the timestamp on the containing record changes. The solution is to force an update on the problem column using the CopyStorm/Medic Refresh Columns tool.
The scheduler starts a second CopyStorm job at 12:30.
In practice this is unlikely to cause an issue because the second job will not catch up with the first job (e.g. the two jobs will never be operating on the same table at the same time by happenstance). However, this is a condition that is easily AND SHOULD BE avoided.
To prevent the same job running twice (or more times) is the flock command. The following script ensures that the CopyStorm job never runs twice at the same time:
If the script is run twice, the second script will wait (at the flock) command until the first script completes. Once the first invocation of the script completes, the flock command will return and the second invocation will continue.
The easiest way to prevent a job from running twice on Windows is to use the Windows scheduler. By default, the Windows Scheduler will not start a scheduled task again if a previous invocation is still running.
SELECT
CONVERT(
VARCHAR(MAX),
CAST(” AS XML).value(‘xs:base64Binary(sql:column(“Body”))’, ‘VARBINARY(MAX)’)
) AS RESULT
FROM
AttachmentSELECT
CAST(” AS XML).value(‘xs:base64Binary(sql:column(“Body”))’, ‘VARBINARY(MAX)’)
FROM
Attachment(
flock -x 9
sh /home/greg/bin/CopyStorm/CopyStorm.sh -run /home/greg/copyStormConfig/MyJob.copyStorm
) 9>/tmp/MyJob.lockStored in a text attribute named “Security Token”
A copy of the kpcli.pl Perl script (version 3.2) available here:
The Perl script is used for both Windows and Linux installations — the Windows-formatted exe will not work.
A Perl installation with all dependencies for kpcli installed.
Dependencies can be found at the kpcli homepage (http://kpcli.sourceforge.net/)
If kpcli.pl is installed correctly and the password entry path is correct, it will print the Salesforce credentials.
Restart the CopyStorm UI. Under the “Advanced Parameters” section of the Main tab, a “Credential Type” option of “Keepass” will appear:
Enter the KeePass file password and the path to the Salesforce user’s password entry:
Test the connection by pressing the “Test Salesforce Connection” button.
If the KeePass file password is incorrect, or if the kpcli.pl script is set up incorrectly, an error will appear which looks like:
If the Entry does not appear in the Keepass file, an error will appear which looks like:
perl /path/to/kpcli.pl -kdb /path/to/passwords.kdbx --command "show -f /password/entry"
For example, changing a VARCHAR to a CLOB.
A new Salesforce column or a length change to an existing column makes the database table “too wide” for the database.
This issue typically only arises in MySQL.
Solutions for this class of problems are discussed in the following sections.
A solution that almost always works for any database type is to DROP the problem table and let CopyStorm rebuild it from scratch. When a table is dropped in the database, CopyStorm will detect the change and automatically rebuild it.
There are two common ways to DROP a table. The simplest approach is to do one of:
Use your favorite SQL tool to run a “DROP TABLE tableName” command.
On the Database Reset section of the CopyStorm Configuration tab temporarily check the “Force Rebuild” option and run CopyStorm with only the problem table selected. CopyStorm will drop and rebuild the table when it runs.
The following approach is more complex but avoids re-downloading data from Salesforce:
Rename the table causing the ALTER issue.
Open CopyStorm and use it to recreate the problem table WITHOUT downloading any data. The procedure is:
Go to the Configuration tab.
Select just the problem table in the Core Configuration section.
Enter a date far into the future for the “Modified Since” value (e.g. 1/1/2150). This parameter can be found in the section.
Start the copy. CopyStorm will create the table but not transfer data.
Close CopyStorm without saving changes.
Copy the contents of the renamed table into the table just created by CopyStorm:
INSERT INTO tableName (fieldName1, fieldName2, …) SELECT fieldName1, fieldName2, … FROM RenamedTable
Drop the renamed table.
Oracle does not support directly changing a column type from VARCHAR2 to CLOB. Unfortunately, this operation is needed when a column in Salesforce increases length to an amount not supported by an Oracle VARCHAR2 column.
To fix this problem, you can rebuild the problem column by hand.
For example, suppose that the column Account.myField__c has increased in length from 2000 to 8000. To hold values in Oracle the corresponding column in Oracle needs to change from VARCHAR2 to CLOB. The following SQL statements will make this happen:
ALTER TABLE Account ADD scratch CLOB NULL
UPDATE Account SET scratch=myField__c
ALTER TABLE Account DROP COLUMN myField__c
ALTER TABLE Account RENAME COLUMN scratch TO myField__c
MySQL has a unique design property among databases that can cause issues when backing up Salesforce: A table cannot be declared wider than the database page size.
When a new column is added in Salesforce or a column’s length is increased, MySQL sometimes reports a “Row Size Too Large” error when increasing a column size or adding a column would push a table beyond the maximum database page size.
Any solution that backs up all record data involves changing the data type of some VARCHAR columns to TEXT. This works because TEXT columns take less space in a table row than VARCHAR types because TEXT column data is not stored within a table row.
The easiest solution is to drop the table and let CopyStorm rebuild it.
Starting with CopyStorm version 7.37.10, CopyStorm will automatically store “enough” VARCHAR columns as TEXT to make the table row size small enough.
In earlier CopyStorm versions, the parameter “Max Varchar” on the Configuration tab can be adjusted until table creation works.
“Max Varchar” determines the largest string that will be stored as a VARCHAR, larger strings will be stored as TEXT.
This parameter can be found in the configuration section.
An alternate solution is to change some of the longer columns in your table from VARCHAR to TEXT:
ALTER TABLE myTable__c MODIFY myColumn__c LONGTEXT CHARACTER SET utf8
Approve or Disapprove of the changes.
Approving the changes will cause CopyStorm to execute all upgrade SQL.
Disapproving the changes will cause CopyStorm to terminate.
Note: By default, CopyStorm automatically applies the upgrades.
View the progress of the approved changes.
CopyStorm offers users the ability to view details about an individual internal schema upgrade.
Users have the ability to see:
Schema Upgrade Description
High level information about the purpose of the upgrade.
SQLassociated with the Schema Upgrade
This provides users with the ability to copy & run the SQL manually.
Note: For some upgrades, SQL can also be generated dynamically by CopyStorm. In these cases, it is not appropriate to run upgrade SQL manually. Please contact support@capstorm.com before proceeding to run any upgrade SQL manually.
*Note:*The Schema Upgrade shown in the above screenshots are for an update to introduce support for off-database partitions. To learn more about how off-database partitions work, refer to the documentation.
When Schema Upgrades are not approved, the following dialog will be shown:
From this point, users have the options to:
Exit
Terminate the CopyStorm application
Cancel
Return to the Schema Upgrade Notice Dialog

Setup
3
In this step CopyStorm reads Salesforce table definitions for all tables being backed up. By default it takes a single API call per 100 tables.
Backup
1 * Number of Tables
CopyStorm uses at least 1 API call for each Salesforce table in the backup set. If there are no records to be backed up or if there are fewer than 2000 records to be backed up then this is the only API call used.
The number of records that can be read per API call varies by table in Salesforce. For most tables, between 1000 and 2000 can be returned for each API call. However, there are a few tables that return a single record per API call. This includes:
Attachment
ContentVersion
EventLogFile
For example:
A frequent incremental CopyStorm backup of 100 tables that includes Attachments would usually take a number of API calls equal to:
3 + 3 + 99 + The Number of Changed Attachments
Bootstrap
3
There are several operations that take place each time CopyStorm connects to Salesforce:
Find the name of all visible tables in Salesforce (1 API Call)
Cache the definition of the User and Profile tables (1 API Call)
Read the User record for the current User (1 API Call)
Configure Mutual Authentication, including a Digital Signature and appropriate OAuth Scopes.
Update the Connected Application Policies to allow appropriate users to login to Salesforce.
OAUTH logins can be enabled in CopyStorm by going to the Advanced Parameters dialog on the Main tab:
After selecting the Oauth 2.0 JWT login type, provide the credentials needed to authenticate with Salesforce:
Keystore
Yes
Path to a JKS or PKCS12 Keystore containing the private key used to sign JWT requests.
The generated SQL queries provided by CopyStorm should help you avoid a deep dive into a study of how to build an XML column query for your specific database type.
To practice this procedure see:
The How to Setup a Custom Snapshot tutorial
The reference page Column Expression Filter Rule.
To configure a TOTP Security Key in Salesforce:
Open the User Details page.
Click on the link to Connect a One-Time Password Authenticator.
Select “I Can’t Scan the QR Code”.
Copy the Key into CopyStorm.
Generate a Code in CopyStorm and paste it into Salesforce.
Click on the “Connect” button in Salesforce to complete the connection.
Save the CopyStorm Configuration File.
When connecting to Snowflake using the “private_key_file” and “private_key_file_pwd” parameters, Copystorm may report an error with the text:
PBES2 SecretKeyFactory not available
This error indicates that the certificate file is encrypted, and that the Java installation used by CopyStorm does not support the encryption used to secure the certificate file.
This is a known issue in the Snowflake driver (details can be found here) – with multiple possible solutions.
The simplest solutions are to:
Update the CopyStorm Java version to version 21 or later – Java 21 includes the required libraries.
Modifying the Private Key File to be unencrypted. While this is not advised due to security concerns, it will resolve the issue by bypassing the problem encryption logic.
A more complex solution is to:
Update CopyStorm with an encryption library that adds support for the encryption type.
The remainder of this article details the “complex solution” – integrating a third-party library with CopyStorm to enable the missing encryption algorithm. Instructions in this document are for the BouncyCastle security provider.
BouncyCastle is an open-source standard cryptographic library. It can be added to CopyStorm to enable support for additional encryption functions, including the PBES2 function that is missing in Java versions 20 and earlier. For more information about Bouncy Castle, please see .
To add the BouncyCastle PKIX library to CopyStorm, there are three steps:
Add the library JAR files to the CopyStorm lib/ directory.
Add a JVM argument in the CopyStorm.bat or CopyStorm.sh launch script.
Update the Java installation’s java.security file to enable BouncyCastle.
BouncyCastle jars can be downloaded here:
You will need to download two JAR files:
bcprov-jdk18on-[version].jar
bcpkix-jdk18on-[version].jar
To add the JARs to CopyStorm, copy them into the [CopyStorm]/lib/ directory.
The following JVM argument is added to the CopyStorm.bat or CopyStorm.sh script:
-Dnet.snowflake.jdbc.enableBouncycastle=TRUE
To add the parameter in Linux:
Modify this line of CopyStorm.sh:
“$JAVA” -Dcsapp.class=CopyStorm -jar “$MYROOT/lib/CapstormAppLoader.jar” “$@”
Adding the parameter:
“$JAVA” -Dnet.snowflake.jdbc.enableBouncycastle=TRUE -Dcsapp.class=CopyStorm -jar “$MYROOT/lib/CapstormAppLoader.jar” “$@”
To add the parameter in Windows:
Modify this line of CopyStorm.bat:
SET JVM_ARGS=
Adding the parameter:
SET JVM_ARGS=-Dnet.snowflake.jdbc.enableBouncycastle=TRUE
This step requires modifying the java.security file to add BouncyCastle support to Java.
The java.security file is located in the Java installation directory. For example, in the Windows release of CopyStorm, it can be found at:
[CopyStorm]/jre/conf/security/java.security
To add BouncyCastle:
Open the java.security file.
Find the lines that begin with “security.provider.”.
Add a new line to the end of the list.
The new line will look like:
Changes will take effect the next time CopyStorm is launched.
Close any running instances of CopyStorm.
Start a new CopyStorm instance by running the CopyStorm.bat or CopyStorm.sh script.
If your site is using a self-signed certificate to establish SSL (HTTPS) connections you may see an error like the following when attempting to connect to Salesforce:
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
... 26 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 32 moreThis type of error typically means that your network is using a self-signed certificate. To make CopyStorm (or any other Java based application) work with your certificate, you must add the certificate to Java’s trusted store file “cacerts”.
Open the “Help” menu in the top left of the application GUI and select the “Load Network Certificates” option:
This will open the “Certificate Viewer” popup where you can view, approve, or export the necessary certificates:
Approve the certificates by clicking the “Approve” button. This will create a keystore file called “CapStormKeyStore.jks” in the OR the current user’s home directory that will contain the approved certificates. CapStorm applications will use this keystore file for SSL traffic.
Get a copy of your certificate.
This will be a CER or CRT file (example: mycompany.crt).
Copy the certificate to the certificate directory in your CopyStorm installation:
[CopyStormRoot]/jre/lib/security
If your environment requires that multiple certificates be installed, you will need to import each certificate using a unique alias:
....\bin\keytool -import -keystore cacerts -file firstcertificate.crt -alias firstcertificate
....\bin\keytool -import -keystore cacerts -file secondcertificate.crt -alias secondcertificate
If you have encountered this problem, it is better in the long run to use a “cacerts” file for a Java runtime that is installed globally on your computer. The procedure is the same, but the “cacerts” file is in a different location. If you take this approach then remove the “jre” directory from CopyStorm and the application will use the system default Java.
Here is a with more details — please reference it if you need more help.
When metadata backup is enabled for CopyStorm a table named SFMetaFileProperties will be created in the target database to hold metadata backups. In addition a table named SFMetaFilePropertiesHistory will be created to hold past revisions of metadata.
The columns in SFMetaFileProperties mimic the FileProperties data structure returned from the Salesforce Metadata API:
id
The companion table “SFMetaFilePropertiesHistory” has the same structure as SFMetaFileProperties but with two additional columns:
It is doubtful that you will want to access these tables directly. However, CopyStorm’s companion product, CopyStorm/Restore, uses these tables to provide a metadata report experience that can be performed with surgical accuracy.
This article explains how Capstorm license management works and provides tips on diagnosing license management problems.
When a Capstorm product connects to Salesforce it also checks for a valid product license in the file “license.txt”. The “license.txt” file will be located in the same directory as the script used to launch the Capstorm product. If a license.txt file is not found or a valid non-expired license is not found in the file, the Capstorm product will issue a request to the Capstorm license service to retrieve (or generate) a license.
When issuing the license request to the Capstorm license server, the CapstormCustomerKey.txt file will be used to identify the installation. If the CapstormCustomerKey.txt file is not valid, a message indicating the issue will be shown.
If a Capstorm product fails to retrieve/generate a license it is usually because the connection is blocked by a firewall rule. Diagnosing and confirming this condition can be done using a web browser. Here’s how.
To retrieve or generate a license, a Capstorm product makes a https request in the following form:
Where:
salesforceOrgId is the full 18 character unique identifier of your Salesforce organization.
productName is the name of the product for which a license is desired.
productVersion is the version number of the product.
For example:
If the request is successful the license server will return a JSON string in the following form:
Information from the JSON string will be added to the product’s license.txt file.
If a firewall is blocking access to the Capstorm license server then pasting a license request into a browser will almost always provide a meaningful message. If you receive a “Connection Refused” response then a firewall is likely blocking access to license.capstorm.com. You need to tell your network administrator to open ports 80 and 443 to license.capstorm.com (75.2.67.235).
Here are a few URLs you can click on to test the connection to the license manager:
This article explains how CopyStorm optimally decides which records are copied from Salesforce.
CopyStorm’s default behavior is to perform an incremental copy from Salesforce every time it runs. There are no special parameters to set — just use the defaults and CopyStorm will incrementally update your Salesforce backup.
CopyStorm minimizes the number of records processed during each run by using record timestamps stored in the CopyStorm database from previous runs.
For example, if the most recent timestamp for an Account in the CopyStorm database is 14-Jul-2013 at 12:00:00.000 then there is no need to read records from Salesforce that were modified before this timestamp.
The following diagram illustrates how CopyStorm reads records for each selected table:
The details are a bit more complex than the above diagram — for example, records are not read one at a time in the code. However, this is the exact logical process followed by CopyStorm.
This section provides a bit more detail on exactly how timestamp values are used by CopyStorm. You do not need to grasp this section to understand how CopyStorm works.
Salesforce has an interesting quirk — records are not committed to a Salesforce database in timestamp order. The implications of this are:
At 13:01 a SOQL query indicates that there are 1000 records created earlier than 13:00.
At 13:02 the same SOQL query may indicate that there are 1001 records created earlier than 13:00.
It seems that records written to Salesforce “take a little while” to be committed to the database AND are committed in no particular order.
CopyStorm overcomes this Salesforce quirk using two parameters on the Advanced tab:
The SFDC Commit Latency parameter indicates how long to wait for Salesforce to commit records. The default is 300 seconds.
This means that, by default, CopyStorm will not read a record from Salesforce until it has a timestamp at least 300 seconds old.
The Timestamp Latency parameter indicates how many seconds to subtract from the most recent timestamp found in CopyStorm.
To sum up the details, the SOQL used by CopyStorm really looks like:
SELECT * FROM TT WHERE TT.systemmodstamp>=(MostRecent – “TimestampLatency”) AND TT.systemdstamp <=(CURRENT_TIME – “SFDC Commit Latency”)
In Salesforce a query of the form “SELECT * FROM TT” will often fail with a timeout error on large tables. To avoid this problem CopyStorm runs every SOQL query with a LIMIT. For most tables the LIMIT value is set to 20,000 — but is configured to be smaller for a handful of tables known to have problems with this high of a limit.
The default LIMIT value can be overridden on the Advanced tab using the “Row LIMIT per Query” option — however, changing this parameter generally results in non-optimal behavior.
In the case where all records in a batch have exactly the same timestamp, CopyStorm dynamically increases the LIMIT value until the end of records is reached or not all records have the same timestamp. When this type of adjustment is required it is rarely noticed unless a Salesforce table has 100,000’s of records with exactly the same timestamp.
If you would like to know about further Salesforce quirks CopyStorm has to manage (and be convinced that you don’t want to write your own CopyStorm) take a look at this blog post: .
CopyStorm supports reading Database credentials from a user-supplied Database password manager.
This feature was introduced to eliminate the need to:
Change the saved password in many CopyStorm configuration files.
Provide the password to CopyStorm on the command line due to security rules.
In addition to security benefits, this feature allows you to use your own company-wide password manager.
The process to add a new Database password manager to CopyStorm is to:
CopyStorm can be configured to provide a headless Salesforce backup by running in batch/background mode and leveraging the built-in scheduler on your computer. This article will show you how.
The base script used to launch the CopyStorm UI can also be used to start CopyStorm as a headless Salesforce backup application (required for a batch job). To configure the CopyStorm command line:
Save your CopyStorm configuration file using the “Encrypted” and “Save Passwords” options on the CopyStorm “Save As” dialog.
This will create a file named “MySettings.copyStorm” (using the name you choose for the file).
During the initial backup of Salesforce instances which include large numbers of old Tasks or Events, CopyStorm may experience repeated Salesforce timeout issues when running SOQL queries on these tables. This article explains approaches for solving these problems.
Once the initial backup of the Task and/or Event tables is complete, the Salesforce timeout issue goes away and the recommendations on this page are no longer needed.
Note that these recommendations apply to any Salesforce table, but this issue is rarely seen elsewhere.
Within the Salesforce infrastructure there are multiple levels of data storage — within this section we will refer to them as Tier-1, Tier-2, and Tier-3. Frequently used data (and most tables) tend to be kept in fast Tier-1 storage. Data in some tables (like Task) are migrated to slower storage as they age and are not queried by a user. Eventually most old Task records will be migrated into the slowest storage tier, Tier-3, and become fairly time consuming to query. When data has been migrated to Tier-3 storage, the only way to cause it to move back go faster storage is to attempt to read the Tier-3 data. When old data has been referenced enough times it will be “promoted” into faster storage — even old Task records can migrate from slow Tier-3 storage back to Tier-1 storage if they are referenced frequently.
When CopyStorm first attempts to backup the Task table it runs a query like:
SELECT * FROM Task ORDER BY SystemModStamp ASC LIMIT 20000
If you have a security gateway that manipulates XML returned from Salesforce before passing it along to CopyStorm, you may see a Salesforce SOAP Entity Not Recognized error like:
ConnectionException: Found invalid XML. could not resolve entity named ‘deg’ (position: START_TAG seen …1133;敌湈त 2;喚솕驘&# 20077;°… @122:9536)
This error means that your gateway has converted a standard XML character representation (e.g. “°”) into its equivalent HTML entity (in this case “°”). XML parsers are not required to understand the hundreds of entity tags used by HTML (and many, including the one used by the core WSC Salesforce libraries, do not).
Due to this issue, starting with version 8.37.1, CopyStorm has augmented the standard WSC parser to understand nearly all HTML entity tags. If you encounter an entity tag missed by CopyStorm, this article explains how to fix the issue.
To add a new entity to the core Salesforce XML parser:
The ID of this metadata record — unlike other IDs in Salesforce it is not guaranteed to be non-null OR unique. In short, internal Salesforce objects violate the normal non-null uniqueness rule.
metatype
The type of metadata in this record (e.g. CustomObject, ApexTrigger, etc…). Note that if a meta type is contained within another meta type (e.g. CustomField lives within CustomObject) then it will not have an entry in this table. The data will be contained in the parent record for the object.
fileName
The name of the file the metadata API requires for the record.
fullName
The full API name of the record.
manageableState
This field will contain “unmanaged” for types of metadata that can be redeployed.
namespacePrefix
For installed packages this contains the name of the package’s namespace.
metaxml
For records that require a companion “-meta.xml” this field contains the content.
content
The raw base64 encoded data for this meta record.
body
For records in UTF-8, contains the decoded value of the content column.
createdById
ID of the user in Salesforce who created this metadata record. NOTE: this value may be null.
createdByName
Name of the user in Salesforce who created this metadata record. NOTE: this value may be null.
createdDate
Timestamp of when the record was created.
lastModifiedById
ID of the user in Salesforce who last modified this metadata record. NOTE: this value may be null.
lastModifiedByName
Name of the user in Salesforce who last modified this metadata record. NOTE: this value may be null.
lastModifiedDate
Timestamp of when the record was last modified.
historyDate
Timestamp of when this history record was written. Older versions have older historyDate values.
version
The history date represented as the number of milliseconds since 1-Jan-1970.
Create a text file named “HTMLEntityResolver.xml”.
Put the following text into the file:
``
Add as many Entity tags as necessary. Each will either override or supplement the entity tags built into CopyStorm.
Put the file in the “config” subdirectory of the CopyStorm installation directory.
Finally, send an email to support@capstorm.com to tell us you had to add a new entity. We will add it to our built-in list.
Our standard list includes all of the entities defined on this Wiki page.
security.provider.N=org.bouncycastle.jce.provider.BouncyCastleProvider
Where N is the next sequential number.



Keystore Password
Yes
Password used to access the Keystore (blank if the Keystore does not have a password).
Key Alias
Yes
The name of the private key used to sign JWT requests.
Key Password
Yes
The password used to access the private key.
OAUTH Client Id
Yes
The Salesforce-generated Client Id for the Connected Application.
Username
Yes
The login Id of the CopyStorm Salesforce user.
Token Validity (minutes)
240
Yes
The lifetime of JWT access tokens. If the token expires during the CopyStorm run, CopyStorm will re-authenticate and get a new token.


















Navigate to the certificate directory in a shell (Linux) or command prompt (Windows) and run the command:
....\bin\keytool -import -keystore cacerts -file mycompany.crt
The tool will ask you for a password. It is “changeit”.
You’re done! CopyStorm will now connect to Salesforce without a PKIX error.


CopyStorm/PostgreSQL
CopyStorm/H2
CopyStorm/Restore
{“license”:{“id”:1,”ipAddress”:”38.114.70.254″,”licenseKey”:”2520b633-13fd-4488-800e-449526035835″,”product”:”CopyStorm/MySQL”,”version”:”Test”,”sfdcOrganization”:”CAPSTORMTEST000000″,”grantDate”:”2013-08-10″,”createdDate”:”2013-08-10″,”modifiedDate”:”2014-04-02″,”lock”:”q/nI2XtrIaof6u0CdEVSe28EDxjiUUW21uB8h9mpQfE\u003d”,”note”:””,”ipOrganization”:”Capstorm”,”ipDomain”:”wisperisp.com”,”ipCity”:”Edwardsville”,”ipCountry”:”United States”,”ipRegion”:”Illinois”},”successful”:true}CopyStorm/MySQL
CopyStorm/SQL Server
CopyStorm/Oracle
Write a Java class that extends the class com.aslan.sfdc.connect.credentials.AbstractJDBCUserPasswordCredentials
Package the new Java class in a jar and place it in the “lib” subdirectory of the CopyStorm installation.
Add a new CredentialsRegistry.xml file to CopyStorm’s config directory to register thenew credential manager with CopyStorm.
The Java class needs to extend com.aslan.sfdc.connect.credentials.AbstractJDBCUserPasswordCredentials, and will need to override/implement the following methods:
String getUsername()
Yes
Returns the username used when authenticating with the Database.
String getPassword()
Yes
In addition to the required methods above, there are several convenience methods which may be used by credential managers:
void fireCredentialsComplete(boolean complete)
Enables or disables the “Test Database Connection” button.
void addRowToUI(String label, String toltip, JComponent editor, JPanel panel, int row
Adds a new editor to the UI. This method can be used in the injectIntoUI() method to maintain consistent styling with the rest of the CopyStorm UI.
String encrypt(String text)
Click Here to view the Java source of Capstorm’s built-in Keepass Database password manager.
On Windows run the command:
CopyStorm.bat -run MySettings.copyStorm
On Linux or Mac run the command:
sh CopyStorm.sh -run MySettings.copyStorm
If the notification feature built into CopyStorm is used then this is likely the only command you will need.
There are a number of optional command line switches (documentation available here), but you do not need this information to go through the process in this article.
If you do not want to use CopyStorm’s built-in email notification or you want to be notified even when the CopyStorm program fails to start then you may want to use the CopyStorm Batch tab to build a starting script.
In practice, a script that does a bit more than run CopyStorm is often used for a batch job. In a typical batch job an organization wants to be notified if a CopyStorm job fails and many organizations also want to be notified any time CopyStorm runs. Though an organization is always free to write their own script for launching CopyStorm, the CopyStorm GUI has a built-in tool for creating a launch script. The generated launch script is often very close to what is desired:
The CopyStorm tool can create a launch script in a variety of scripting languages.
The generated launch script is readily customizable.
The script is easy to run as as a scheduled job under CRON or Windows Scheduler.
The Batch File tab on the CopyStorm GUI is used to create a script for launching a headless Salesforce backup, running CopyStorm as a batch job. Once the required parameters have been specified, press the “Generate Script” button to create a launch script and then press the “Save Script” button to save the script to disk.
Script Format
Yes
Indicates the scripting language to be used for the generated script. Options include:
bat — Windows BAT language.
vbs — Windows Visual Basic.
bash — Linux/Mac shell script.
python — The Python scripting language.
Most Linux or Mac computers manage scheduled jobs using the built-in cron tool. If the script that runs CopyStorm is called RunProductionCopyStorm.sh:
Run the command “crontab -e”
Add the following line to the crontab to run CopyStorm once a day at 17:00
0 17 * * * sh ~/RunProductionCopyStorm.sh
For additional information on the format of a crontab entry see the Wikipedia article on cron.
Here is an example crontab from one of Capstorm’s servers:
Scheduled jobs on Windows are usually managed using the Windows Scheduler. The following procedure will add a CopyStorm job using a script named RunProductionCopyStorm.vbs to the Windows Scheduler:
Find and Open the Windows Scheduler
Open the Create Basic Task Wizard
Follow the Create Basic Task Wizard Steps
The good news is that this problem tends to go away after the initial backup, because the Tasks that need to be backed up going forward are generally still in fast storage.
Note that each of the possible solutions on this page are one-time tasks that rarely have to be repeated.
If you ask Salesforce, they can increase the amount of time a query can run before timing out. Once Salesforce makes the change, update the “Max Timeout (seconds)” option in the “Advanced” popup on CopyStorm’s Main tab before restarting your backup job.
This solution increases the number of times CopyStorm will attempt to re-run a query if it times out. This usually works because repeatedly running the same query tends to force more data to migrate to faster storage tiers. This parameter is called “Reconnect Delay” and is located in the Salesforce Network configuration section of the CopyStorm Configuration tab.
Set the CopyStorm “Reconnect Delay” to a large value (20 or greater).
Select just the Task table.
Run CopyStorm.
This solution requires knowing the date of the earliest Task in your Salesforce instance. Once this date is known then use the “Modified Since” and “Modified Thru” CopyStorm options to backup a selected slice of Tasks.
For example, if the earliest Task has a SystemModStamp of 1-Feb-2000:
Go to the Configuration tab.
Select the Maintenance configuration section.
Set Modified Since to 2000-02-01T00:00:00.000Z
Set Modified Thru to 2001-02-01T00:00:00.000Z
Select just the Task table.
Run CopyStorm. It will only backup Tasks from the year 2000.
If the query still times out, then decrease the timebox.
Repeat the first four steps for the next timebox.
This solution performs a backup of Tasks based on the sort order of Task.Id rather than Task.SystemModStamp.
Here is the process when applied to the Task table (but the same process will work for any table):
Truncate the Task table.
Select only the Task table on the Configuration tab “Select Tables to Copy” section.
You can also type just “Task” into the input box rather than select it from the popup.
In the Maintenance configuration section of the Configuration tab, check the “Ignore Timestamps” option.
If you do not see this option then make sure that the “Advanced” Configuration Level is selected.
Run CopyStorm. This will backup records based on their unique Salesforce Id.
If Salesforce or the database fails during this procedure restart CopyStorm — it will continue backing up by Salesforce Id starting from where it last stopped.
Perform the following steps to get the CopyStorm database into a state where incremental timestamp-based updates will work going forward:
Uncheck the “Ignore Timestamps” option. This will cause CopyStorm to perform subsequent backups based on record timestamps.
Set the “Modified Since” parameter to LAST_WEEK (or any timestamp earlier than when you started this solution).
Run CopyStorm. This will back up all Task modifications that occurred while performing the Id-based backup.
After these steps are completed, CopyStorm will be able to perform subsequent backups using Salesforce timestamp data (e.g. CopyStorm backups will be incremental).
This articles explores situations where CopyStorm appears to miss an update or insert of a record from Salesforce and the solutions to correct the CopyStorm database. The root causes tend to be one of the following:
Salesforce permission changes altered what columns are visible to the credentials used when running CopyStorm.
Salesforce permission changes altered what records are visible to the credentials used when running CopyStorm.
There is a problem altering the CopyStorm schema to match Salesforce.
The “Salesforce believes in Time Travel” problem.
When CopyStorm discovers a new column from the Salesforce metadata it automatically creates the new column in the database and assumes that it must be a new column in Salesforce. Here is the scenario where changing Salesforce permissions make it look like CopyStorm missed updating column.
The Salesforce credentials used by CopyStorm do not have permission to see the column Contact.MyCustom__c.
On Monday the Contact table is backed up with CopyStorm.
On Tuesday morning an administrator changes permissions to allow the CopyStorm Salesforce account to see Contact.MyCustom__c
On Tuesday afternoon an incremental backup of the Contact table happens.
How do you fix this issue? There are two easy approaches:
Use CopyStorm/Medic’s tool.
Run CopyStorm with the following options:
Enter the name of the problem table in the Tables to Copy box.
Enable the Force Updates option.
Since CopyStorm can only backup Salesforce records it can see, if a Salesforce permission change makes new records available they normally will not be picked up until their timestamp changes. Here is how to make CopyStorm rescan all records in a table and pick up missing records.
Enter the name of the problem table in the Tables to Copy box.
Enter 1/1/1990 in the Modified Since option.
Run a Copy
CopyStorm will rescan all records and insert any missing records into the database.
If a field is altered or added in Salesforce and CopyStorm finds it impossible to make the same change to the database then CopyStorm will record an error and refuse to backup data to the table until the error is resolved.
The quickest way to fix this problem is:
Enter the name of the problem table in the Tables to Copy box.
Click on the Force Rebuild option.
Run a backup and CopyStorm will drop the problem table, recreate it, and then repopulate it with data from Salesforce.
If the quick fix is too drastic for your case, the see the article.
First, this problem does not occur unless CopyStorm internal parameters are modified but it is included in this article for completeness (and because it is rare condition that few people know about). The end of this section describes how to make it possible for the “Time Travel” issue to occur but you may have to wait months for it to happen!
CopyStorm achieves fast incremental backup of Salesforce by using the timestamp on Salesforce records. Logically CopyStorm does the following each time it runs:
Read the most recent timestamp from the CopyStorm database and call it “T”
Run SOQL that looks like: SELECT * FROM TableName WHERE timestamp >= T
The “Time Travel” problem is that Salesforce DOES NOT always commit records in timestamp order. This means that a record whose timestamp is 12:02 may show up in Salesforce BEFORE a record with a timestamp of 12:01. This does happen often but when it does it is likely that any program doing incremental copies based on a timestamp may:
Save all records modified at timestamp 12:02 or earlier in the first run MISSING the one record modified at 12:01.
Start searching for new records using timestamp 12:02 in the second run and NEVER SEE the 12:01 record.
Fortunately it is possible to pretend that Salesforce always writes records in timestamp order by not processing records that have been modified in the past 2 minutes. How did we pick 2 minutes? We worked with a lot of high volume sites and also simulated massive Salesforce loads that reproduced the problem.
Occasionally a person evaluating CopyStorm will decide that it is skipping a record when performing an experiment like:
Backup all Contacts
In Salesforce, modify a Contact.
Immediately run CopyStorm. It will copy no records because the change is less than 2 minutes old.
When the evaluator emails support@capstorm.com we point them to the original time travel post and suggest that they run CopyStorm again. Of course, it picks up the changed record the second time.
If you are doing CopyStorm work on a sandbox and are willing to live with the “time travel” problem you can tell CopyStorm to pretend that a safe amount of time to wait is 1 second. Here is how:
Select the section of the CopyStorm Configuration Tab.
Click on the Edit... button next to Internal Parameters.
Set SFDC Commit Latency and Timestamp Latency to 1.
The CopyStorm “Copying…” tab has real-time metrics which help identify a components that are limiting the speed of a database backup. The metrics, located in the lower right hand corner of a “Copying…” tab are described in this article.
There are two primary factors which limit the speed of a CopyStorm job:
The rate at which Salesforce delivers data to CopyStorm.
The rate at which the target database accepts data from CopyStorm.
Metrics highlighted in the following image provide data indicating which component is the bottleneck at your site:
Metrics are divided into three sections:
In a balanced system:
The “S” threads will be blinking blue almost all of the time.
This means that a steady stream of data is being delivered from Salesforce.
The “D” threads will be grey most of the time but blinking blue rapidly.
The data throughput values will be less than 50ms and the database write speed will be less than 20ms.
In a system where the database is the bottleneck:
The “S” threads will often turn grey.
The “D” threads will be blue most of the time.
The database write speed will be large.
This value is elapsed time for a single request to the database to write a block of records.
In a system where Salesforce is the bottleneck:
The “S” threads will be solid blue most of the time.
This means that they are waiting for a response from Salesforce.
The “D” threads will be grey most of the time.
The first data throughput number will be large.
The most common issue we see is that CopyStorm and the database are not in the same data center. The underlying issue is that the protocols used to talk to relational databases require close proximity between the application and the database for great performance. Until we discover a way to increase the speed of light, CopyStorm running in India and talking to a database in Canada will give slow performance. You can solve this problem by running CopyStorm and its corresponding database in the same data center.
CopyStorm will write data to a database as quickly as Salesforce delivers it. If the “S” threads are grey, the “D” threads are blue, the data throughput numbers are large, and you are sure that CopyStorm and the database are in the same data center; then the database is likely overloaded. Using system monitoring tools on the database computer will quickly pinpoint the issue — often the database computer will be page-faulting like crazy.
If the CopyStorm “S” threads are solid blue, the “D” threads are almost always grey, and the first data throughput number is large; then Salesforce is not delivering data rapidly. Even with a modest internet bandwidth of 20M/s, CopyStorm can easily transfer 20,000 – 30,000 accounts per minute. If you are sure that your available bandwidth is high then see your system administrators. There may be network software inspecting and slowing packets from Salesforce.
Though CopyStorm’s runtime requirements are modest, it cannot control demands made by other applications. Use a local system monitor to see which applications are using a high amount of CPU time. On a balanced system CopyStorm will always be consuming CPU — reading from Salesforce and writing to the target database.
To ensure seamless integration between CapStorm and Salesforce, you’ll need to configure a Salesforce Connected App.
This setup enables CapStorm to access Salesforce APIs and retrieve necessary data.
This guide walks you through the steps to configure a Connected App
and use it to see exact API responses from Salesforce, particularly for support purposes.
Log in to Salesforce with an administrator account.
Navigate to the Setup Menu:
Clear the “Modified Since” parameter.
Returns the password used when authenticating with the Database.
boolean setRequired(boolean required)
Yes
Update the credentials editor to indicate that the connection type does not require credential information (e.g. when using SQL/Server’s integrated security).
int injectIntoUI(JPanel panel, int startRow)
No
Adds any UI elements needed by the password manager to the CopyStorm UI.
boolean isAvailable()
No
Returns true if the password manager should appear as an option in the UI.
void saveState(Element e, boolean savePasswords)
Yes
Adds XML attributes to the provided Element to save any information needed to restore system state. This information is saved to CopyStorm’s configuration file.
void restoreState(Element e)
Yes
Restore XML state saved via saveState()
String getFingerprint()
Yes
Returns a value used to determine whether or not credentials have changed. This is used to determine whether or not a cached session may be used when connecting with the Database.
boolean isComplete()
Yes
Returns true when information provided by the user is enough to attempt a connection to the Database.
void clear()
Yes
Clears out any internal state kept by the password manager.
Encrypts text. This method can be used in the saveState() function to avoid implementing a custom encryption scheme to support encrypting saved passwords.
String decrypt(String encryptedText)
Decrypts text encrypted with encrypt(). This method can be used in the restoreState() function to avoid implementing a custom encryption scheme.
void saveXMLAttribute(Element e, String key, String value)
Adds a new attribute to an XML element. This method can be used in the saveState() function to avoid interacting with the Element directly.
String loadXMLAttribute(Element e, String key)
Retrieves an attribute to an XML element This method can be used in the restoreState() function to avoid interacting with the Element directly.
CopyStorm create the column Contact.MyCustom__c in the database.
The value for all modified records are backed up — including their value for Contact.MyCustom__c
On late Tuesday afternoon someone notices that not all records in CopyStorm have the correct value in the MyCustom__c record. All records with timestamps earlier than Tuesday afternoon seem to have the problem.
Enter 1/1/1990 in the Modified Since option.
Run a backup.










Memory Usage
84m/201m
These two numbers indicate:
The amount of virtual memory currently in use. In this example, 14 megabytes are in use.
The maximum amount of virtual memory used during this session. In this example, 201 megabytes is the maximum memory usage so far.
For example, if the “Destination Batch Size” is 100 and the database write speed is 4500ms then this means that the database is taking 4.5 seconds to write 100 records (e.g. terrible performance).
This number indicates how frequently a buffer is ready to be written to the database.
The second data throughput number will be small.
Read/Write Threads
S D
The “S” and “D” values indicate thread execution status:
“S”, “R”, and “B” threads read data from Salesforce.
“D” threads write data to the target database.
When a “S” thread is BLUE then it is either reading data from Salesforce or waiting for Salesforce to respond to a read request.
When a “D” thread is BLUE then it is writing data to the target database.
When either type of thread is GREY then it has nothing to do or is waiting for the other thread type to catch up.
Data Throughput
44ms/16ms

These two numbers indicate:
How frequently a write request is being sent to a “D” thread. In this example, 44ms means that a write request was sent to a “D” thread 44 milliseconds ago.
How quickly the database processed the most recent write operation. In this example, 16ms means that the last write to the database took 16 milliseconds.
Click on the gear icon (⚙️) in the upper right corner.
Select Setup.
Search for “App Manager” in the Quick Find box.
Create a New Connected App:
Click New Connected App.
Fill in the Connected App Details:
Connected App Name: Enter a descriptive name (e.g., “CapStorm Integration”).
API Name: This will auto-fill based on the name you enter.
Contact Email: Enter a valid email address for contact.
Configure OAuth Settings:
Check the Enable OAuth Settings box.
Callback URL: Enter https://localhost/callback (adjust based on your environment if needed).
OAuth Scopes: Select the appropriate scopes. For CapStorm, you’ll likely need:
Full Access (full)
Perform requests on your behalf at any time (refresh_token, offline_access)
Save the Connected App:
Click Save.
After saving, you’ll be redirected to the Connected App’s detail page where you can find the Consumer Key and Consumer Secret.
Make a note of these credentials.
Configure Additional Settings:
In the API (Enable OAuth Settings) section, adjust any additional settings as needed.
Open Postman and create a new collection named “CapStorm Connected App”.
Configure the Collection for OAuth 2.0:
Click on the collection name.
Go to the Authorization tab.
Set the Type to OAuth 2.0.
Scroll Down to Configure New Token.
Enter Token Request Details:
Token Name: Enter a descriptive name (e.g., “CapStorm Token”).
Grant Type: Set to Password Credentials.
Save and Obtain the Access Token:
Click Request Token to obtain an access token.
Once successful, click Use Token to apply it to your collection.
Test API Endpoints:
Use the access token to make API requests in Postman.
Verify that the requests are successful and review the responses.
Example ContentVersion Endpoint
Troubleshoot Common Issues:
Invalid Grant: Verify that the username, password, and security token are correctly concatenated.
Invalid Client ID: Ensure that the client_id and client_secret match those from the Connected App.
Enable OAuth Scopes: Ensure that all necessary OAuth scopes are enabled to provide CapStorm with the required permissions.
Callback URL: Adjust the callback URL based on your specific environment or testing setup.
Security Settings: If you encounter authentication issues, check the security settings and ensure that IP restrictions are configured correctly.
When Salesforce says your instance uses 4.2GB of table space and 100.8GB of file space, how much space should you allocate for your CopyStorm Salesforce backup database?
This is a harder question than it appears because Salesforce computes used space differently than databases. This article describes Capstorm’s guidelines for computing space requirements for CopyStorm databases.
Salesforce does not appear to count the cost of indexes when it reports used space. The space used by indexes can add up quickly in a relational database. For example, on SQL/Server we have learned:
The core indexes CopyStorm needs to work incrementally plus the primary key index take around 15.25MB per 100,000 table rows.
Each index on a reference field takes around 4.3MB per 100,000 table rows.
In practice, nearly all Salesforce tables contain at least two reference fields (CreatedById and LastModifiedById), and many also contain OwnerId. It is not uncommon for a table to contain 10 or more reference fields.
In summary, for every 100,000 rows you can expect to need at least this much space for indexes where is always at least 3 and usually much larger:
15.25M + *4.3MB
Once CopyStorm has built a schema and before any data has been copied, you can guess the amount of space required for indexes with a bit of SQL. Note: In each example, you must substitute “NumberOfRows” with the actual number of rows in Salesforce.
SQL/Server: SELECT ((SELECT (15.24 + (4.12*COUNT(*))) FROM CopyForceTableField WHERE tableName=’Account’ and fieldType=’reference’)*(NumberOfRows)/100000.0)
Oracle: SELECT ((SELECT (15.24 + (4.12*COUNT(*))) FROM CopyForceTableField WHERE tableName=’Account’ and fieldType=’reference’)*(NumberOfRows)/100000.0) FROM DUAL
PostgreSQL: SELECT ((SELECT (15.24 + (4.12*COUNT(*))) FROM CopyForceTableField WHERE tableName=’Account’ and fieldType=’reference’)*(NumberOfRows)/100000.0)
MySQL: SELECT ((SELECT (15.24 + (4.12*COUNT(*))) FROM CopyForceTableField WHERE tableName=’Account’ and fieldType=’reference’)*(NumberOfRows)/100000.0
Any table with a BASE64 column (for example, Attachment and ContentVersion) seem to report much less space usage in Salesforce than in a target database. Often 3-4x more space is needed in a relational database than what is reported in Salesforce.
We have never seen a case where 5x the size reported by Salesforce is too small but this may be overkill for your case. In most cases sizing the Salesforce backup database to be 4x the size of your file storage and 2x the size of your data storage will be sufficient.
For Salesforce sandbox: https://test.salesforce.com/services/oauth2/token
For Salesforce production: https://login.salesforce.com/services/oauth2/token
Client ID: Enter the Consumer Key from your Connected App.
Client Secret: Enter the Consumer Secret from your Connected App.
Username: Enter your Salesforce username.
Password: Enter your Salesforce password followed by your security token.
Client Authentication: Select Send client credentials in body.
CopyStorm supports reading Salesforce credentials from a user-supplied Salesforce password manager.
This feature was introduced when a customer had strict rules on password changes for service accounts in Salesforce and did not want to:
Change the saved password in many CopyStorm configuration files.
Provide the password to CopyStorm on the command line due to security rules.
Since this customer used their own company-wide password manager, an extension was added to CopyStorm to allow them to retrieve password information directly from their password manager instead of from CopyStorm configuration files or the command line.
This article describes how to add a new custom password manager to CopyStorm.
The process to add a new Salesforce password manager to CopyStorm is to:
Write a Java class that extends the class com.aslan.sfdc.connect.credentials.AbstractSalesforceUserPasswordCredentials.
Package the new Java class in a jar and place it in the “lib” subdirectory of the CopyStorm installation.
Add a new CredentialsRegistry.xml file to CopyStorm’s config directory to register the new credential manager with CopyStorm.
The Java class needs to extend com.aslan.sfdc.connect.credentials.AbstractSalesforceUserPasswordCredentials, and will need to override/implement the following methods:
In addition to the required methods above, there are several convenience methods which may be used by credential managers:
CopyStorm discovers all available Salesforce Password Managers by looking for a file named “CredentialsRegistry.xml” in the CopyStorm config directory.
The following CredentialsRegistry.xml file will load a new password manager named “Keyring”:
Click Here to view the Java source of Capstorm’s built-in Keepass Salesforce password manager.
By default, CopyStorm has a single snapshot policy named the Default Recycle Bin. The Default Recycle Bin is a regular snapshot policy, implemented using the same features available for custom snapshots, with a few limitations.
The name of the Default Recycle Bin cannot be changed.
The filter used by the Default Recycle Bin cannot be changed.
By default, the Default Recycle Bin is not enabled and you should make a few decisions before enabling it.
Do you want to restrict the tables where the recycle bin is used?
How many days do you want to keep records in the recycle bin?
Do you want to keep records from some tables longer than others?
Once you have made these decisions and applied them to the Default Recycle Bin, simply enable the snapshot and CopyStorm will automatically manage the Default Recycle Bin as part of a backup.
Prior to setting up our recycle bin, we have made the following choices. (Your criteria will likely be different!)
All tables except history and change event tables will be managed by the Default Recycle Bin.
The default retention period for a record will be 90 days (after 90 days a record will be deleted from the snapshot).
EmailMessages should be retained for a two full years.
Accounts, Contacts, and Cases should be retained for a full year.
Launch the Policy Editor for the Default Recycle Bin
Set a 90 Day Default Record Retention Policy
Add Custom Record Retention Rules
Select Tables to put in the Recycle Bin
There are two basic ways to select the tables to include in the Recycle bin.
A White List can be used to indicate the tables to include.
A Black List can be used to indicate the tables to exclude. All tables not on the black list will be included.
For additional help see the .
Activate the Default Recycle Bin
Congratulations! You have successfully setup the Default Recycle Bin.
String getUsername()
Yes
Returns the username used when authenticating with Salesforce.
String getPassword()
Yes
void fireCredentialsComplete(boolean complete)
Enables or disables the “Test Salesforce Connection” button.
void addRowToUI(String label, String toltip, JComponent editor, JPanel panel, int row
Adds a new editor to the UI. This method can be used in the injectIntoUI() method to maintain consistent styling with the rest of the CopyStorm UI.
String encrypt(String text)
<Credentials>
<CredentialType family="Salesforce" name="Keyring"
class="com.mycompany.copystorm.credentials.KeyringSalesforceCredentials"
/>
</Credentials>Returns the password used when authenticating with Salesforce.
String getSecurityToken()
Yes
Returns the security token used when authenticating with Salesforce.
int injectIntoUI(JPanel panel, int startRow)
No
Adds any UI elements needed by the password manager to the CopyStorm UI.
boolean isAvailable()
No
Returns true if the password manager should appear as an option in the UI.
void saveState(Element e, boolean savePasswords)
Yes
Adds XML attributes to the provided Element to save any information needed to restore system state. This information is saved to CopyStorm’s configuration file.
void restoreState(Element e)
Yes
Restore XML state saved via saveState()
String getFingerprint()
Yes
Returns a value used to determine whether or not credentials have changed. This is used to determine whether or not a cached session may be used when connecting with Salesforce.
boolean isComplete()
Yes
Returns true when information provided by the user is enough to attempt a connection to Salesforce.
void clear()
Yes
Clears out any internal state kept by the password manager.
Encrypts text. This method can be used in the saveState() function to avoid implementing a custom encryption scheme to support encrypting saved passwords.
String decrypt(String encryptedText)
Decrypts text encrypted with encrypt(). This method can be used in the restoreState() function to avoid implementing a custom encryption scheme.
void saveXMLAttribute(Element e, String key, String value)
Adds a new attribute to an XML element. This method can be used in the saveState() function to avoid interacting with the Element directly.
String loadXMLAttribute(Element e, String key)
Retrieves an attribute to an XML element This method can be used in the restoreState() function to avoid interacting with the Element directly.






Salesforce has a handful of tables that are almost certainly implemented as database Views internally within Salesforce. Some of the views are quite odd:
The ActivityHistory table combines data from the Task and Event table BUT cannot be queried directly using Salesforce APIs.
Though most Salesforce table views can be read directly, representing them as a view in the Salesforce backup database rather than including them as tables in the Salesforce data backup speeds up CopyStorm backup jobs and reduces the size of database files.
The following table contains links to SQL that can be used to create database views in your CopyStorm Salesforce backup that will mimic the corresponding Salesforce table views:
After creating the corresponding database view you will no longer need to include the table in your Salesforce backup, speeding up backup time and reducing storage costs.
ActivityHistory
ActivityHistoryView
AccountUserTerritory2View
AccountUserTerritory2View
Each time CopyStorm runs it records a variety of data into tables in the CopyStorm database:
A summary of records written to the database and any exceptions.
The content and structure of the tables will be familiar because they mimic what is displayed as progress within the CopyStorm GUI.
Changes to field values (see CopyForceFieldHistory in this article).
DDL statements (e.g. ALTER TABLE) that were issued against the CopyStorm database.
CopyStorm database logging tables were introduced starting with the 7.*.* version of CopyStorm.
The following tables are used for logging:
These logging tables are created automatically by CopyStorm. The only changes that should ever be performed by a customer is the deletion of log records — this should be done using .
The simplest way to view and manage CopyStorm log data is often the tool in CopyStorm/Medic.
The remainder of this article describes the column structure for each table.
The CopyForceJob table contains one record for each time CopyStorm successfully connects to Salesforce, connects to the target database, and starts a copy.
The table contains these columns:
The CopyForceJobTable table contains one record for each table that was modified during a CopyStorm run.
The table contains these columns:
The CopyForceJobException table contains one record for each exception that occurred during a CopyStorm run.
The table contains these columns:
The CopyForceDDLLog table contains a record of each DDL statement ran against the CopyStorm database.
The table contains these columns:
The CopyForceFieldHistory table records changes to field value. This table will be empty unless field history tracking is explicitly enabled.
History records will be maintained even if the referenced table / field is modified or deleted in Salesforce.
The table contains these columns:
The CopyForceMedicJob table contains one record for each time a CopyStorm/Medic job runs.
The table contains these columns:
The CopyForceMedicJobException table contains one record for each exception that occurred during a CopyStorm/Medic run.
The table contains these columns:
CopyForceJob
Contains a single record for each time CopyStorm runs.
CopyForceJobTable
Contains a single record for each table modified in a CopyStorm run.
CopyForceJobException
jobId
integer
Unique ID for this job. This value is the job’s primary key.
startTime
jobId
integer
The unique ID of the job that modified the table.
tableName
jobId
integer
The unique ID of the job where the exception occurred.
exceptionId
string
tableName
string
The name of the table addressed by the DDL statement.
command
string
id
string
The unique Salesforce record ID of the record that was the source of the data.
tableName
string
jobId
integer
The unique ID of the job.
startTime
jobId
integer
The unique ID of the job where the exception occurred.
exceptionId
integer
Contains a record of each exception (problem) encountered during a CopyStorm run.
CopyForceDDLLog
Contains a record of all DDL type statements issued against the database.
CopyForceFieldHistory
If field history tracking is enabled, this table will record the old and new value each time a field changes (except on record insert).
CopyForceMedicJob
Contains a single record for every time a CopyStorm/Medic job runs.
CopyForceMedicJobException
Contains a record of each exception (problem) encountered during a CopyStorm/Medic run.
timestamp
The time when the job started. Note that this time will be slightly after the start of the CopyStorm executable because it takes a few seconds for CopyStorm to initialize and connect to its data sources.
endTime
timestamp
The time when the job completed. This time is updated as each table finishes and after the entire job completes.
nCopied
integer
The total number of records copied to the target database.
nImagesCopied
integer
The total number of image records copied to the target database.
nImagesRead
integer
The total number of image records read from the target Salesforce Org.
nDeleted
integer
The total number of records deleted from the target database in accordance of the configured retention policies.
nFieldHistory
integer
The total number of field history records inserted into the target database.
nArchived
integer
The total number of record snapshots inserted into the target database via the Snapshot feature.
nTransactions
integer
The number of Salesforce transactions used during the run.
nExceptions
integer
The number of exceptions encountered during the run. If this value is non-zero then details for each exception will be recorded in the CopyStormJobException table.
configFileName
string
The base name of the CopyStorm configuration file used for the run. This value will be NULL if there was no active configuration file.
configFileDir
string
The directory containing the CopyStorm configuration file used for the run.
copyStormVersion
string
The version of CopyStorm that created the log record (e.g. 7.34.1).
copyStormDir
string
The directory in which CopyStorm was installed when the job ran.
elapsedTime
float
The total number of seconds taken by the job to run.
processId
integer
The system process id for the CopyStorm process.
string
The Salesforce name of the modified table.
startTime
timestamp
The time when CopyStorm started processing the table.
endTime
timestamp
The time when CopyStorm finished processing the table.
startTimestamp
timestamp
The timestamp of the first record copied from Salesforce when CopyStorm started processing the table.
endTimestamp
timestamp
The timestamp of the last record read from Salesforce when CopyStorm finished processing the table.
nRead
integer
The total number of records read from Salesforce.
nCopied
integer
The number of records inserted or updated in the CopyStorm database.
nSkipped
integer
The number of records read from Salesforce and skipped because they were already up to date in the CopyStorm database.
nDeleted
integer
The number of records deleted from the CopyStorm database.
nImagesCopied
integer
The total number of image records copied to the target database table.
nImagesRead
integer
The total number of image records read from the target Salesforce Org.
nFieldHistory
integer
The total number of field history records inserted into the target database for this table.
nArchived
integer
The total number of record snapshots inserted into the target database for this table via the Snapshot feature.
nPerMinute
integer
The average number of records processed per minute.
elapsedTime
float
The total number of seconds used to process the table.
startSize
integer
The size of the table in bytes when CopyStorm started processing the table.
endSize
integer
The size of the table in bytes when CopyStorm finished processing the table.
Order in which the exception occurred (starting at 0).
tableName
string
The name of the table being processed when the exception occurred.
message
string
A short message describing the exception.
traceback
string
The full traceback from the exception.
exceptionTime
timestamp
The time when the exception occurred.
The full DDL command.
traceback
string
If the DDL command failed, this field contains the full traceback from CopyStorm.
applyDate
timestamp
The date on which the DDL was executed.
The Salesforce API table name.
fieldName
string
The Salesforce API field name.
oldValue
string
The value of the field before it was updated.
newValue
string
The updated value of the field.
lastModifiedById
string
The unique Salesforce ID of the User that last modified the record.
lastModifiedDate
timestamp
The date on which the record was last modified.
createdDate
timestamp
The date on which the history record was created.
timestamp
The time when the CopyStorm/Medic job started.
endTime
timestamp
The time when the CopyStorm/Medic job finished.
elapsedTime
float
The total number of seconds that the job ran.
nTransactions
integer
The number of Salesforce transactions used by the job.
nExceptions
integer
The number of Exceptions (problems) reported by the job.
configFileName
string
The name of the configuration file used to start the job.
configFileDir
string
The path to the configuration file used to start the job.
medicVersion
string
The CopyStorm/Medic application version.
processId
integer
The system process id for the CopyStorm/Medic process.
toolName
string
The medic tool ran by the job. This corresponds to the value provided on the -tool command line switch.
status
string
The job status – one of Pending, Running, Cancelled, Finished, or Error.
output
CLOB
The job’s output. The format of this field will depend on the type of job that was ran.
Order in which the exception occurred (starting at 0).
message
string
A short message describing the exception.
traceback
string
The full traceback from the exception.
exceptionTime
timestamp
The time when the exception occurred.
CopyStorm stores all snapshot data in the following database tables.
CopyForceArchiveToken
Mapping from string names to integer tokens. The table is used to minimize the size of other tables.
CopyForceArchiveFilter
The following diagram illustrates the relationships between the various tables.
Note: All physical database tables are prefixed with “CopyForce”.
A CopyForceArchiveFilter describes the implementation of Java class which can determine if records should be snapshot. These classes are built into the CopyStorm Snapshot subsystem and include:
Deleted Records — determine if a record has been deleted in Salesforce.
Column Expression — evaluation of a user supplied expression to determine if a record matches.
All Changes — indicate if a record matches if it has any changes.
SQL Predicate — use a bit of user supplied SQL to determine if a record matches.
A CopyForceArchivePolicy record holds the definition for a CopyStorm Snapshot — if a record matches the rules for a CopyStormArchivePolicy then it will be written to the policy’s associated database storage.
The CopyForceArchivePolicyStat contains table level statistics about a CopyStorm Snapshot. Statistics about the tables contained in a CopyStorm Snapshot are maintained automatically while the record count statistics require a scheduled job.
The CopyForceArchiveRetentionRule table contains rules that override the default data retention rules for an archive for specific tables. For example:
The default retention rule for an archive is set to 30 days.
For the Account,Contact, and Case table use a override retention rule to keep them in the archive for 180 days.
The algorithm which determines the policy for a specific table always selects the matching rule with the longest number of days.
The CopyForceArchiveFieldSet table contains a unique configuration of the fields for a Saleforce table. When a record is snapshot:
If the current table field definitions have never been snapshot then create a record in the CopyForceArchiveFieldSet table*.*
Associate a CopyForceArchiveFieldSet with each snapshot record. This supports recovering both the schema and data for a snapshot record.
The fields in this type of record are represented as XML in the form below. Naturally, a complete record will contains many more fields and this is only a subset.
The CopyForceArchiveRecord table contains all snapshot records. Since it can grow quite large sites may consideration partitioning the table based on the policyId column.
CopyForceArchiveRecord field data can be read directly using the XML extensions for your database though most people will use SQL generated from the CopyStorm Snapshot Explorer tool rather than handcraft XML. However, if you are a master of XML and database then this section illustrates the format of a snapshot record. Note:
In the example code formula column values were excluded.
In the example fields with empty values were excluded.
The purpose of the CopyForceArchiveRecordRelat table is to support rapid traversal of relationships between snapshot records by avoiding scanning the XML to find relationships.
List of filter types that are used to determine if a record belongs in a snapshot.
CopyForceArchivePolicy
This the root table for each individual snapshot.
CopyForceArchivePolicyStat
Statistics about the data stored in each snapshot.
CopyForceArchiveRetentionRule
Rules which describe data retention rules for groups of tables within a snapshot. This table allows a single snapshot to support different retention policies for various tables.
CopyForceArchiveFieldSet
Description of the fields defined in Salesforce at the point a record was snapshot.
CopyForceArchiveRecord
Snapshot records. This is the primary storage table for each snapshot.
CopyForceArchiveRecordRelat
Relationships between record based on Salesforce references fields. The purpose of this table is to facilitate fast record relationship traversal without scanning the complete text of a snapshot record in the CopyForceArchiveRecord table.
Id
Integer
Unique Id assigned to the Name.
Name
String
Id
Integer
Unique internal id for the filter.
Name
String
Id
Integer
Unique internal id for the filter.
Name
PolicyId
Integer
Snapshot policy that owns the statistic
TableNameToken
Integer
Id
Integer
Unique id for the rule.
PolicyId
Integer
Id
Integer
Unique id for the field set.
TableName
String
<ArchiveFields table="Account" version="24MAY18">
<Field name="AccountNumber" label="Account Number" type="string" length="40" ndigits="0" scale="0" nameField="false" calculated="false" encrypted="false" custom="false"/>
<Field name="AccountSource" label="Account Source" type="picklist" length="40" ndigits="0" scale="0" nameField="false" calculated="false" encrypted="false" custom="false"/>
<Field name="Active__c" label="Active" type="boolean" length="0" ndigits="0" scale="0" nameField="false" calculated="false" encrypted="false" custom="true"/>
<Field name="CLS_Account_Reconcile__c" label="Account Reconcile" type="string" length="1300" ndigits="0" scale="0" nameField="false" calculated="true" formula="IF( RecordType.DeveloperName = 'Procurement_Supplier', 'ESP', 
IF( RecordType.DeveloperName = 'CLS_Customer_Account', 'CLS', 
IF( RecordType.DeveloperName = 'Global_Account', 'GLOBAL', 
IF( RecordType.DeveloperName = 'Supplier', 'SRM', 
'' 
))))" encrypted="false" custom="true"/>
</ArchiveFields>Id
Integer
Unique id for the snapshot record.
SalesforceId
String
<FieldData>
<Active__c>false</Active__c>
<BillingCity>Orlando</BillingCity>
<BillingCountry>Florida</BillingCountry>
<BillingPostalCode>L4B 1Y3</BillingPostalCode>
<BillingState>Orlando</BillingState>
<BillingStreet>Walt Disney Street</BillingStreet>
<CreatedById>0051a000000EVk1AAG</CreatedById>
<CreatedDate>2015-04-23T15:06:27.000Z</CreatedDate>
<Description>Walt Disney World is a leading entertainment destination.</Description>
<Id>0011a000003B7M2AAK</Id>
<Industry>Media</Industry>
<IsCustomerPortal>false</IsCustomerPortal>
<IsDeleted>false</IsDeleted>
<LastActivityDate>2015-04-22</LastActivityDate>
<LastModifiedById>0051a000000EVk1AAG</LastModifiedById>
<LastModifiedDate>2015-04-23T15:06:27.000Z</LastModifiedDate>
<Name>Walt Disney</Name>
<NumberOfEmployees>14668</NumberOfEmployees>
<OwnerId>0051a000000EVk1AAG</OwnerId>
<Phone>(905) 232-8888</Phone>
<SystemModstamp>2016-07-29T10:57:56.000Z</SystemModstamp>
<Type>Prospect</Type>
</FieldData>ArchiveRecordId
Integer
Id of the CopyForceArchiveRecord entry that contains the relationship.
ParentTableToken
String
Name of a table, field, etc. in Salesforce.
Name of the filter as presented to a user.
Description
String
Description of the filter.
ClassName
String
Name of a Java class that implements the filter. These classes are typically developed by Capstorm rather than customers.
CreatedDate
Timestamp
Timestamp of when the record was created.
ModifiedDate
Timestamp
Timestamp of the most recent modification to the record.
String
Name of the filter as presented to a user.
Description
String
Description of the policy.
FilterId
Integer
Id of the CopyForceArchiveFilter that will be used to determine if a record matches the policy.
Active
Boolean
True if the policy should be automatically evaluated during a CopyStorm backup.
IncludeFormulaFields
Boolean
True if formula field values should be stored in an archived record.
IncludeNullFields
Boolean
True if field with an empty (null) value should be explicitly stored in an archive record.
IncludedTables
Boolean
Comma separated list of table names and/or regular expressions for which this policy is applicable.
ExcludedTables
String
Comma separated list of tables and/or regular expressions that should be ignored by the policy. If the IncludedTables value is not blank then the ExcludedTables value is ignored.
ExcludedReferenceFields
String
Comma separated list of Salesforce reference field names that should be excluded from the CopyForceArchiveRecordRelat table. The primary reason to exclude a reference field is to save space.
Argument
String
Argument that will be passed to the corresponding ArchiveFilterId logic. For example, the Column Expression filter has a argument the represents the expression.
ArchiveAfterInsert
Boolean
If True and the policy is active then evaluate a record for potential snapshot by the policy immediately after it is inserted into CopyStorm.
ArchiveBeforeUpdate
Boolean
If True and the policy is active then evaluate a record for potential snapshot by the policy just before it is updated in CopyStorm.
ArchiveAfterUpdate
Boolean
If True and the policy is active then evaluate a record for potential snapshot by the policy just after it is updated in CopyStorm.
RetentionDays
Integer
Default number of days a record will be retained in the snapshot before it is deleted. If blank then records will be kept forever.
RetentionVersions
Integer
Maximum number of versions to keep for a record even when the default retention days has not been met.
CreatedDate
Timestamp
Timestamp of when the record was created.
ModifiedDate
Timestamp
Timestamp of the most recent modification to the record.
Table for which the statistic applies.
NumRecords
Integer
Number of table records in the snapshot (updated on demand).
FirstArchiveDate
Timestamp
Timestamp of the earliest record in the snapshot (updated on demand).
LastArchiveDate
Timestamp
Timestamp of the oldest record in the snapshot (updated on demand).
LastRetentionRunDate
Timestamp
Most recent date on which the policy’s record retention date rules were run.
NumRetentionDeleted
Integer
Number of records deleted from the snapshot during the most recent record retention policy run.
The archive policy that owns the rule.
RetentionDays
Integer
Number to retain records before they are deleted from the archive.
IncludedTables
String
Comma separated list of table names and/or regular expressions for which the retention rule applies.
API Name of the Salesforce table used to define the field set.
TableLabel
String
Label of the Salesforce table used to define the field set.
Fingerprint
String
Unique fingerprint for the field set. Used for rapid searching and duplicate detection.
Fields
XML
Simple XML document describing the fields in a table.
CreatedDate
Timestamp
Date on which the field set was created.
ModifiedDate
Timestamp
Date on which the field set was last updated.
Salesforce Id of the snapshot record.
Name
String
Value of the Salesforce Name field for the record. If a record does not contain a Name field then the table name is used.
TableNameToken
Integer
Internal Id used to lookup the name of the Salesforce table.
PolicyId
Integer
Internal Id of the snapshot policy which created the record.
FieldSetId
Integer
Internal Id of the field set definitions in place when the record was snapshot.
Fingerprint
String
Unique string used to rapidly avoid redundant snapshot records.
FieldData
XML
Simple XML document describing data in the record.
SystemModStamp
Timestamp
The Salesforce SystemModStamp when the record was snapshot. In the rare case where a record does not have a SystemModStamp column a different column with the same semantics is selected.
CreatedDate
Timestamp
The Salesforce CreatedDate when the record was snapshot. In the rare case where a record does not have a CreatedDate column a different column with the same semantics is selected.
ModifiedDate
Timestamp
The Salesforce ModifiedDate when the record was snapshot. In the rare case where a record does not have a ModifiedDate column a different column with the same semantics is selected.
ArchivedDate
Timestamp
The timestamp when the record was written to the snapshot (UTC).
Salesforce tokenized name of the table that owns the relationship. Example: Contact
ParentFieldToken
String
Salesforce tokenized name of the table column that owns the relationship. Example: AccountId (for relationship Contact.ParentId)
ParentId
String
Salesforce Id of the record that owns the relationships.
ReferenceTableToken
Integer
Salesforce tokenized name of the table pointed to by the relationship. Example: Account.
ReferenceId
Integer
Salesforce Id of the record the relationship is pointing to.
ArchivedDate
Timestamp
The timestamp when the record was written to the snapshot (UTC).

If a Salesforce instance contains extremely large Attachments (600MB – 2000MB), backing them up with CopyStorm may take a special approach. The reasons are rooted in the fact that none of the APIs provided by Salesforce provide a sufficient solution “out of the box”.
Fact 1: The Salesforce SOAP API returns attachment bodies as part of the SOAP XML envelope. This can cause two problems:
The SOAP envelope will cause large memory requirements for the XML parser. Increasing the maximum amount of memory allowed for CopyStorm will usually solve this problem.
If the SOAP envelope is too large to fit in a single string variable, the XML parser will suffer a fatal error. The largest string the XML parser can handle is 2GB and the string in a SOAP envelope can exceed this length.
Fact 2: The Salesforce REST API returns attachment bodies as hyperlinks to the body content. This approach minimizes the memory requirements for CopyStorm but has some downsides:
Salesforce throttles the retrieval of attachment bodies to 1MB per second AND limits the time of retrieval to 10 minutes. This means that attachments larger than roughly 600MB cannot be retrieved using the REST API under default Salesforce parameters.
There is a way to get around this issue but it requires a call to Salesforce support:
Call Salesforce and ask them to increase your Organization’s maximum timeout to a value that will allow your largest attachment to be read (at a rate of ~1MB per second).
In CopyStorm, backup massive Salesforce Attachments using the REST API.
The default is SOAP — it is generally faster.
The short answer is “Yes, CopyStorm backs up all Salesforce metadata.”
In Salesforce, metadata is stored in two different ways:
In Tables (SObject) — much of the key Salesforce metadata is stored in tables.
Examples include Apex Classes, Apex Pages, Apex Triggers, and Workflows/Processes
Not In Tables — this type of data is only accessible as zip archives via the Salesforce Metadata API.
CopyStorm backs up all metadata stored in Tables and, just as importantly, maintains revision history as the records change.
For example:
If an ApexClass changes, the old version of the class is saved in a field history tracking table.
If an ApexPage is deleted, the definition of the ApexPage just before it was deleted is saved in a field history tracking table.
Since metadata tables used by CopyStorm are defined by Salesforce’s ERD, the data in them is readily accessible within the CopyStorm database. For example, the definition of the ApexClass “MyFavoriteClass” can be found with the following SQL:
SELECT body FROM ApexClass WHERE name=”MyFavoriteClass”
Starting with CopyStorm 7.37.2, metadata accessible only via the Salesforce metadata API is backed up to the CopyStorm table SFMetaFileProperties and can be restored using CopyStorm/Restore.
The following table describes how Salesforce column data types are mapped to database data types:
The compound type ADDRESS is ignored but its data is picked up in component fields.
The compound type LOCATION is ignored but its data is picked up in its component Latitude and Longitude fields.
If the length of any string type column exceeds the “Maximum Varchar” parameter then its data type will be the same as used for BASE64 types.
For Oracle Only:
CopyStorm can be forced to use a VARCHAR2 rather than NVARCHAR2 by unchecking the “Use NVARCHAR2” option in the Advanced Database Options on the Advanced tab. When CopyStorm creates or modifies a column it chooses a VARCHAR2 or NVARCHAR2 Oracle data type based on the current setting of the “Use NVARCHAR2” option. Note: CopyStorm will not change the data type of an existing column unless the column’s length increases in Salesforce.
ANYTYPE
CLOB
TEXT
NCLOB
TEXT
NVARCHAR(MAX)
BASE64
CLOB
TEXT, MEDIUMTEXT, or LONGTEXT
CLOB
TEXT
VARCHAR(MAX)
BOOLEAN
BOOLEAN
BOOLEAN
DECIMAL(1)
BOOLEAN
BIT
COMBOBOX
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
CURRENCY
DECIMAL
DECIMAL
NUMBER
NUMERIC
DECIMAL
DATACATEGORYGROUPREFERENCE
CHAR
CHAR
CHAR
CHAR
CHAR
DATE
TIMESTAMP
DATE
DATE
DATE
DATE
DATETIME
TIMESTAMP
DATETIME
TIMESTAMP(3)
TIMESTAMP
DATETIME
DOUBLE
DECIMAL
DECIMAL
NUMBER
NUMERIC
DECIMAL
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
ENCRYPTEDSTRING
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
ID
CHAR
CHAR
CHAR
CHAR
CHAR
INT
INTEGER
INTEGER, DECIMAL, or BIGINT
NUMBER
INTEGER
INT or BIGINT
MULTIPICKLIST
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
PERCENT
DECIMAL
DECIMAL
NUMBER
NUMERIC
DECIMAL
PHONE
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
PICKLIST
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
REFERENCE
CHAR
CHAR
CHAR
CHAR
CHAR
STRING
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
TEXTAREA
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
TIME
TIME
DATETIME
TIMESTAMP(3)
TIME
DATETIME
URL
NVARCHAR
VARCHAR
NVARCHAR2
VARCHAR
NVARCHAR
CopyStorm supports the use of multiple running CopyStorm jobs to backup the same Salesforce instance to a Salesforce backup database, and there are some situations in which this can be preferable to a single job. For example:
A company has 20 CopyStorm Oracle tables that they want to be no more than 10 minutes behind the data in Salesforce. An incremental backup of all tables would take too long to allow a job to run every 10 minutes.
A company has a limited number of Salesforce API calls and does not want to accidentally use them all during the week. On the weekend they decide to backup the API-expensive tables (Attachment and ContentVersion).
While there is no practical limit to the number of CopyStorm jobs that can run at the same time while writing to the Salesforce backup database, there are a few restrictions:
Two CopyStorm jobs SHOULD NEVER be configured to backup the same table if they can run at the same time.
While this is unlikely to cause database issues, a lot of exceptions will likely be reported.
Salesforce will randomly kill a session if too many queries are active for an organization. This is a Salesforce governor limit and is typically around 20.
CopyStorm often generates longer running queries, so this has a material effect on how many CopyStorm jobs can be run at the same time on the same Salesforce organization.
One common good practice is to divide Salesforce tables into two groups:
Group A: Tables where it is important to keep the data in your database in near real-time sync with Salesforce.
Group B: All tables not in Group A.
The configuration file for Group A lists the tables to be backed up in the “Included Tables” section.
The configuration file for Group B leaves the “Include Tables” section blank and puts the tables from “Group A” in the “Excluded Tables” section.
The CopyStorm job for Group A is scheduled to run every 30 to 60 minutes. The CopyStorm job for Group B is scheduled to run every night or every weekend.
Since the tables in Group A and Group B do not overlap, it is safe to run both jobs at the same time.