Function SQL_Services(@Service, @Params) /*********************************************************************************************************************** This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written permission from SRP Computer Solutions, Inc.. Name : SQL_Services Description : Handler program for all module related services. Notes : The generic parameters should contain all the necessary information to process the services. Often this will be information like the data Record and Key ID. Parameters : Service [in] -- Name of the service being requested Param1-10 [in/out] -- Additional request parameter holders Response [out] -- Response to be sent back to the Controller (MCP) or requesting procedure History : (Date, Initials, Notes) 10/19/17 dmb v1.0.0 - Original programmer. 05/06/20 dmb v2.0.0 - Added GetDatabases, GetSchemas, and GetTables services. 05/09/20 dmb v2.0.0 - Changed GetSQLServer service to GetMappedSQLServer to use the same naming convention as other similar services. 05/09/20 dmb v2.0.0 - Decprecate the GetTableNames service. Use GetTables instead. 05/09/20 dmb v2.0.0 - Update GetTableColumns service to support Database and Schema arguments. Add logic to check the Table argument for other SQL objects. 05/09/20 dmb v2.0.0 - Remove all case conversions for SQL table names in all services. 05/11/20 dmb v2.0.0 - Update the GetMappedSQLColumnValues and GetMappedOIColumnValues services to support additional SQL data types and to use SRP_Date/SRP_DateTime/SRP_Time functions instead of Iconv/Oconv. 05/11/20 dmb v2.0.0 - Update GetSQLUpdateStatements service so secondary tables use the correct SQL syntax. 05/12/20 djs v2.0.0 - Update GetServers service to use new SERVERS table. Add CreateNewConnection, EditConnection, DeleteConnection, and SetConnectionDesc services. 05/12/20 dmb v2.0.0 - More updates to the GetSQLInsertStatements and GetSQLUpdateStatements services to improve handling of AMV mapping. 05/12/20 dmb v2.0.0 - Move transaction control out of the WriteDataRowToSQL and DeleteDataRowFromSQL services into the ExecuteQueries service so error trapping can determine if a COMMIT or ROLLBACK should be made. 05/13/20 dmb v2.0.0 - Update GetConnectionString service to use the SERVERS table. 05/13/20 dmb v2.0.0 - Remove deprecated LogConnectionActivity service. 05/14/20 dmb v2.0.0 - Update the ExecuteQueries service to ignore query statements that are empty. This will allow other query statements to be executed in the event of an accidental empty entry. 05/14/20 dmb v2.0.0 - Update the GetMappedSQLColumnValues service return the OI Key value correctly when working with AMV values greater than 1. 05/14/20 dmb v2.0.0 - Update the GetSQLUpdateStatements service to DELETE all secondary SQL table rows first and then INSERT rows as needed. This is necessary to keep the data in sync since AMV columns likely will not have a column that can be used as a secondary Key ID within the secondary SQL table. 06/03/20 dmb v2.0.0 - Update the GetSQLInsertStatements and GetSQLUpdateStatements services so that AMV master columns with actual data (rather than empty values) will generate a SQL statement. This fixes a problem where NULLs were attempted to be stored in a primary key column. 06/04/20 dmb v2.0.0 - Update the GetStaticSQLColumnNames and GetStaticSQLColumnValues services to support the new JSON structure. 06/05/20 dmb v2.0.0 - Update the GetDatabases service so system schemas are excluded. 06/06/20 dmb v2.0.0 - Improve error handling in the GetAllQueryDataRows service. 06/06/20 dmb v2.0.0 - Update the GetAllQueryDataRows service to check the EOF property of the RecordSet object before calling the GetString method. 06/06/20 dmb v2.0.0 - Update the GetSchemas service to see if the error returned from the ExecuteQuery service reports a permissions error. If so, ignore and clear the error. 06/08/20 dmb v2.0.0 - Change all references to information_schema to all caps to avoid case sensitivity issues. 06/08/20 dmb v2.0.0 - Update the GetDatabases service to see if the response from the ExecuteQuery service is "0". If so, then clear the response and set an error. 06/10/20 dmb v2.0.1 - Update the GetJoinedOIColumns service to assign to the ValuesReturned passed by reference argument whether an associated column should return its column data (default) or its index position. 06/10/20 dmb v2.0.1 - Update the GetMappedOIColumnNames to use the ValuesReturned argument that is assigned by the GetJoinedOIColumns service. This service will also assigned its own ValuesReturned passed by preference argument. 06/10/20 dmb v2.0.1 - Update the GetMappedSQLColumnValues to use the ValuesReturned argument that is assigned by the GetMappedOIColumnNames service. 06/10/20 dmb v2.0.1 - Change the Errors argument to ErrorList in the AddConnectionErrors service to avoid suspected VNAV warnings. 06/10/20 dmb v2.0.1 - Change the Desc argument to Description in the SetConnectionDesc service to avoid suspected VNAV warnings. 06/10/20 dmb v2.0.1 - Update the GetMappedSQLColumnNames service to better exclude SQL columns that are not mapped. 06/10/20 dmb v2.0.1 - Update the GetMappedOIColumnNames service to better exclude OI columns that are not mapped. 06/12/20 dmb v2.0.1 - Update the GetAMVMaster service to locate the AMV Master using the attributes of the join clause rather than the dedicated key/value pair. 06/12/20 dmb v2.0.1 - Update the GetSQLInsertStatements and GetSQLUpdateStatements services to use the updated GetAMVMaster service. 06/14/20 dmb v2.0.1 - Update the GetSQLInsertStatements and GetSQLUpdateStatements services to verify if any columns used in the join clause are not defined in the map. If so, then include these columns and their corresponding values in the Insert or Update statements. 06/14/20 dmb v2.0.1 - Fix bug in the GetMappedSQLColumnValues service to properly return the AMV index position if the value returned requested it. 06/14/20 dmb v2.0.1 - Added the GetJoinedSQLColumns service. 06/15/20 dmb v2.0.1 - Update the GetMappedSQLColumnValues service to support the bit SQL data type. 06/15/20 dmb v2.0.1 - Update the GetTableColumns service to use a SQL statement that also returns PK and Null constraints. 06/22/20 dmb v2.0.1 - Update the GetTableColumns service so the results are sorted by PK and then alphabetically. 06/22/20 dmb v2.0.1 - Update the GetTableColumns service to make a USE query if the database is known. 06/23/20 dmb v2.0.1 - Rename the GetJoinedSQLColumns service to GetMappedJoinedSQLColumns and update all calls to this service. 06/23/20 dmb v2.0.1 - Rename the GetJoinedSQLColumns service to GetMappedJoinedSQLColumnNames and update all calls to this service. 06/23/20 dmb v2.0.1 - Rename the GetJoinedOIColumns service to GetMappedJoinedOIColumnNames and update all calls to this service. 06/23/20 dmb v2.0.1 - Added the GetMappedJoinedSQLColumnValues service. 06/23/20 dmb v2.0.1 - Added the GetMappedJoinedOperators service. 06/23/20 dmb v2.0.1 - Major refactoring of all services that create SQL statements to better handle edge cases and joined columns. 06/24/20 dmb v2.0.1 - Fix memory leak in the GetMappedOIColumnNames service by releasing the MapObj object. 06/29/20 dmb v2.0.1 - Update the GetMappedSQLColumnValues service so that all errors are cleared once the column value is being calculated because any errors that are created must have come from a calculated column. This will avoid returning a number of values that differs from the number of column names. 07/10/20 dmb v2.0.1 - Update the GetMappedSQLColumnValues service to support the uniqueidentifier SQL data type. 07/10/20 dmb v2.0.1 - Udpate the GetMappedOIColumnNames and GetMappedSQLColumnNames services to support a ExcludeJoinedColumns flag rather than assume joined columns should always be excluded. 07/10/20 dmb v2.0.1 - Update the GetMappedOIColumnValues and GetMappedSQLColumnValues services to pass the ExcludeJoinedColumns flag to the GetMappedOIColumnNames and GetMappedSQLColumnNames services. 07/20/20 dmb v2.0.1 - Fix bug in the GetMappedJoinedSQLColumnValues service that attempted to convert an index value based on the data type. 07/20/20 dmb v2.0.1 - Fix bug in the WriteDataRowToSQL service to avoid VNAV error with the TransactionQueries variable. 07/31/20 dmb v2.0.2 - Fix bug in the GetSQLInsertStatements and GetSQLUpdateStatements services where maps to tables with no data columns would attempt to insert/update empty values in empty columns. 07/31/20 dmb v2.0.2 - Update the GetSQLUpdateStatements service to avoid creating an update state for primary tables that only have a join but no column maps. 08/13/20 djs v2.0.3 - Replaced CreateNewConnection service with CreateNewConnectionString and SaveConnectionString services. These new services allow multiple connections to the same SQL server (i.e. same SQL source, different user credentials and/or base catalog) to be stored under user defined Server ID key IDs. 08/14/20 djs - Created a new copy of SQL_Services (LSL2) from SQL_Services (SYSPROG). Added PostSQLRequest and ProcessSQLRequests services back into SQL_Services (LSL2), which are services that only exist in Infineon's copy of SQL_Services. These services add the ability to query SQL servers outside of the originating server's domain. Created SERVERS entries for all SQL Server connections currently in the APP_INFO table. 08/17/20 djs - Replaced all calls to SQL_Services_DJS (a temporary stored procedure that was utilized during the SQL_Services (SYSPROG) upgrade) throughout the LSL2 application with calls to SQL_Services. 08/17/20 dmb v2.0.7 - Update the GetMappedJoinedSQLColumnValues and GetMappedSQLColumnValues services to safety check integer and floating point numbers for empty and non-numeric values and convert to something other than an empty or unquoted string. 09/18/20 dmb v2.0.8 - Update the GetTables service to sort the results rather than rely upon SQL to return sorted results. 06/28/21 dmb v2.0.9 - Update the GetMappedSQLColumnNames and GetMappedSQLColumnValues services to compare the passed in SQL Table against the mapped SQL table in the JSON definition before accepting the current SQL Column. This resolves issues where one OI table with only MultiValue columns is mapped to two SQL tables. 02/12/2024 djm v2.0.10- Move Free_Class.Net(DotNetObj) in ExecuteQuery to avoid memory leak. ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler $insert LOGICAL $insert SERVICE_SETUP $insert SERVERS_EQUATES $insert MICROSOFT_ADO_EQUATES $insert DICT_EQUATES $insert SQL_REQUESTS_EQUATES $insert RLIST_EQUATES $insert REVDOTNETEQUATES Equ CRLF$ to \0D0A\ Equ COMMA$ to ',' Common /SQLServices/ ConnectionObjects@, Unused2@, Unused3@, Unused4@, Unused5@, Unused6@, Unused7@, Unused8@ Declare function Memory_Services, SQL_Services, Database_Services, SRP_JSON, SRP_Array, SRP_Hash, SRP_COM, SRP_Encode Declare function SRP_Date, SRP_DateTime, SRP_Time, Utility, Unicode_UTF8, Str_Unicode, GetTickCount, SRP_Decode Declare function SRP_List, Environment_Services, Logging_Services, Active_Directory_Services Declare subroutine Memory_Services, SQL_Services, Database_Services, SRP_JSON, SRP_Stopwatch, SRP_COM, SRP_List Declare subroutine GetTempPath, GetTempFileName, Sleepery, WinYield, Yield, RList, Set_Status, Logging_Services Declare subroutine Update_Index, obj_Notes UseRevDotNet = Database_Services('ReadDataRow', 'APP_INFO', 'USE_REVDOTNET') If UseRevDotNet EQ '' then UseRevDotNet = False$ LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\SQL_Services' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' SQL Services Log.csv' Headers = 'Logging DTM' : @FM : 'Error' objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Replication' LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Null Record Log.csv' Headers = 'Logging DTM' : @FM : 'Error' objNullLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM If ConnectionObjects@ EQ '' then ConnectionObjects@ = SRP_List('Create') GoToService else Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' module.') end Return Response OR '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Service Parameter Options //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Options BOOLEAN = True$, False$ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Services //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------------------------------------- // WriteDataRowToSQL // // OITableName - The name of the OpenInsight table that is mapped to the SQL table being written to. - [Required] // OIKeyID - The Key ID to the OpenInsight row being written to SQL. - [Required] // OIRow - The OpenInsight row being written to SQL. - [Required] // OIColumns - An @FM delimited list of OpenInsight table columns that should only be used to write to SQL. If empty, // all columns that have a map defintion will be used. - [Optional] // // High level services that writes OpenInsight data into a designated SQL table. This services calls other lower // level services as needed and assumes an OpenInsight to SQL map has already been created. //---------------------------------------------------------------------------------------------------------------------- Service WriteDataRowToSQL(OITableName, OIKeyID, OIRow, OIColumns) If (OITableName NE '') AND (OIKeyID NE '') AND (OIRow NE '') then // Create a new or get an existing Connection Object. SQLServer = SQL_Services('GetMappedSQLServer', OITableName) objConnection = SQL_Services('GetConnectionObject', SQLServer, 2) TransactionQueries = '' If Error_Services('NoError') then // Confirm if row already exists. This will determine if an INSERT or UPDATE should be made. PrimarySQLTableName = SQL_Services('GetPrimarySQLTable', OITableName) TransactionQueries = SQL_Services('GetSQLMergeStatements', OITableName, OIKeyID, OIRow, OIColumns) end If Error_Services('NoError') AND (TransactionQueries NE '') then // Process the tranaction queries. SQL_Services('ExecuteQueries', objConnection, TransactionQueries, True$, OITableName, OIKeyID) If Error_Services('HasError') then ErrorMessage = Error_Services('GetMessage') Error_Services('Clear') InsertError = IndexC(ErrorMessage, 'FOREIGN', 1) If InsertError then // Record may have been inserted in between the time this routine began and by the time the SQL // statement executed. Try an UPDATE statement instead. TransactionQueries = SQL_Services('GetSQLUpdateStatements', OITableName, OIKeyID, OIRow, OIColumns) If Error_Services('NoError') AND (TransactionQueries NE '') then SQL_Services('ExecuteQueries', objConnection, TransactionQueries, True$, OITableName, OIKeyID) end end else Error_Services('Add', ErrorMessage) end end end end else Error_Services('Add', 'The OITableName, OIKeyID, or OIRow argument was missing in the ' : Service : ' service.') end end service //---------------------------------------------------------------------------------------------------------------------- // DeleteDataRowFromSQL // // High level services that deletes data from a designated SQL table. This services calls other lower level services as // needed and assumes an OpenInsight to SQL map has already been created. //---------------------------------------------------------------------------------------------------------------------- Service DeleteDataRowFromSQL(OITableName, OIKeyID) If (OITableName NE '') AND (OIKeyID NE '') then // Create a new or get an existing Connection Object. SQLServer = SQL_Services('GetMappedSQLServer', OITableName) objConnection = SQL_Services('GetConnectionObject', SQLServer, 2) TransactionQueries = '' If Error_Services('NoError') then // Confirm if row already exists. This will determine if an INSERT or UPDATE should be made. PrimarySQLTableName = SQL_Services('GetPrimarySQLTable', OITableName) JoinClause = SQL_Services('GetJoinClause', OITableName, PrimarySQLTableName, OIKeyID, OIRow) SQLStatement = 'SELECT TOP 1 * FROM ' : PrimarySQLTablename : ' WHERE ' : JoinClause RowData = SQL_Services('ExecuteQuery', objConnection, SQLStatement, True$) If RowData NE '' then // Create the DELETE statements so the data in SQL is cleared out first. TransactionQueries = SQL_Services('GetSQLDeleteStatements', OITableName, OIKeyID) end end If Error_Services('NoError') AND (TransactionQueries NE '') then // Process the tranaction queries. SQL_Services('ExecuteQueries', objConnection, TransactionQueries, True$) end end else Error_Services('Add', 'The OITableName or OIKeyID argument was missing in the ' : Service : ' service.') end end service //---------------------------------------------------------------------------------------------------------------------- // ReadDataRowFromSQL // // High level services that reads data from a designated SQL table. This services calls other lower level services as // needed and assumes an OpenInsight to SQL map has already been created. //---------------------------------------------------------------------------------------------------------------------- Service ReadDataRowFromSQL(OITableName, OIKeyID) OIRow = '' If (OITableName NE '') AND (OIKeyID NE '') then // Create a new or get an existing Connection Object. SQLServer = SQL_Services('GetMappedSQLServer', OITableName) objConnection = SQL_Services('GetConnectionObject', SQLServer, 2) If Error_Services('NoError') then // Select the SQL data for the primary SQL table associated to the OpenInsight table. SQLTableName = SQL_Services('GetPrimarySQLTable', OITableName) SQLSelectStatement = SQL_Services('GetSQLSelectStatement', OITableName, SQLTableName, OIKeyID) SQLData = SQL_Services('ExecuteQuery', objConnection, SQLSelectStatement, True$) If (SQLData NE '') AND (Error_Services('NoError')) then OIRow = SQL_Services('GetMappedOIColumnValues', OITableName, SQLTableName, SQLData) end end If Error_Services('NoError') then // Select the SQL data for all secondary SQL tables associated to the OpenInsight table. SQLTableNames = SQL_Services('GetSecondarySQLTables', OITableName) If SQLTableNames NE '' then For Each SQLTableName in SQLTableNames using @FM SQLSelectStatement = SQL_Services('GetSQLSelectStatement', OITableName, SQLTableName, OIKeyID) // Create a new or get an existing Connection Object. SQLServer = SQL_Services('GetMappedSQLServer', OITableName) objConnection = SQL_Services('GetConnectionObject', SQLServer, 2) If Error_Services('NoError') AND (SQLSelectStatement NE '') then SQLData = SQL_Services('ExecuteQuery', objConnection, SQLSelectStatement, True$) If (SQLData NE '') AND (Error_Services('NoError')) then OIRow = SQL_Services('GetMappedOIColumnValues', OITableName, SQLTableName, SQLData, OIRow) end end While (Error_Services('NoError')) Next SQLTable end end end else Error_Services('Add', 'The OITableName or OIKeyID argument was missing in the ' : Service : ' service.') end Response = OIRow end service //---------------------------------------------------------------------------------------------------------------------- // GetRowCount // // Server - Name of the server the connection object is bound to. This should be the same name that will be used in // the Data Source connection string. // Table - SQL table whose row count is being requested. // // High level services that counts the number of rows in the designated table. This services calls other lower level // services. //---------------------------------------------------------------------------------------------------------------------- Service GetRowCount(Server, TableName) RowCount = '' If (Server NE '') AND (TableName NE '') then // Create a new or get an existing Connection Object. objConnection = SQL_Services('GetConnectionObject', Server, 2) If Error_Services('NoError') then // Select the SQL data for the primary SQL table associated to the OpenInsight table. ErrorMessage = '' SQLCountStatement = 'SELECT COUNT(*) FROM ' : TableName RowCount = SQL_Services('ExecuteQuery', objConnection, SQLCountStatement, True$) If Error_Services('HasError') then ErrorMessage = Error_Services('GetMessage') end SQL_Services('DestroyConnectionObject', objConnection) If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) end end else Error_Services('Add', 'The Server or TableName argument was missing in the ' : Service : ' service.') end Response = RowCount end service //---------------------------------------------------------------------------------------------------------------------- // GetDataRows // // Server - Name of the server the connection object is bound to. This should be the same name that // will be used in the Data Source connection string. // QueryStatement - Query command. This should be a properly syntaxed SQL statement. // // High level service that gets database rows from the indicated database using the indicated query statement. This // service will automatically get the connection and query object needed to perform the query statement. //---------------------------------------------------------------------------------------------------------------------- Service GetDataRows(Server, QueryStatement, AttemptsBeforeFailure) If AttemptsBeforeFailure EQ '' then AttemptsBeforeFailure = 1 DataRows = '' If ( (Server NE '') AND (QueryStatement NE '') ) then ErrorMessage = '' objConnection = SQL_Services('GetConnectionObject', Server, 2) If Error_Services('NoError') then If Error_Services('NoError') then DataRows = SQL_Services('ExecuteQuery', objConnection, QueryStatement, True$, AttemptsBeforeFailure) end // Get any errors from the GetConnectionObject service or the ExecuteQuery service. ErrorMessage = Error_Services('GetMessage') end SQL_Services('DestroyConnectionObject', objConnection) If ErrorMessage then Error_Services('Set', ErrorMessage) end else Error_Services('Add', 'Server or QueryStatement argument was missing in the ' : Service : 'service.') end Response = DataRows end service //---------------------------------------------------------------------------------------------------------------------- // GetConnectionObject // // Server - Name of the server the connection object is bound to. This should be the same name that // will be used in the Data Source connection string. // AttemptsBeforeFailure - Number of attempts to make the connect before erroring out. Default is 1. // // Returns a Connection Object based on the server. A returned Connection Object means that the server has been // successfully connected to with the provided credentials. This service uses caching, so until an existing Connection // Object has been destroyed (see the DestroyConnectionObject service), it will continue to use the one already in // existence. //---------------------------------------------------------------------------------------------------------------------- Service GetConnectionObject(Server, AttemptsBeforeFailure) If UseRevDotNet EQ False$ then If AttemptsBeforeFailure EQ '' then AttemptsBeforeFailure = 1 objConnection = '' // Check to see if the Connection Object already exists. ServiceKeyID := '*' : Server objConnection = Memory_Services('GetValue', ServiceKeyID) If objConnection EQ '' then If Server NE '' then Attempts = 0 Error = '' Loop If SRP_COM(objConnection, 'CREATE', 'ADODB.Connection') then Memory_Services('SetValue', objConnection : '*Server', Server) If SRP_COM('', 'ERROR') then Error = SRP_COM('', 'ERROR') SQL_Services('DestroyConnectionObject', objConnection) objConnection = '' end else ConnectionString = SQL_Services('GetConnectionString', Server) If Error_Services('NoError') then SRP_COM(objConnection, 'CALL', 'Open', ConnectionString) If SRP_COM('', 'ERROR') then Error = SRP_COM('', 'ERROR') SQL_Services('DestroyConnectionObject', objConnection) objConnection = '' end end else objConnection = '' end end end Attempts += 1 Until (objConnection NE '') OR (Attempts GE AttemptsBeforeFailure) Repeat If objConnection then Memory_Services('SetValue', ServiceKeyID, objConnection) end else If Error_Services('NoError') then // If no error message has been set then create a generic one. Error_Services('Add', 'Unable to create the connection object to ' : Server : ' in the ' : Service : ' service: ' : Error) end end end else Error_Services('Add', 'Server argument was missing from the ' : Service : ' service.') end end Response = objConnection end else If AttemptsBeforeFailure EQ '' then AttemptsBeforeFailure = 1 objConnection = '' // Check to see if the Connection Object already exists. ServiceKeyID := '*' : Server : '*objConnection' objConnection = Memory_Services('GetValue', ServiceKeyID) If objConnection EQ '' then If Server NE '' then Attempts = 0 Error = '' Loop // Define the .NET version DotNetHandle = StartDotNet("","4.0") DotNetDir = CheckDotNet('4.0'):'\' SqlClientDLLPath = DotNetDir:'System.Data.dll' ConnectionString = Sql_Services('GetConnectionString', Server) // Specify the DLL rv = Set_Property.NET(DotNetHandle, "AssemblyName", SqlClientDLLPath) // Define the classes objConnection = Create_Class.NET(DotNetHandle, "System.Data.SqlClient.SqlConnection", 0, ConnectionString, 'System.String') If Not(Get_Status(errCode)) then rv = Set_Property.NET(objConnection, 'Pooling', 'False') If Not(Get_Status(errCode)) then rv = Send_Message.Net(objConnection, "Open") If Not(Get_Status(errCode)) then ConnectionState = Get_Property.Net(objConnection, "State") If ConnectionState EQ 'Open' then ClientConnectionID = Get_Property.NET(objConnection, 'ClientConnectionId', False$) Memory_Services('SetValue', ClientConnectionID : '*Server', Server) end else Sql_Services('DestroyConnectionObject', objConnection) objConnection = '' end end else Sql_Services('DestroyConnectionObject', objConnection) objConnection = '' end end else Sql_Services('DestroyConnectionObject', objConnection) objConnection = '' end end Attempts += 1 Until (objConnection NE '') OR (Attempts GE AttemptsBeforeFailure) Repeat If objConnection and Error_Services('NoError') then Memory_Services('SetValue', ServiceKeyID, objConnection) ConnObjIndex = SRP_List('Add', ConnectionObjects@, objConnection) end else If Assigned(objConnection) then Free_Class.Net(objConnection) If Error_Services('NoError') then // If no error message has been set then create a generic one. Error_Services('Add', 'Unable to create the connection object to ' : Server : ' in the ' : Service : ' service: ' : Error) end end end else Error_Services('Add', 'Server argument was missing from the ' : Service : ' service.') end end Response = objConnection end end service //---------------------------------------------------------------------------------------------------------------------- // DestroyConnectionObject // // objConnection - Connection Object (see GetConnectionObject service.) // // Destroys the Connection Object. This returns True$ if successful, False$ if not. //---------------------------------------------------------------------------------------------------------------------- Service DestroyConnectionObject(objConnection) Destroyed = False$ ; // Assume object is not destroyed for now. If UseRevDotNet EQ False$ then If objConnection NE '' then Error = '' // Close the connection object, but don't worry about errors. It might have already been closed. SRP_COM(objConnection, 'CALL', 'Close') SRP_COM(objConnection, 'RELEASE') If SRP_COM('', 'ERROR') then Error = SRP_COM('', 'ERROR') end else Destroyed = True$ end If Destroyed then SQL_Services('ClearConnectionErrors', objConnection) Server = Memory_Services('GetValue', objConnection : '*Server') Memory_Services('SetValue', ServiceModule : '*GetConnectionObject*' : Server, '') end else SQL_Services('AddConnectionErrors', objConnection, Error) Error_Services('Add', 'Service : ' : Service : ', Error : ' : Error) end end else Error_Services('Add', 'The objConnection argument was missing in the ' : Service : ' service.') end end else If objConnection NE '' then ConnObjIndex = SRP_List('Locate', ConnectionObjects@, objConnection) If ConnObjIndex GT 0 then Error = '' ClientConnectionID = Get_Property.NET(objConnection, 'ClientConnectionId', False$) // Close the connection object, but don't worry about errors. It might have already been closed. Set_Status(0) Sql_Services('ClearConnectionErrors', objConnection) rv = Send_Message.Net(objConnection, 'Close') errCode = '' If Not(Get_Status(errCode)) then Server = Memory_Services('GetValue', ClientConnectionID : '*Server') MemKey = ServiceModule : '*GetConnectionObject*' : Server : '*objConnection' Memory_Services('SetValue', MemKey, '') SRP_List('RemoveAt', ConnectionObjects@, ConnObjIndex) Free_Class.Net(objConnection) end else Error = 'Error in service ':Service:'. Failed to close SQL connection. Error code: ':errCode Sql_Services('AddConnectionErrors', objConnection, Error) Error_Services('Add', 'Service : ' : Service : ', Error : ' : Error) end end end else Error_Services('Add', 'The objConnection argument was missing in the ' : Service : ' service.') end end Response = Destroyed end service //---------------------------------------------------------------------------------------------------------------------- // AddConnectionErrors // // objConnection - Connection Object (see GetConnectionObject service.) // ErrorList - @FM delimited list of errors. // // Adds a list of errors to the indicated Connection Object so the GetConnectionErrors service can retrieve them at // will. This list will accumulate until the ClearConnectionErrors service is called. //---------------------------------------------------------------------------------------------------------------------- Service AddConnectionErrors(objConnection, ErrorList) If UseRevDotNet EQ False$ then objConnection = objConnection[1, '*'] ServiceKeyID = ServiceModule : '*' : 'GetConnectionErrors' : '*' : objConnection ConnectionErrors = Memory_Services('GetValue', ServiceKeyID) If (objConnection NE '') AND (ErrorList NE '') then If ConnectionErrors NE '' then ConnectionErrors := @FM : ErrorList end else ConnectionErrors = ErrorList end Memory_Services('SetValue', ServiceKeyID, ConnectionErrors) end else Error_Services('Add', 'The objConnection or ErrorList argument was missing in the ' : Service : ' service.') end end else objConnection = objConnection[1, '*'] ClientConnectionID = Get_Property.NET(objConnection, 'ClientConnectionId', False$) ServiceKeyID = ServiceModule : '*' : 'GetConnectionErrors' : '*' : ClientConnectionID ConnectionErrors = Memory_Services('GetValue', ServiceKeyID) If (objConnection NE '') AND (ErrorList NE '') then If ConnectionErrors NE '' then ConnectionErrors := @FM : ErrorList end else ConnectionErrors = ErrorList end Memory_Services('SetValue', ServiceKeyID, ConnectionErrors) end else Error_Services('Add', 'The objConnection or ErrorList argument was missing in the ' : Service : ' service.') end end end service //---------------------------------------------------------------------------------------------------------------------- // GetConnectionErrors // // objConnection - Connection Object (see GetConnectionObject service.) // // Returns an @FM list of all connection errors associated with the indicated Connection Object. //---------------------------------------------------------------------------------------------------------------------- Service GetConnectionErrors(objConnection) If UseRevDotNet EQ False$ then objConnection = objConnection[1, '*'] ConnectionErrors = '' If objConnection NE '' then ServiceKeyID = ServiceModule : '*' : 'GetConnectionErrors' : '*' : objConnection ConnectionErrors = Memory_Services('GetValue', ServiceKeyID) end else Error_Services('Add', 'The objConnection argument was missing in the ' : Service : ' service.') end Response = ConnectionErrors end else objConnection = objConnection[1, '*'] ConnectionErrors = '' If objConnection NE '' then ClientConnectionID = Get_Property.NET(objConnection, 'ClientConnectionId', False$) ServiceKeyID = ServiceModule : '*' : 'GetConnectionErrors' : '*' : ClientConnectionID ConnectionErrors = Memory_Services('GetValue', ServiceKeyID) end else Error_Services('Add', 'The objConnection argument was missing in the ' : Service : ' service.') end Response = ConnectionErrors end end service //---------------------------------------------------------------------------------------------------------------------- // ClearConnectionErrors // // objConnection - Connection Object (see GetConnectionObject service.) // // Clears all connection errors associated with the indicated Connection Object. //---------------------------------------------------------------------------------------------------------------------- Service ClearConnectionErrors(objConnection) If UseRevDotNet EQ False$ then objConnection = objConnection[1, '*'] If objConnection NE '' then ServiceKeyID = ServiceModule : '*' : 'GetConnectionErrors' : '*' : objConnection Memory_Services('SetValue', ServiceKeyID, '') end else Error_Services('Add', 'The objConnection argument was missing in the ' : Service : ' service.') end end else objConnection = objConnection[1, '*'] If objConnection NE '' then ClientConnectionID = Get_Property.NET(objConnection, 'ClientConnectionId', False$) ServiceKeyID = ServiceModule : '*' : 'GetConnectionErrors' : '*' : ClientConnectionID Memory_Services('SetValue', ServiceKeyID, '') end else Error_Services('Add', 'The objConnection argument was missing in the ' : Service : ' service.') end end end service //---------------------------------------------------------------------------------------------------------------------- // HasConnectionErrors // // objConnection - Connection Object (see GetConnectionObject service.) // // Returns a Boolean flag indicating of the Connection Object has any connection errors. //---------------------------------------------------------------------------------------------------------------------- Service HasConnectionErrors(objConnection) objConnection = objConnection[1, '*'] HasErrors = False$ ; // Assume no errors for now. If objConnection NE '' then ConnectionErrors = SQL_Services('GetConnectionErrors', objConnection) If ConnectionErrors NE '' then HasErrors = True$ end else HasErrors = False$ end end else Error_Services('Add', 'The objConnection argument was missing in the ' : Service : ' service.') end Response = HasErrors end service //---------------------------------------------------------------------------------------------------------------------- // GetConnectionString // // Returns a well formed Connection String for the current server. This is used for ADO connections. //---------------------------------------------------------------------------------------------------------------------- Service GetConnectionString(Server) If UseRevDotNet EQ False$ then ServiceKeyID := '*' : Server ConnectionString = Memory_Services('GetValue', ServiceKeyID) If ConnectionString EQ '' then If (Server NE '') then ConnectionInfo = Database_Services('ReadDataRow', 'SERVERS', Server) If ConnectionInfo NE '' then Swap \0D0A\ with @FM in ConnectionInfo ConnectionString = ConnectionInfo<3> ConnectionString := ';' Memory_Services('SetValue', ServiceKeyID, ConnectionString) end else Error_Services('Add', Server : ' is not a valid server. [' : Service : ']') end end else Error_Services('Add', 'The Server argument was missing in the ' : Service : ' service.') end end Response = ConnectionString end else If (Server NE '') then // Prod Stealth ConnectionString = Database_Services('ReadDataRow', 'SERVERS', Server) If ConnectionString NE '' then ConnectionString = Delete(ConnectionString, 2, 0, 0) ProviderIdx = IndexC(ConnectionString, 'Provider', 1) If ProviderIdx then ConnectionString = ConnectionString[(ProviderIdx), 999] ProviderEndIdx = Index(ConnectionString, ';', 1) ConnectionString = ConnectionString[(ProviderEndIdx + 1), 999] end InitialIdx = IndexC(ConnectionString, 'Initial File Name', 1) If InitialIdx then InitialLen = Len(ConnectionString[InitialIdx, 'F;']) ConnectionString[InitialIdx, InitialLen + 1] = '' end DataSourceIdx = IndexC(ConnectionString, 'Data Source', 1) If DataSourceIdx then ConnectionString[DataSourceIdx + 12, 0] = 'tcp:' end TrustIdx = IndexC(ConnectionString, 'Trust Server Certificate', 1) If TrustIdx then TrustLen = Len(ConnectionString[TrustIdx, 'F;']) ConnectionString[TrustIdx, TrustLen + 1] = '' end AccessIdx = IndexC(ConnectionString, 'Access Token', 1) If AccessIdx then AccessLen = Len(ConnectionString[AccessIdx, 'F;']) ConnectionString[AccessIdx, AccessLen + 1] = '' end AuthIdx = IndexC(ConnectionString, 'Authentication', 1) If AuthIdx then AuthLen = Len(ConnectionString[AuthIdx, 'F;']) ConnectionString[AuthIdx, AuthLen + 1] = '' end SpnIdx = IndexC(ConnectionString, 'Server SPN', 1) If SpnIdx then SpnLen = Len(ConnectionString[SpnIdx, 'F;']) ConnectionString[SpnIdx, SpnLen + 1] = '' end If ConnectionString[-1, 1] EQ ';' then ConnectionString[-1, 1] = '' end else Error_Services('Add', Server : ' is not a valid server. [' : Service : ']') end end else Error_Services('Add', 'The Server argument was missing in the ' : Service : ' service.') end Response = ConnectionString end end service //---------------------------------------------------------------------------------------------------------------------- // ExecuteQuery // // objConnection - Connection Object (see GetConnectionObject service.) // QueryStatement - Query command. This should be a properly syntaxed SQL statement. // ReturnDataRows - Boolean flag to determine if all data rows resulting from the query should automatically be // returned. This is the same as if the caller used the GetAllQueryDataRows service, but this allows // everything to be done in one service rather than two. Default is False$ // // Executes the query against the Connection Object. If the ReturnDataRows argument is False$, then this returns True$ // if there are results, False$ if there are no results or if there is a problem running the services. Otherwise, the // datarows from the query will be returned unless there is an error. //---------------------------------------------------------------------------------------------------------------------- Service ExecuteQuery(objConnection, QueryStatement, ReturnDataRows=BOOLEAN, AttemptsBeforeFailure) If AttemptsBeforeFailure EQ '' then AttemptsBeforeFailure = 1 Results = False$ ; // Assume no results from this query for now. If ReturnDataRows NE True$ then ReturnDataRows = False$ ErrorMessage = '' If UseRevDotNet EQ False$ then If (objConnection NE '') AND (QueryStatement NE '') then Attempts = 0 ErrorMessage = '' Loop objRecordSet = SRP_COM(objConnection, 'CALL', 'Execute', QueryStatement) If SRP_COM('', 'ERROR') OR (objRecordSet EQ 0) then ErrorMessage = 'ADO error in the ' : Service : ' service: ' : SRP_COM('', 'ERROR') Results = '' ; // Since there is an error, no result should be returned. end else If ReturnDataRows then Results = SQL_Services('GetAllQueryDataRows', objRecordSet) end else Results = True$ end SRP_COM(objRecordSet, 'CALL', 'Cancel') SRP_COM(objRecordSet, 'RELEASE') end Attempts += 1 Until ( (ErrorMessage EQ '') OR (Attempts GE AttemptsBeforeFailure) ) Repeat end else Error_Services('Add', 'The objConnection or QueryStatement argument was missing in the ' : Service : ' service.') end end else If (objConnection NE '') AND (QueryStatement NE '') then Attempts = 0 ConnObjIndex = SRP_List('Locate', ConnectionObjects@, objConnection) If ConnObjIndex GT 0 then Loop objCommand = Send_Message.Net(objConnection, 'CreateCommand', '', '', 1) If Not(Get_Status(errCode)) then rv = Set_Property.NET(objCommand, 'CommandText', QueryStatement) If Not(Get_Status(errCode)) then If ReturnDataRows then objReader = Send_Message.Net(objCommand, 'ExecuteReader', '', '', 1) If Not(Get_Status(errCode)) then Reading = '' RowIndex = 0 Loop RowData = '' RowIndex += 1 Reading = Send_Message.Net(objReader, 'Read') Until ( (Reading EQ 'False') or (ErrorMessage NE '') ) If Not(Get_Status(errCode)) then NumCols = Get_Property.Net(objReader, 'FieldCount') If Not(Get_Status(errCode)) then For Col = 1 to NumCols DotNetObj = Send_Message.Net(objReader, 'GetValue', (Col - 1), 'System.Int32', 1) If Not(Get_Status(errCode)) then Result = Send_Message.Net(DotNetObj, 'ToString') If (Result EQ 'True' or Result EQ 'False') then DotNetObjType = Send_Message.Net(DotNetObj, 'GetType') If DotNetObjType EQ 'System.Boolean' then Swap 'True' with 1 in Result Swap 'False' with 0 in Result end end RowData<0, Col> = Result If Get_Status(errCode) then ErrorMessage = 'Error calling ToString method in the Object object in the ' : Service : ' service.' : errCode end end else ErrorMessage = 'Error calling GetValue method in the SqlDataReader object in the ' : Service : ' service.' : errCode end If Assigned(DotNetObj) then Free_Class.NET(DotNetObj) Until Error EQ True$ Next Col end else ErrorMessage = 'Error getting FieldCount property of the SqlDataReader in the ' : Service : ' service.' : errCode end end else ErrorMessage = 'Error calling Read method in the SqlDataReader object in the ' : Service : ' service.' : errCode end Results = RowData Repeat If Reading EQ 'False' and RowIndex EQ 1 then Results = '' ; // No results end else AccessError = (IndexC(errCode, 'not able to access the database', 1) GT 0) If Not(AccessError) then ErrorMessage = 'Error creating SqlDataReader object in the ' : Service : ' service.' : errCode end Swap @FM with @RM in Results Swap @VM with @FM in Results If Assigned(objReader) and (objReader NE '') then rv = Send_Message.Net(objReader, 'Close') Free_Class.NET(objReader) end end else objTransaction = Send_Message.Net(objConnection, 'BeginTransaction', '', '', 1) If Not(Get_Status(errCode)) then rv = Set_Property.NET(objCommand, 'Transaction', objTransaction) If Not(Get_Status(errCode)) then Results = Send_Message.Net(objCommand, "ExecuteScalar") If Not(Get_Status(errCode)) then rv = Send_Message.Net(objTransaction, 'Commit') If Get_Status(errCode) then AllAccepted = False$ ErrorMessage = 'Error committing transaction in the ' : Service : ' service.' : errCode end else Results = True$ end end else ErrorMessage = 'Failed to execute SQL command in the ' :Service : 'service.' : errCode end end else ErrorMessage = 'Unable to set Transaction property of the SqlCommand object in the ' : Service : ' service: ' : errCode end end else ErrorMessage = 'Unable to create the SQLTransaction object in the ' : Service : ' service: ' : errCode end end end else ErrorMessage = 'Unable to set CommandText property of the SQLCommand object in the ' : Service : ' service: ' : errCode end If Assigned(objTransaction) then Free_Class.NET(objTransaction) If Assigned(objCommand) then Free_Class.NET(objCommand) end else ErrorMessage = 'Unable to create the SQLCommand object in the ' : Service : ' service: ' : errCode end Attempts += 1 Until ( (ErrorMessage EQ '') or (Attempts GE AttemptsBeforeFailure) ) Repeat end else ErrorMessage = 'objCommand could not be found in the ' : Service : ' service.' end end else ErrorMessage = 'The objConnection or QueryStatement argument was missing in the ' : Service : ' service.' end If ErrorMessage NE '' then Results = '' LogData = '' LogData<1> = LoggingDTM LogData<2> = QueryStatement LogData<3> = ErrorMessage Logging_Services('AppendLog', objLog, LogData, @RM, @FM) Swap @FM with @VM in ErrorMessage Error_Services('Add', ErrorMessage) end end Response = Results end service //---------------------------------------------------------------------------------------------------------------------- // ExecuteQueries // // objConnection - Connection Object (see GetConnectionObject service.) // QueryStatements - @FM delimited list of Query commands. These should be a properly syntaxed SQL statement. // // Executes one or more queries against the Connection Object. This returns True$ if all queries processed without any // errors, False$ if there is a problem running any of the queries. //---------------------------------------------------------------------------------------------------------------------- Service ExecuteQueries(objConnection, QueryStatements, UseTransactionControl=BOOLEAN, OITableName, OIKeyID) If UseTransactionControl NE True$ then UseTransactionControl = False$ AllAccepted = True$ ; // Assume all queries were accepted for now unless otherwise proven. ErrorMessage = '' If UseRevDotNet EQ False$ then If (objConnection NE '') AND (QueryStatements NE '') then *Message = '1. Begin transaction processing.' ; GoSub WriteLog If UseTransactionControl EQ True$ then // Begin transaction processing. objRecordSet = SRP_COM(objConnection, 'CALL', 'Execute', 'BEGIN TRANSACTION') *Message = '2. Begin transaction processing.' ; GoSub WriteLog If SRP_COM('', 'ERROR') OR (objRecordSet EQ 0) then *Message = '3a. Begin transaction processing.' ; GoSub WriteLog Error_Services('Add', 'ADO error in the ' : Service : ' service: ' : SRP_COM('', 'ERROR')) end else *Message = '3b. Begin transaction processing.' ; GoSub WriteLog SRP_COM(objRecordSet, 'RELEASE') end end *Message = '4. Begin transaction processing.' ; GoSub WriteLog If Error_Services('NoError') then *Message = '5. Begin execute call.' ; GoSub WriteLog For Each QueryStatement in QueryStatements using @FM If QueryStatement NE '' then *Message = '6. Begin execute call.' ; GoSub WriteLog objRecordSet = SRP_COM(objConnection, 'CALL', 'Execute', QueryStatement) If SRP_COM('', 'ERROR') OR (objRecordSet EQ 0) then *Message = '7a. Begin execute call.' ; GoSub WriteLog Error_Services('Add', 'ADO error in the ' : Service : ' service: ' : SRP_COM('', 'ERROR')) AllAccepted = False$ end else *Message = '7b. Begin execute call.' ; GoSub WriteLog SRP_COM(objRecordSet, 'RELEASE') end end Until Error_Services('HasError') Next QueryStatement end *Message = '8. Begin execute call.' ; GoSub WriteLog If UseTransactionControl EQ True$ then // COMMIT or ROLLBACK the transaction. *Message = '9. Begin execute call.' ; GoSub WriteLog If Error_Services('NoError') then *Message = '10a. Begin execute call.' ; GoSub WriteLog objRecordSet = SRP_COM(objConnection, 'CALL', 'Execute', 'COMMIT TRANSACTION') end else *Message = '10b. Begin execute call.' ; GoSub WriteLog AllAccepted = False$ objRecordSet = SRP_COM(objConnection, 'CALL', 'Execute', 'ROLLBACK TRANSACTION') SRP_COM(objRecordSet, 'RELEASE') end *Message = '11. Begin execute call.' ; GoSub WriteLog SRP_COM(objRecordSet, 'RELEASE') end end else *Message = '12. All accepted not true.' ; GoSub WriteLog AllAccepted = False$ Error_Services('Add', 'The objConnection or QueryStatement argument was missing in the ' : Service : ' service.') end end else If (objConnection NE '') AND (QueryStatements NE '') then ConnObjIndex = SRP_List('Locate', ConnectionObjects@, objConnection) If ConnObjIndex GT 0 then objCommand = Send_Message.Net(objConnection, 'CreateCommand', '', '', 1) If Not(Get_Status(errCode)) then objTransaction = Send_Message.Net(objConnection, 'BeginTransaction', 'Test', 'System.String', 1) If Not(Get_Status(errCode)) then rv = Set_Property.NET(objCommand, 'Transaction', objTransaction) If Not(Get_Status(errCode)) then For Each QueryStatement in QueryStatements using @FM If QueryStatement NE '' then rv = Set_Property.Net(objCommand, 'CommandText', QueryStatement) If Not(Get_Status(errCode)) then rv = Send_Message.Net(objCommand, 'ExecuteNonQuery') If Get_Status(errCode) then ErrorMessage = 'Error executing command ':Quote(QueryStatement):' in the ' : Service : ' service.' : errCode end end else ErrorMessage = 'Error setting CommandText property of the SqlCommand object in the ' : Service : ' service.' : errCode end end Until ErrorMessage NE '' Next QueryStatement end else ErrorMessage = 'Unable to set Transaction property of the SqlCommand object in the ' : Service : ' service. ' : errCode end end else ErrorMessage = 'Unable to create the SQLTransaction object in the ' : Service : ' service. ' : errCode end end else ErrorMessage = 'Unable to create the SQLCommand object in the ' : Service : ' service. ' : errCode end If UseTransactionControl EQ True$ then // COMMIT or ROLLBACK the transaction. If ErrorMessage EQ '' then rv = Send_Message.Net(objTransaction, 'Commit') If Get_Status(errCode) then AllAccepted = False$ ErrorMessage = 'Error committing transaction in the ' : Service : ' service.' : errCode end end else AllAccepted = False$ rv = Send_Message.Net(objTransaction, 'Rollback') end end If Assigned(objTransaction) then Free_Class.NET(objTransaction) If Assigned(objCommand) then Free_Class.NET(objCommand) end end else AllAccepted = False$ ErrorMessage = 'The objConnection or QueryStatement argument was missing in the ' : Service : ' service.' end If ErrorMessage NE '' then LogData = '' LogData<1> = LoggingDTM LogData<2> = OITableName LogData<3> = OIKeyID LogData<4> = ErrorMessage Logging_Services('AppendLog', objLog, LogData, @RM, @FM) Swap @FM with ',' in ErrorMessage Error_Services('Add', ErrorMessage) end end Response = AllAccepted end service //---------------------------------------------------------------------------------------------------------------------- // GetAllQueryDataRows // // objRecordSet - RecordSet Object (see ExecuteQuery service.) // // Gets all of the data rows from the RecordSet Object. This returns an @RM array of data rows. //---------------------------------------------------------------------------------------------------------------------- Service GetAllQueryDataRows(objRecordSet) DataRows = '' If Len(objRecordSet) then BOF = SRP_COM(objRecordSet, 'GET', 'BOF') EOF = SRP_COM(objRecordSet, 'GET', 'EOF') If (EOF EQ False$) then DataRows = SRP_COM(objRecordSet, 'CALL', 'GetString', 2, -1, @FM, @RM) If SRP_COM('', 'ERROR') then Error = SRP_COM('', 'ERROR') Error_Services('Add', 'ADO error in the ' : Service : ' service: ' : SRP_COM('', 'ERROR')) end If Error_Services('NoError') then If DataRows[-1, 1] EQ @RM then DataRows[-1, 1] = '' If DataRows EQ objRecordSet then DataRows = '' Error_Services('Add', 'Unknown ADO error in the ' : Service : ' service.') end else If SRP_COM('', 'ERROR') then Error = SRP_COM('', 'ERROR') If IndexC(Error, 'current record has been deleted', 1) then DataRows = '' end else Error_Services('Add', 'ADO error in the ' : Service : ' service: ' : SRP_COM('', 'ERROR')) end end end end end end else Error_Services('Add', 'The objRecordSet argument was missing in the ' : Service : ' service.') end Response = DataRows end service //---------------------------------------------------------------------------------------------------------------------- // GetServers // // Returns an @FM list of database servers. //---------------------------------------------------------------------------------------------------------------------- Service GetServers() Servers = '' hServers = Database_Services('GetTableHandle', 'SERVERS') If Error_Services('NoError') then Select hServers EOF = False$ Loop Readnext ServerID else EOF = True$ Until EOF Servers := ServerID : @FM Repeat Servers[-1, 1] = '' Servers = SRP_Array('SortRows', Servers, 'AL1', 'LIST', @FM, @VM) end Response = Servers end service //---------------------------------------------------------------------------------------------------------------------- // SaveConnectionString // // ServerID - Key ID to a row in the SERVERS database table. // ConnectionString - SQL server connection string // // If a row in the SERVERS table with the key ServerID exists, updates the connection string, otherwise a new row // within the SERVERS database table containing ConnectionString. //---------------------------------------------------------------------------------------------------------------------- Service SaveConnectionString(ServerName, ConnectionString) If ServerName NE '' then ServerRec = Database_Services('ReadDataRow', 'SERVERS', ServerName) ServerRec = ConnectionString Database_Services('WriteDataRow', 'SERVERS', ServerName, ServerRec, True$, False$, True$) end else ErrorMsg = 'Error saving connection. Null server name passed in to the ' : Service : ' service.' Error_Services('Add', ErrorMsg) end end service //---------------------------------------------------------------------------------------------------------------------- // CreateNewConnectionString // // Utilizes the Windows Data Link Properties utility to create a new connection string. // Returns a field mark delimited array containing a suggested server name (the data source) and the connection string // generated by the Windows Data Link Properties utility. //---------------------------------------------------------------------------------------------------------------------- Service CreateNewConnectionString() Response = '' ServerName = '' ConnectionString = '' OleDBString = '' Filename = 'temp.udl' TempPath = Str(\00\, 1024) GetTempPath(Len(TempPath), TempPath) Convert \00\ to '' in TempPath TempFilename = Str(\00\, 1024) GetTempFileName(TempPath, \00\, 0, TempFilename) OSWrite OleDBString to TempFilename UDLFile = 'C:\Windows\syswow64\rundll32.exe "C:\Program Files (x86)\Common Files\System\Ole DB\oledb32.dll",OpenDSLFile ' : TempFilename Mode = '-1' ;* modal rv = Utility('RUNWIN', UDLFile, Mode) OSRead ConnectionString from TempFilename then If ConnectionString NE '' then Convert \FFFE\ to '' in ConnectionString ConnectionString = Unicode_UTF8(ConnectionString) DataSourcePos = Index(ConnectionString, 'Data Source', 1) ServerPos = Index(ConnectionString, 'Server', 1) Begin Case Case DataSourcePos ServerName = ConnectionString[(DataSourcePos + Len('Data Source') + 1), 'F;'] Case ServerPos ServerName = ConnectionString[(ServerPos + Len('Server') + 1), 'F;'] End Case end end Response = ServerName : @FM : ConnectionString end service //---------------------------------------------------------------------------------------------------------------------- // EditConnection // // ServerID - Key ID for the SERVERS database table. // // Utilizes the Windows Data Link Properties utility to edit the connection string found in the SERVERS record // associated with the ServerID key. //---------------------------------------------------------------------------------------------------------------------- Service EditConnection(ServerID) If ServerID NE '' then ServerRec = Database_Services('ReadDataRow', 'SERVERS', ServerID) If Error_Services('NoError') then ConnectionString = ServerRec TempPath = Str(\00\, 1024) GetTempPath(Len(TempPath), TempPath) TempFilename = Str(\00\, 1024) GetTempFileName(TempPath, \00\, 0, TempFilename) If ConnectionString NE '' then UnicodeString = \FFFE\ : Str_Unicode(ConnectionString) OSWrite UnicodeString To TempFilename end else OSWrite '' to TempFileName end Program = 'C:\Windows\syswow64\rundll32.exe "C:\Program Files (x86)\Common Files\System\Ole DB\oledb32.dll",OpenDSLFile ':TempFilename Mode = '-1' ;* modal rv = Utility("RUNWIN", Program, Mode) NewFile = '' OSRead NewConnectionString from TempFilename then Convert \FFFE\ to '' in NewConnectionString NewConnectionString = Unicode_UTF8(NewConnectionString) ServerRec = NewConnectionString Database_Services('WriteDataRow', 'SERVERS', ServerID, ServerRec, True$, False$, True$) end end end end service //---------------------------------------------------------------------------------------------------------------------- // DeleteConnection // // ServerID - Key ID for the SERVERS database table. // // Deletes the SERVERS record associated with the ServerID key. //---------------------------------------------------------------------------------------------------------------------- Service DeleteConnection(ServerID) If ServerID NE '' then Database_Services('DeleteDataRow', 'SERVERS', ServerID, True$) end end service //---------------------------------------------------------------------------------------------------------------------- // SetConnectionDesc // // ServerID - Key ID for the SERVERS database table. // Description - Description of the server connection // // Sets the DESCRIPTION column of the SERVERS record associated with the ServerID key. //---------------------------------------------------------------------------------------------------------------------- Service SetConnectionDesc(ServerID, Description) If ServerID NE '' then ServerRec = Database_Services('ReadDataRow', 'SERVERS', ServerID) ServerRec = Description Database_Services('WriteDataRow', 'SERVERS', ServerID, ServerRec) end end service //---------------------------------------------------------------------------------------------------------------------- // SetOITableToSQLMap // // TableName - OpenInsight table being mapped. - [Required] // SQLMap - JSON object containing the OI Table to SQL Map information. - [Required] // // Updates the stored JSON object that defines the mapping between the indicated OpenInsight table and the SQL table. //---------------------------------------------------------------------------------------------------------------------- Service SetOITableToSQLMap(TableName, SQLMap) Convert @Lower_Case to @Upper_Case in TableName ServiceKeyID = ServiceModule : '*' : 'GetOITableToSQLMap' : '*' : TableName If (TableName NE '') AND (SQLMap NE '') then Convert \0D0A\ to @FM in SQLMap ; // Makes it easier to inspect. The GetOITableToSQLMap service removes the @FMs. Database_Services('WriteDataRow', 'DICT.' : TableName, '%SQLMap%', SQLMap, True$) If Error_Services('NoError') then Convert @FM to '' in SQLMap Memory_Services('SetValue', ServiceKeyID, SQLMap) end end else Error_Services('Add', 'The TableName or SQLMap argument was missing in the ' : Service : ' service.') end end service //---------------------------------------------------------------------------------------------------------------------- // GetOITableToSQLMap // // TableName - OpenInsight table being mapped. - [Required] // // Returns JSON object that defines the mapping between the indicated OpenInsight table and the SQL table. //---------------------------------------------------------------------------------------------------------------------- Service GetOITableToSQLMap(TableName) Convert @Lower_Case to @Upper_Case in TableName ServiceKeyID := '*' : TableName OITableToSQLMap = Memory_Services('GetValue', ServiceKeyID) If OITableToSQLMap EQ '' then If TableName NE '' then OITableToSQLMap = Database_Services('ReadDataRow', 'DICT.' : TableName, '%SQLMap%') Convert @FM to '' in OITableToSQLMap If OITableToSQLMap NE '' then Memory_Services('SetValue', ServiceKeyID, OITableToSQLMap) end end else Error_Services('Add', 'The TableName argument was missing in the ' : Service : ' service.') end end Response = OITableToSQLMap end service //---------------------------------------------------------------------------------------------------------------------- // SetOIColumnToSQLMap // // TableName - OpenInsight table being mapped. - [Required] // ColumnName - Database column from the OpenInsight table. - [Required] // SQLMap - JSON object containing the OI Column to SQL Map information. - [Required] // // Updates the stored JSON object that defines the mapping between the indicated OpenInsight column and the SQL table. //---------------------------------------------------------------------------------------------------------------------- Service SetOIColumnToSQLMap(TableName, ColumnName, SQLMap) Convert @Lower_Case to @Upper_Case in TableName Convert @Lower_Case to @Upper_Case in ColumnName ServiceKeyID = ServiceModule : '*' : 'GetOIColumnToSQLMap' : '*' : TableName : '*' : ColumnName If (TableName NE '') AND (ColumnName NE '') AND (SQLMap NE '') then Convert @FM to '' in SQLMap Convert \0D0A\ to '' in SQLMap ColumnData = Database_Services('ReadDataRow', 'DICT.' : TableName, ColumnName) ColumnData = SQLMap Database_Services('WriteDataRow', 'DICT.' : TableName, ColumnName, ColumnData, True$) If Error_Services('NoError') then Memory_Services('SetValue', ServiceKeyID, SQLMap) end end else Error_Services('Add', 'The TableName, ColumnName, or SQLMap argument was missing in the ' : Service : ' service.') end end service //---------------------------------------------------------------------------------------------------------------------- // GetAllOIColumnToSQLMaps // // TableName - OpenInsight table being mapped. - [Required] // // Returns an @FM/@VM delimited array of all JSON objects that define the mapping being the table columns and their // respective SQL table columns. Columns with no maps will return an empty string for the JSON object. //---------------------------------------------------------------------------------------------------------------------- Service GetAllOIColumnToSQLMaps(TableName) Convert @Lower_Case to @Upper_Case in TableName ColumnSQLMaps = '' If TableName NE '' then FieldArray = Database_Services('ReadDataRow', 'DICT.' : TableName, '%FIELDS%') ColumnNames = FieldArray For Each ColumnName in ColumnNames using @VM SQLMap = SQL_Services('GetOIColumnToSQLMap', TableName, ColumnName) ColumnSQLMaps := ColumnName : @VM If SQLMap NE '' then ColumnSQLMaps := SQLMap end ColumnSQLMaps := @FM Next ColumnName ColumnSQLMaps[-1, 1] = '' end else Error_Services('Add', 'The TableName argument was missing in the ' : Service : ' service.') end Response = ColumnSQLMaps end service //---------------------------------------------------------------------------------------------------------------------- // GetOIColumnToSQLMap // // TableName - OpenInsight table being mapped. - [Required] // ColumnName - Database column from the OpenInsight table. - [Required] // // Returns JSON object that defines the mapping between the indicated OpenInsight table column and the SQL table column. //---------------------------------------------------------------------------------------------------------------------- Service GetOIColumnToSQLMap(TableName, ColumnName) Convert @Lower_Case to @Upper_Case in TableName Convert @Lower_Case to @Upper_Case in ColumnName ServiceKeyID := '*' : TableName : '*' : ColumnName OIColumnToSQLMap = Memory_Services('GetValue', ServiceKeyID) If OIColumnToSQLMap EQ '' then If (TableName NE '') AND (ColumnName NE '') then ColumnData = Database_Services('ReadDataRow', 'DICT.' : TableName, ColumnName) OIColumnToSQLMap = ColumnData If OIColumnToSQLMap NE '' then Memory_Services('SetValue', ServiceKeyID, OIColumnToSQLMap) end end else Error_Services('Add', 'The TableName or ColumnName argument was missing in the ' : Service : ' service.') end end Response = OIColumnToSQLMap end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedSQLServer // // Returns the name of the SQL Server that the indicated OpenInsight table is mapped to. //---------------------------------------------------------------------------------------------------------------------- Service GetMappedSQLServer(OITableName) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName SQLServer = Memory_Services('GetValue', ServiceKeyID) If SQLServer EQ '' then If OITableName NE '' then OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) If SRP_JSON(MapObj, 'PARSE', OITableToSQLMap) EQ '' then SQLServer = SRP_JSON(MapObj, 'GETVALUE', 'SQLServer.Name') SRP_JSON(MapObj, 'RELEASE') end If SQLServer NE '' then Memory_Services('SetValue', ServiceKeyID, SQLServer) end else Error_Services('Add', 'OITableName argument was missing in the ' : Service : ' service.') end end Response = SQLServer end service //---------------------------------------------------------------------------------------------------------------------- // GetDatabases // // objConnection - Connection Object (see GetConnectionObject service.) - [Optional, but Server is then Required] // Server - Name of a defined server. - [Optional, but objConnection is then Required] // // Returns an @FM list of databases available through the indicated connection object. If the connection object is // empty, then a new one will be created (and then subsequently destroyed) for the indicated server. //---------------------------------------------------------------------------------------------------------------------- Service GetDatabases(objConnection, Server) Databases = '' If (objConnection NE '') OR (Server NE '') then If objConnection EQ '' then objConnection = SQL_Services('GetConnectionObject', Server, 3) NewObject = True$ end else NewObject = False$ end If Error_Services('NoError') then SQLQuery = "SELECT name FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb')" Databases = SQL_Services('ExecuteQuery', objConnection, SQLQuery, True$) If Databases EQ 0 then Databases = '' Error_Services('Add', 'Unknown error in the ' : Service : ' service for server ' : Server : '.') end else Convert @RM to @FM in Databases end end If NewObject EQ True$ then SQL_Services('DestroyConnectionObject', objConnection) end end else Error_Services('Add', 'objConnection and Server arguments were both missing in the ' : Service : ' service.') end Response = Databases end service //---------------------------------------------------------------------------------------------------------------------- // GetSchemas // // objConnection - Connection Object (see GetConnectionObject service.) - [Optional, but Server is then Required] // Server - Name of a defined server. - [Optional, but objConnection is then Required] // Database - Name of a specific database to use. If empty, then all databases will be used. - [Required] // // Returns an @FM list of schemas available for the indicated database. If the connection object is empty, then a new // one will be created (and then subsequently destroyed) for the indicated server. //---------------------------------------------------------------------------------------------------------------------- Service GetSchemas(objConnection, Server, Database) Schemas = '' If Database NE '' then If (objConnection NE '') OR (Server NE '') then If objConnection EQ '' then objConnection = SQL_Services('GetConnectionObject', Server, 3) NewObject = True$ end else NewObject = False$ end If Error_Services('NoError') then SQLQuery = "SELECT DISTINCT TABLE_SCHEMA FROM [" : Database : "].INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'" Schemas = SQL_Services('ExecuteQuery', objConnection, SQLQuery, True$) If Error_Services('NoError') then Convert @RM to @FM in Schemas end else Message = Error_Services('GetMessage') If IndexC(Message, 'not able to access the database', 1) AND IndexC(Message, 'under the current security context', 1) then // Users does not have permission. Clear the error rather than report it. Error_Services('Clear') end end end If NewObject EQ True$ then ErrorMessage = Error_Services('GetMessage') SQL_Services('DestroyConnectionObject', objConnection) If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) end end else Error_Services('Add', 'objConnection and Server arguments were both missing in the ' : Service : ' service.') end end else Error_Services('Add', 'Database argument was missing in the ' : Service : ' service.') end Response = Schemas end service //---------------------------------------------------------------------------------------------------------------------- // GetTables // // objConnection - Connection Object (see GetConnectionObject service.) - [Optional, but Server is then Required] // Server - Name of a defined server. - [Optional, but objConnection is then Required] // Databases - @FM delimited list of databases to use. If empty, then all databases will be used. // - [Optional] // Schemas - @FM delimited list of schemas to use. If empty, then all schemas will be used. If Databases is // empty, then Schemas will be ignored. - [Optional] // ReturnFullObjects - Boolean flag to indicate if full object notation (e.g., Server.Database.Schema.Table) should // be returned or just the tables. Default is False$ - [Optional] // BracketObjects - Boolean flag to indicate if the objects being returned should be bracketed in case some of the // object names are reserved words. Default is False$ - [Optional] // // Returns an @FM list of tables using full object name formatting (i.e., Database.Schema.Table) available for the // indicated connection object (or server). If the connection object is empty, then a new one will be created (and then // subsequently destroyed) for the indicated server. //---------------------------------------------------------------------------------------------------------------------- Service GetTables(objConnection, Server, Databases, Schemas, IncludeServerObject=BOOLEAN, IncludeDatabaseObject=BOOLEAN, IncludeSchemaObject=BOOLEAN, BracketObjects=BOOLEAN) Tables = '' If IncludeServerObject NE True$ then IncludeServerObject = False$ If IncludeDatabaseObject NE True$ then IncludeDatabaseObject = False$ If IncludeSchemaObject NE True$ then IncludeSchemaObject = False$ If BracketObjects NE True$ then BracketObjects = False$ If Databases EQ '' then Schemas = '' If (objConnection NE '') OR (Server NE '') then If objConnection EQ '' then objConnection = SQL_Services('GetConnectionObject', Server, 3) NewObject = True$ end else NewObject = False$ end If Error_Services('NoError') then If Databases EQ '' then Databases = SQL_Services('GetDatabases', objConnection, Server) * If @USER4 EQ 'DANIEL_ST' then * debug * ConnectionState = Get_Property.Net(objConnection, "State") * end If Error_Services('NoError') AND (Databases NE '') then For Each Database in Databases using @FM If Schemas EQ '' then Schemas = SQL_Services('GetSchemas', objConnection, Server, Database) * If @USER4 EQ 'DANIEL_ST' then * debug * ConnectionState = Get_Property.Net(objConnection, "State") * end If UseRevDotNet EQ True$ and Schemas EQ 0 then Schemas = '' If Error_Services('NoError') AND (Schemas NE '') then For Each Schema in Schemas using @FM SQLQuery = "SELECT TABLE_NAME FROM [" : Database : "].INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='" : Schema : "'" TableNames = SQL_Services('ExecuteQuery', objConnection, SQLQuery, True$) Convert @RM to @FM in TableNames If Error_Services('NoError') AND (TableNames NE '') then If (IncludeServerObject EQ True$) OR (IncludeDatabaseObject EQ True$) OR (IncludeSchemaObject EQ True$) then For Each Table in TableNames using @FM TableObject = Table If IncludeSchemaObject EQ True$ then TableObject = Schema : '.' : TableObject If IncludeDatabaseObject EQ True$ then TableObject = Database : '.' : TableObject If IncludeServerObject EQ True$ then TableObject = Server : '.' : TableObject end end end Tables := TableObject : @FM Next Table end else Tables := TableNames : @FM end end Next Schema Schemas = '' end Next Database end Tables[-1, 1] = '' If (Tables NE '') AND (BracketObjects EQ True$) then Swap '.' with '].[' in Tables Swap @FM with ']' : @FM : '[' in Tables Tables = '[' : Tables : ']' Tables = SRP_Array('SortRows', Tables, 'AL1', 'LIST', @FM, @VM) end end If NewObject EQ True$ then ErrorMessage = Error_Services('GetMessage') SQL_Services('DestroyConnectionObject', objConnection) If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) end end else Error_Services('Add', 'objConnection and Server arguments were both missing in the ' : Service : ' service.') end Response = Tables end service //---------------------------------------------------------------------------------------------------------------------- // GetTableColumns // // objConnection - Connection Object (see GetConnectionObject service.) - [Optional, but Server is then Required] // Server - Name of a defined server. - [Optional, but objConnection is then Required] // Database - Database object for the table. - [Optional] // Schema - Schema object for the table. - [Optional] // Table - Database Table whose column data is being requested. The Table argument might have the Server, // Database, and/or Schema objects embedded. If so, then these will override any values specified // in the Server, Database, or Schema arguments. - [Required] // // Returns an @FM/@VM array of database column information. //---------------------------------------------------------------------------------------------------------------------- Service GetTableColumns(objConnection, Server, Database, Schema, Table) TableColumns = '' If Table NE '' then Convert '[]' to '' in Table ; // Remove any brackets so the query won't fail. If Index(Table, '.', 1) then // Table came formatted with other objects. Parse these out. NumObjects = DCount(Table, '.') Begin Case Case NumObjects EQ 4 Server = Table[1, '.'] Database = Table[Col2() + 1, '.'] Schema = Table[Col2() + 1, '.'] Table = Table[Col2() + 1, '.'] Case NumObjects EQ 3 Database = Table[1, '.'] Schema = Table[Col2() + 1, '.'] Table = Table[Col2() + 1, '.'] Case NumObjects EQ 2 Schema = Table[1, '.'] Table = Table[Col2() + 1, '.'] End Case end If (objConnection NE '') OR (Server NE '') then If objConnection EQ '' then objConnection = SQL_Services('GetConnectionObject', Server, 3) NewObject = True$ end else NewObject = False$ end If Error_Services('NoError') then ErrorMessage = '' // This statement allows us to return PK and Null constraints. If Database NE '' then SQL_Services('ExecuteQuery', objConnection, "USE " : Database, False$) end If Error_Services('NoError') then QueryStatement = "" QueryStatement := "SELECT " QueryStatement := " c.name 'Column Name', " QueryStatement := " t.Name 'Data type', " QueryStatement := " c.max_length 'Max Length', " QueryStatement := " c.is_nullable, " QueryStatement := " ISNULL(i.is_primary_key, 0) 'Primary Key' " QueryStatement := "FROM " QueryStatement := " sys.columns c " QueryStatement := "INNER JOIN " QueryStatement := " sys.types t ON c.user_type_id = t.user_type_id " QueryStatement := "LEFT OUTER JOIN " QueryStatement := " sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id " QueryStatement := "LEFT OUTER JOIN " QueryStatement := " sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id " QueryStatement := "WHERE" QueryStatement := " c.object_id = OBJECT_ID('" If Database NE '' then QueryStatement := "[" : Database : "]." If Schema NE '' then QueryStatement := "[" : Schema : "]." QueryStatement := "[" : Table : "]')" TableColumns = SQL_Services('ExecuteQuery', objConnection, QueryStatement, True$) If Error_Services('NoError') then Convert @FM to @VM in TableColumns Convert @RM to @FM in TableColumns TableColumns = SRP_Array('SortRows', TableColumns, 'DR5' : @FM : 'AL1', 'LIST', @FM, @VM) end else ErrorMessage = Error_Services('GetMessage') end SQL_Services('DestroyConnectionObject', objConnection) If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) end end If NewObject EQ True$ then ErrorMessage = Error_Services('GetMessage') SQL_Services('DestroyConnectionObject', objConnection) If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) end end else Error_Services('Add', 'The Server or Table argument was missing in the ' : Service : ' service.') end end else Error_Services('Add', 'Table argument was missing in the ' : Service : ' service.') end Response = TableColumns end service //---------------------------------------------------------------------------------------------------------------------- // GetPrimarySQLTable // // OITableName - The name of the OpenInsight table that is mapped to the primary SQL table. - [Required] // // Returns the name of the primary SQL table that the indicated OpenInsight table is mapped to. //---------------------------------------------------------------------------------------------------------------------- Service GetPrimarySQLTable(OITableName) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName PrimarySQLTable = Memory_Services('GetValue', ServiceKeyID) If PrimarySQLTable EQ '' then If OITableName NE '' then OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) If SRP_JSON(MapObj, 'PARSE', OITableToSQLMap) EQ '' then PrimarySQLTable = SRP_JSON(MapObj, 'GETVALUE', 'PrimarySQLTable.Name') SRP_JSON(MapObj, 'RELEASE') end If PrimarySQLTable NE '' then Memory_Services('SetValue', ServiceKeyID, PrimarySQLTable) end else Error_Services('Add', 'The OITableName argument was missing in the ' : Service : ' service.') end end Response = PrimarySQLTable end service //---------------------------------------------------------------------------------------------------------------------- // GetSecondarySQLTables // // OITableName - The name of the OpenInsight table that is mapped to secondary SQL tables. - [Required] // // Returns an @FM delimited list of the secondary SQL tables that the indicated OpenInsight table is mapped to. //---------------------------------------------------------------------------------------------------------------------- Service GetSecondarySQLTables(OITableName) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName SecondarySQLTables = Memory_Services('GetValue', ServiceKeyID) If SecondarySQLTables EQ '' then If OITableName NE '' then OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) If SRP_JSON(MapObj, 'PARSE', OITableToSQLMap) EQ '' then TablesArray = SRP_JSON(MapObj, 'GET', 'SecondarySQLTables') NumTables = SRP_JSON(TablesArray, 'GETCOUNT') MatchFound = False$ For TableNum = 1 to NumTables SecondarySQLTables := SRP_JSON(TablesArray, 'GETVALUE', '[' : TableNum : '].Name', '') : @FM Until MatchFound Next TableNum SRP_JSON(TablesArray, 'RELEASE') SRP_JSON(MapObj, 'RELEASE') end SecondarySQLTables[-1, 1] = '' If SecondarySQLTables NE '' then Memory_Services('SetValue', ServiceKeyID, SecondarySQLTables) end else Error_Services('Add', 'The OITableName argument was missing in the ' : Service : ' service.') end end Response = SecondarySQLTables end service //---------------------------------------------------------------------------------------------------------------------- // GetStaticSQLColumnNames // // OITableName - The name of the OpenInsight table that columns mapped to a SQL table with static values. - [Required] // // Returns an @FM delimited list of SQL column names that have a static value. These are usually used in a SQL insert // statement along with the mapped columns. //---------------------------------------------------------------------------------------------------------------------- Service GetStaticSQLColumnNames(OITableName) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName StaticSQLColumnNames = Memory_Services('GetValue', ServiceKeyID) If StaticSQLColumnNames EQ '' then If (OITableName NE '') then // Add all OpenInsight columns defined in the SQL Join Clause. OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) If SRP_JSON(MapObj, 'PARSE', OITableToSQLMap) EQ '' then StaticColumnsArray = SRP_JSON(MapObj, 'GET', 'StaticColumns') NumColumns = SRP_JSON(StaticColumnsArray, 'GETCOUNT') For ColumnNum = 1 to NumColumns objStaticColumn = SRP_JSON(StaticColumnsArray, 'GET', '[' : ColumnNum : ']') StaticSQLColumnNames := SRP_JSON(objStaticColumn, 'GETVALUE', 'SQLColumnName') : @FM SRP_JSON(objStaticColumn, 'RELEASE') Next NumColumns StaticSQLColumnNames[-1, 1] = '' SRP_JSON(StaticColumnsArray, 'RELEASE') SRP_JSON(MapObj, 'RELEASE') end If StaticSQLColumnNames NE '' then Memory_Services('SetValue', ServiceKeyID, StaticSQLColumnNames) end else Error_Services('Add', 'The OITableName argument was missing in the ' : Service : ' service.') end end Response = StaticSQLColumnNames end service //---------------------------------------------------------------------------------------------------------------------- // GetStaticSQLColumnValues // // OITableName - The name of the OpenInsight table that columns mapped to a SQL table with static values. - [Required] // // Returns an @FM delimited list of values for SQL column names that have a static value. These are usually used in a // SQL insert statement along with the mapped columns. //---------------------------------------------------------------------------------------------------------------------- Service GetStaticSQLColumnValues(OITableName) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName StaticSQLColumnValues = Memory_Services('GetValue', ServiceKeyID) If StaticSQLColumnValues EQ '' then If (OITableName NE '') then // Add all OpenInsight columns defined in the SQL Join Clause. OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) If SRP_JSON(MapObj, 'PARSE', OITableToSQLMap) EQ '' then StaticColumnsArray = SRP_JSON(MapObj, 'GET', 'StaticColumns') NumColumns = SRP_JSON(StaticColumnsArray, 'GETCOUNT') For ColumnNum = 1 to NumColumns objStaticColumn = SRP_JSON(StaticColumnsArray, 'GET', '[' : ColumnNum : ']') StaticValue = SRP_JSON(objStaticColumn, 'GETVALUE', 'StaticValue') StaticValue = "'" : StaticValue : "'" StaticSQLColumnValues := StaticValue : @FM SRP_JSON(objStaticColumn, 'RELEASE') Next NumColumns StaticSQLColumnValues[-1, 1] = '' SRP_JSON(StaticColumnsArray, 'RELEASE') SRP_JSON(MapObj, 'RELEASE') end If StaticSQLColumnValues NE '' then Memory_Services('SetValue', ServiceKeyID, StaticSQLColumnValues) end else Error_Services('Add', 'The OITableName argument was missing in the ' : Service : ' service.') end end Response = StaticSQLColumnValues end service //---------------------------------------------------------------------------------------------------------------------- // GetAMVMaster // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // // Returns the name of the OpenInsight column used as the AMV (associated multivalue) master used to determine the // number of values needed to write into the secondary SQL table. //---------------------------------------------------------------------------------------------------------------------- Service GetAMVMaster(OITableName, SQLTableName) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName : '*' : SQLTableName AMVMaster = Memory_Services('GetValue', ServiceKeyID) If AMVMaster EQ '' then If (OITableName NE '') AND (SQLTableName NE '') then OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) JoinArray = '' ; // Initialize the array. If SRP_JSON(MapObj, 'Parse', OITableToSQLMap) EQ '' then PrimarySQLTableName = SRP_JSON(MapObj, 'GetValue', 'PrimarySQLTable.Name') If SQLTableName _EQC PrimarySQLTableName then // Primary SQL tables do not have a Seq Key. Just return the empty string. end else // Look for a matching secondary SQL table. TableArray = SRP_JSON(MapObj, 'Get', 'SecondarySQLTables') TableObjs = SRP_JSON(TableArray, 'GetElements') TableFound = False$ For Each TableObj in TableObjs using @FM SecondarySQLTableName = SRP_JSON(TableObj, 'GETVALUE', 'Name', '') If SQLTableName _EQC SecondarySQLTableName then JoinClassArray = SRP_JSON(TableObj, 'Get', 'JoinClause') JoinClassObjs = SRP_JSON(JoinClassArray, 'GetElements') For Each JoinClassObj in JoinClassObjs using @FM If SRP_JSON(JoinClassObj, 'GetValue', 'AMVMaster') EQ True$ then AMVMaster = SRP_JSON(JoinClassObj, 'GetValue', 'OIColumnName') end SRP_JSON(JoinClassObj, 'Release') Until AMVMaster NE '' Next JoinClassObj TableFound = True$ SRP_JSON(JoinClassArray, 'Release') end SRP_JSON(TableObj, 'Release') Until TableFound Next TableObj SRP_JSON(TableArray, 'Release') end SRP_JSON(MapObj, 'Release') end If AMVMaster NE '' then Memory_Services('SetValue', ServiceKeyID, AMVMaster) end end else Error_Services('Add', 'The OITableName or SQLTableName argument was missing in the ' : Service : ' service.') end end Response = AMVMaster end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedJoinedOIColumnNames // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // ValuesReturned - A return varabiable that will contain the type of values each associated column should return. // See below for more information. - [Optional] // // Returns an @FM list of column names from the indicated OpenInsight table that are used to join with the indicated // SQL table. This service will also populate the ValuesReturned variable with the intended value to be returned by the // associated column (.e.g, Column Data or Index Position). //---------------------------------------------------------------------------------------------------------------------- Service GetMappedJoinedOIColumnNames(OITableName, SQLTableName, Ref ValuesReturned) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName : '*' : SQLTableName ColumnNames = Memory_Services('GetValue', ServiceKeyID) ValuesReturned = Memory_Services('GetValue', ServiceKeyID : '*ValuesReturned') If ColumnNames EQ '' then If (OITableName NE '') AND (SQLTableName NE '') then OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) JoinArray = '' ; // Initialize the array. If SRP_JSON(MapObj, 'PARSE', OITableToSQLMap) EQ '' then PrimarySQLTableName = SRP_JSON(MapObj, 'GETVALUE', 'PrimarySQLTable.Name') If SQLTableName _EQC PrimarySQLTableName then // Use the join array from the primary SQL Table. JoinArray = SRP_JSON(MapObj, 'GET', 'PrimarySQLTable.JoinClause') end else // Look for a matching secondary SQL table. TablesArray = SRP_JSON(MapObj, 'GET', 'SecondarySQLTables') NumTables = SRP_JSON(TablesArray, 'GETCOUNT') MatchFound = False$ For TableNum = 1 to NumTables TableObj = SRP_JSON(TablesArray, 'GET', '[' : TableNum : ']') SecondarySQLTableName = SRP_JSON(TableObj, 'GETVALUE', 'Name', '') If SQLTableName _EQC SecondarySQLTableName then JoinArray = SRP_JSON(TableObj, 'GET', 'JoinClause') MatchFound = True$ end SRP_JSON(TableObj, 'RELEASE') Until MatchFound Next TableNum SRP_JSON(TablesArray, 'RELEASE') end SRP_JSON(MapObj, 'RELEASE') end If JoinArray GT 0 then NumColumns = SRP_JSON(JoinArray, 'GETCOUNT') For ColumnNo = 1 to NumColumns OIColumnName = SRP_JSON(JoinArray, 'GETVALUE', '[' : ColumnNo : ']' : 'OIColumnName', '') ValueReturned = SRP_JSON(JoinArray, 'GETVALUE', '[' : ColumnNo : ']' : 'ValueReturned', '') ColumnNames := OIColumnName : @FM ValuesReturned := ValueReturned : @FM Next ColumnNo ColumnNames[-1, 1] = '' ValuesReturned[-1, 1] = '' SRP_JSON(JoinArray, 'RELEASE') end If ColumnNames NE '' then Memory_Services('SetValue', ServiceKeyID, ColumnNames) Memory_Services('SetValue', ServiceKeyID : '*ValuesReturned', ValuesReturned) end end else Error_Services('Add', 'The OITableName or SQLTableName argument was missing in the ' : Service : ' service.') end end Response = ColumnNames end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedJoinedSQLColumnNames // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // // Returns an @FM list of column names from the indicated SQL table that are used to join with the indicated OpenInsight // table. //---------------------------------------------------------------------------------------------------------------------- Service GetMappedJoinedSQLColumnNames(OITableName, SQLTableName) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName : '*' : SQLTableName ColumnNames = Memory_Services('GetValue', ServiceKeyID) If ColumnNames EQ '' then If (OITableName NE '') AND (SQLTableName NE '') then OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) JoinArray = '' ; // Initialize the array. If SRP_JSON(MapObj, 'PARSE', OITableToSQLMap) EQ '' then PrimarySQLTableName = SRP_JSON(MapObj, 'GETVALUE', 'PrimarySQLTable.Name') If SQLTableName _EQC PrimarySQLTableName then // Use the join array from the primary SQL Table. JoinArray = SRP_JSON(MapObj, 'GET', 'PrimarySQLTable.JoinClause') end else // Look for a matching secondary SQL table. TablesArray = SRP_JSON(MapObj, 'GET', 'SecondarySQLTables') NumTables = SRP_JSON(TablesArray, 'GETCOUNT') MatchFound = False$ For TableNum = 1 to NumTables TableObj = SRP_JSON(TablesArray, 'GET', '[' : TableNum : ']') SecondarySQLTableName = SRP_JSON(TableObj, 'GETVALUE', 'Name', '') If SQLTableName _EQC SecondarySQLTableName then JoinArray = SRP_JSON(TableObj, 'GET', 'JoinClause') MatchFound = True$ end SRP_JSON(TableObj, 'RELEASE') Until MatchFound Next TableNum SRP_JSON(TablesArray, 'RELEASE') end SRP_JSON(MapObj, 'RELEASE') end If JoinArray GT 0 then NumColumns = SRP_JSON(JoinArray, 'GETCOUNT') For ColumnNo = 1 to NumColumns SQLColumnName = SRP_JSON(JoinArray, 'GETVALUE', '[' : ColumnNo : ']' : 'SQLColumnName', '') ColumnNames := SQLColumnName : @FM Next ColumnNo ColumnNames[-1, 1] = '' SRP_JSON(JoinArray, 'RELEASE') end If ColumnNames NE '' then Memory_Services('SetValue', ServiceKeyID, ColumnNames) end end else Error_Services('Add', 'The OITableName or SQLTableName argument was missing in the ' : Service : ' service.') end end Response = ColumnNames end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedJoinedOperators // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // // Returns an @FM list of operators from the indicated SQL table that are used to join with the indicated OpenInsight // table. //---------------------------------------------------------------------------------------------------------------------- Service GetMappedJoinedOperators(OITableName, SQLTableName) Convert @Lower_Case to @Upper_Case in OITableName ServiceKeyID := '*' : OITableName : '*' : SQLTableName Operators = Memory_Services('GetValue', ServiceKeyID) If Operators EQ '' then If (OITableName NE '') AND (SQLTableName NE '') then OITableToSQLMap = SQL_Services('GetOITableToSQLMap', OITableName) JoinArray = '' ; // Initialize the array. If SRP_JSON(MapObj, 'PARSE', OITableToSQLMap) EQ '' then PrimarySQLTableName = SRP_JSON(MapObj, 'GETVALUE', 'PrimarySQLTable.Name') If SQLTableName _EQC PrimarySQLTableName then // Use the join array from the primary SQL Table. JoinArray = SRP_JSON(MapObj, 'GET', 'PrimarySQLTable.JoinClause') end else // Look for a matching secondary SQL table. TablesArray = SRP_JSON(MapObj, 'GET', 'SecondarySQLTables') NumTables = SRP_JSON(TablesArray, 'GETCOUNT') MatchFound = False$ For TableNum = 1 to NumTables TableObj = SRP_JSON(TablesArray, 'GET', '[' : TableNum : ']') SecondarySQLTableName = SRP_JSON(TableObj, 'GETVALUE', 'Name', '') If SQLTableName _EQC SecondarySQLTableName then JoinArray = SRP_JSON(TableObj, 'GET', 'JoinClause') MatchFound = True$ end SRP_JSON(TableObj, 'RELEASE') Until MatchFound Next TableNum SRP_JSON(TablesArray, 'RELEASE') end SRP_JSON(MapObj, 'RELEASE') end If JoinArray GT 0 then NumColumns = SRP_JSON(JoinArray, 'GETCOUNT') For ColumnNo = 1 to NumColumns Operator = SRP_JSON(JoinArray, 'GETVALUE', '[' : ColumnNo : ']' : 'Operator', '') Operators := Operator : @FM Next ColumnNo Operators[-1, 1] = '' SRP_JSON(JoinArray, 'RELEASE') end If Operators NE '' then Memory_Services('SetValue', ServiceKeyID, Operators) end end else Error_Services('Add', 'The OITableName or SQLTableName argument was missing in the ' : Service : ' service.') end end Response = Operators end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedJoinedSQLColumnValues // // OITableName - The name of the OpenInsight table that is mapped to the SQL table to. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // OIKeyID - The Key ID to the OpenInsight row being written to SQL. - [Required] // OIRow - The OpenInsight row being written to SQL. - [Optional] // AMVPosition - The position within the multivalue column that should be used in the join clause if the OpenInsight // column is supposed to use its Index Position. - [Optional] // // Returns an @FM delimited list of SQL column values for the indicated table that are derived from the indicated // OpenInsight table and associated joined columns. This service is normally called to create a fully formed Insert // query statement. Note: OIRow will likely be an empty string since most join clauses will be based on the OpenInsight // Key ID. //---------------------------------------------------------------------------------------------------------------------- Service GetMappedJoinedSQLColumnValues(OITableName, SQLTableName, OIKeyID, OIRow, AMVPosition) Convert @Lower_Case to @Upper_Case in OITableName If Num(AMVPosition) else AMVPosition = '' ColumnValues = '' If (OITableName NE '') AND (SQLTableName NE '') AND (OIKeyID NE '') then FieldArray = Database_Services('ReadDataRow', 'DICT.' : OITablename, '%FIELDS%') OIColumnNames = SQL_Services('GetMappedJoinedOIColumnNames', OITableName, SQLTableName, ValuesReturned) If Error_Services('NoError') then If OIColumnNames NE '' then For Each OIColumnName in OIColumnNames using @FM setting fPos ValueReturned = ValuesReturned If ValueReturned EQ '' then ValueReturned = 'Column Data' Locate OIColumnName in FieldArray using @VM setting vPos then OIColumnToSQLMap = SQL_Services('GetOIColumnToSQLMap', OITableName, OIColumnName) If Error_Services('NoError') then If SRP_JSON(MapObj, 'PARSE', OIColumnToSQLMap) EQ '' then SQLColumnType = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnType') OIColumnType = FieldArray IsOIKey = False$ ; // Assume false for now. If ValueReturned EQ 'Column Data' then If OIColumnType EQ 'F' then OIColumnPos = FieldArray If OIColumnPos GT 0 then OIColumnValue = OIRow end else IsOIKey = True$ OIKeyPart = FieldArray OIColumnValue = Field(OIKeyID, '*', OIKeyPart, 1) If OIColumnValue EQ '' then Error_Services('Add', 'Key ID Column ' : OIColumnName : ' was assigned an empty string value in ' : Service : '.') end end end else // OIColumnValue = Calculate(OIColumnName) ; // Actual logic used in MFS OIColumnValue = Xlate(OITablename, OIKeyID, OIColumnName, 'X') end If (AMVPosition NE '') AND (IsOIKey NE True$) then OIColumnValue = OIColumnValue<0, AMVPosition> end end else If AMVPosition EQ '' then AMVPosition = 1 OIColumnValue = AMVPosition end If ValueReturned EQ 'Column Data' then // Make applicable data conversions. Begin Case Case OIColumnValue EQ '' // Empty strings are treated as NULL values. OIColumnValue = 'NULL' Case InList('varchar,nvarchar,char,nchar', SQLColumnType, ',') // Single quote the value. SQLColumnLength = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnLength') OIColumnConv = FieldArray If OIColumnConv NE '' then OIColumnValue = Fmt(OIColumnValue, OIColumnConv) end If (SQLColumnLength EQ '') OR (SQLColumnLength EQ '-1') then SQLColumnLength = Len(OIColumnValue) OIColumnValue = OIColumnValue[1, SQLColumnLength, 1] Swap "'" with "''" in OIColumnValue OIColumnValue = "'" : OIColumnValue : "'" Case InList('tinyint,smallint,bigint,int', SQLColumnType, ',') // Treat as an integer. OIColumnConv = 'MD0' If OIColumnConv NE '' then OIColumnValue = Fmt(OIColumnValue, OIColumnConv) end Case InList('decimal,numeric,float,real', SQLColumnType, ',') // Treat as a floating point number using any OI column output conversion if it // exists. OIColumnConv = FieldArray Convert 'Z' to '' in OIColumnConv ; // No empty strings with numeric columns. If OIColumnConv NE '' then OIColumnValue = Fmt(OIColumnValue, OIColumnConv) end Case SQLColumnType _EQC 'bit' // Treat as a Boolean, but only return a 1, 0, or NULL. If OIColumnValue EQ '' then OIColumnValue = 'NULL' end else If OIColumnValue NE False$ then OIColumnValue = True$ end Case SQLColumnType _EQC 'date' OIColumnValue = "'" : (SRP_Date('Format', OIColumnValue, 'YYYY-MM-DD')) : "'" Case SQLColumnType _EQC 'datetime' OIColumnValue = "'" : (SRP_DateTime('Format', OIColumnValue, 'YYYY-MM-DD hh:mm:ss')) : "'" Case SQLColumnType _EQC 'time' OIColumnValue = "'" : (SRP_Time('Format', OIColumnValue, 'hh:mm:ss')) : "'" Case Otherwise$ // Treat as a character type. SQLColumnLength = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnLength') OIColumnConv = FieldArray If OIColumnConv NE '' then OIColumnValue = Fmt(OIColumnValue, OIColumnConv) end If (SQLColumnLength EQ '') OR (SQLColumnLength EQ '-1') then SQLColumnLength = Len(OIColumnValue) OIColumnValue = OIColumnValue[1, SQLColumnLength, 1] Swap "'" with "''" in OIColumnValue OIColumnValue = "'" : OIColumnValue : "'" End Case end // Basic conversion rules. Convert \09\ to ' ' in OIColumnValue Swap \0D0A\ with ' ' in OIColumnValue Convert @VM to '|' in OIColumnValue Convert @SVM to ' ' in OIColumnValue Convert @TM to ' ' in OIColumnValue Convert @STM to ' ' in OIColumnValue ColumnValues := OIColumnValue : @FM SRP_JSON(MapObj, 'RELEASE') end end end While Error_Services('NoError') Next OIColumnName end ColumnValues[-1, 1] = '' end end else Error_Services('Add', 'The OITableName, SQLTableName, OIKeyID, or OIRow argument was missing in the ' : Service : ' service.') end Response = ColumnValues end service //---------------------------------------------------------------------------------------------------------------------- // GetJoinClause // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // OIKeyID - The Key ID to the OpenInsight row being written to SQL. - [Required] // OIRow - The OpenInsight row being written to SQL. - [Optional] // AMVPosition - The position within the multivalue column that should be used in the join clause if the // OpenInsight column is supposed to use its Index Position. - [Optional] // IgnoreAMVMaster - Boolean falg to indicate if the joined column associated with the OpenInsight AMV Master should // be ignored. This is necessary for Join Clauses used for Select and Delete statements. - [Optional] // // Returns a well formed join clause using the indicated OpenInsight Key ID and row for the indicated OpenInsight table // and SQL table. Note: OIRow will likely be an empty string since most join clauses will be based on the OpenInsight // Key ID. //---------------------------------------------------------------------------------------------------------------------- Service GetJoinClause(OITableName, SQLTableName, OIKeyID, OIRow, AMVPosition, IgnoreAMVMaster=BOOLEAN) Convert @Lower_Case to @Upper_Case in OITableName JoinClause = '' If IgnoreAMVMaster NE True$ then IgnoreAMVMaster = False$ If (OITableName NE '') AND (SQLTableName NE '') AND (OIKeyID NE '') then JoinedSQLColumns = SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, SQLTableName) If JoinedSQLColumns NE '' then JoinedOperators = SQL_Services('GetMappedJoinedOperators', OITableName, SQLTableName) JoinedSQLValues = SQL_Services('GetMappedJoinedSQLColumnValues', OITableName, SQLTableName, OIKeyID, OIRow, AMVPosition) If IgnoreAMVMaster EQ True$ then // Get all of the OpenInsight columns associated with this join and the AMV Master. Remove the SQL column, // operator, and value associated with the AMV Master. AMVMaster = SQL_Services('GetAMVMaster', OITableName, SQLTableName) If AMVMaster NE '' then JoinedOIColumns = SQL_Services('GetMappedJoinedOIColumnNames', OITableName, SQLTableName) Locate AMVMaster in JoinedOIColumns using @FM setting Pos then JoinedSQLColumns = Delete(JoinedSQLColumns, Pos, 0, 0) JoinedOperators = Delete(JoinedOperators, Pos, 0, 0) JoinedSQLValues = Delete(JoinedSQLValues, Pos, 0, 0) end end end For Each JoinedColumn in JoinedSQLColumns using @FM setting Pos JoinClause := JoinedColumn : ' ' JoinClause := JoinedOperators : ' ' JoinClause := JoinedSQLValues JoinClause := @FM Next JoinedColumn JoinClause[-1, 1] = '' Swap @FM with ' AND ' in JoinClause end end else Error_Services('Add', 'The OITableName, SQLTableName, OIKeyID argument was missing in the ' : Service : ' service.') end Response = JoinClause end service //---------------------------------------------------------------------------------------------------------------------- // GetJoinClause // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // OIKeyID - The Key ID to the OpenInsight row being written to SQL. - [Required] // OIRow - The OpenInsight row being written to SQL. - [Optional] // AMVPosition - The position within the multivalue column that should be used in the join clause if the // OpenInsight column is supposed to use its Index Position. - [Optional] // IgnoreAMVMaster - Boolean falg to indicate if the joined column associated with the OpenInsight AMV Master should // be ignored. This is necessary for Join Clauses used for Select and Delete statements. - [Optional] // // Returns a well formed join clause using the indicated OpenInsight Key ID and row for the indicated OpenInsight table // and SQL table. Note: OIRow will likely be an empty string since most join clauses will be based on the OpenInsight // Key ID. //---------------------------------------------------------------------------------------------------------------------- Service GetMergeClause(OITableName, SQLTableName, OIKeyID, OIRow, AMVPosition, IgnoreAMVMaster=BOOLEAN) Convert @Lower_Case to @Upper_Case in OITableName JoinClause = '' If IgnoreAMVMaster NE True$ then IgnoreAMVMaster = False$ If (OITableName NE '') AND (SQLTableName NE '') AND (OIKeyID NE '') then JoinedSQLColumns = SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, SQLTableName) If JoinedSQLColumns NE '' then JoinedOperators = SQL_Services('GetMappedJoinedOperators', OITableName, SQLTableName) JoinedSQLValues = SQL_Services('GetMappedJoinedSQLColumnValues', OITableName, SQLTableName, OIKeyID, OIRow, AMVPosition) If IgnoreAMVMaster EQ True$ then // Get all of the OpenInsight columns associated with this join and the AMV Master. Remove the SQL column, // operator, and value associated with the AMV Master. AMVMaster = SQL_Services('GetAMVMaster', OITableName, SQLTableName) If AMVMaster NE '' then JoinedOIColumns = SQL_Services('GetMappedJoinedOIColumnNames', OITableName, SQLTableName) Locate AMVMaster in JoinedOIColumns using @FM setting Pos then JoinedSQLColumns = Delete(JoinedSQLColumns, Pos, 0, 0) JoinedOperators = Delete(JoinedOperators, Pos, 0, 0) JoinedSQLValues = Delete(JoinedSQLValues, Pos, 0, 0) end end end For Each JoinedColumn in JoinedSQLColumns using @FM setting Pos JoinClause := 'tgt.':JoinedColumn : ' ' JoinClause := JoinedOperators : ' ' JoinClause := 'src.':JoinedColumn JoinClause := @FM Next JoinedColumn JoinClause[-1, 1] = '' Swap @FM with ' AND ' in JoinClause end end else Error_Services('Add', 'The OITableName, SQLTableName, OIKeyID argument was missing in the ' : Service : ' service.') end Response = JoinClause end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedOIColumnNames // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // ExcludeJoinedColumns - Boolean flag indicating if the columns used for the join should be excluded from the // list of columns returned. This would be done if the columns are used to insert or update // the SQL table. Default is true. - [Optional] // // Returns an @FM delimited list of OpenInsight column names from the indicated table that are mapped to the indicated // SQL table. //---------------------------------------------------------------------------------------------------------------------- Service GetMappedOIColumnNames(OITableName, SQLTableName, ExcludeJoinedColumns=BOOLEAN) Convert @Lower_Case to @Upper_Case in OITableName If ExcludeJoinedColumns NE False$ then ExcludeJoinedColumns = True$ ServiceKeyID := '*' : OITableName : '*' : SQLTableName : '*' : ExcludeJoinedColumns ColumnNames = Memory_Services('GetValue', ServiceKeyID) If ColumnNames EQ '' then If (OITableName NE '') AND (SQLTableName NE '') then // Go through all of the OpenInsight column SQL maps and add any column which is bound to the same SQL // table. Note, one or more of these columns might already be in the list from the // GetMappedJoinedOIColumnNames service. These will be skipped. AllOIColumnToSQLMaps = SQL_Services('GetAllOIColumnToSQLMaps', OITableName) For Each OIColumnToSQLMapList in AllOIColumnToSQLMaps using @FM setting fPos (OIColumnName, OIColumnToSQLMap) using @VM = OIColumnToSQLMapList If SRP_JSON(MapObj, 'PARSE', OIColumnToSQLMap) EQ '' then MappedSQLTableName = SRP_JSON(MapObj, 'GETVALUE', 'SQLTableName') MappedSQLColumnName = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnName') If (MappedSQLTableName NE '') AND (MappedSQLColumnName NE '') AND (SQLTableName EQ MappedSQLTableName) then Locate OIColumnName in ColumnNames using @FM setting fPos else ColumnNames := OIColumnName : @FM end end SRP_JSON(MapObj, 'Release') end Next OIColumnToSQLMap If ExcludeJoinedColumns EQ True$ then // Get all OpenInsight columns defined in the SQL Join Clause. Then remove any that are rely upon Column // Data mapping rather than Index Position. This will avoid duplicate columns being used in a SQL statement. JoinedValuesReturned = '' JoinedOIColumns = SQL_Services('GetMappedJoinedOIColumnNames', OITableName, SQLTableName, JoinedValuesReturned) If JoinedOIColumns NE '' then For Each JoinedColumnName in JoinedOIColumns using @FM Setting JoinedPos Locate JoinedColumnName in ColumnNames using @FM setting Pos then If JoinedValuesReturned EQ 'Column Data' then ColumnNames = Delete(ColumnNames, Pos, 0, 0) end end Next JoinedColumnName end end ColumnNames[-1, 1] = '' If ColumnNames NE '' then Memory_Services('SetValue', ServiceKeyID, ColumnNames) end end else Error_Services('Add', 'The OITableName or SQLTableName argument was missing in the ' : Service : ' service.') end end Response = ColumnNames end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedOIColumnValues // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // SQLRow - The SQL row that will be mapped to the OpenInsight row. - [Required] // OIRow - The OpenInsight row with pre-existing data. See below for more information. - [Optional] // // Returns an OpenInsight data row for the indicated table that are derived from the indicated SQL table and // corresponding SQL data. Note, since data can come from multiple SQL tables, the OIRow arguments can already contain // data from a previous call to this service. This allows primary and secondary SQL tables to be passed into this // service so that all relevant SQL data can be denormalized into a single OpenInsight data row. This service is // normally called to create a denormalized OpenInsight row. //---------------------------------------------------------------------------------------------------------------------- Service GetMappedOIColumnValues(OITableName, SQLTableName, SQLData, OIRow) Convert @Lower_Case to @Upper_Case in OITableName If (OITableName NE '') AND (SQLTableName NE '') AND (SQLData NE '') then MappedOIColumnNames = SQL_Services('GetMappedOIColumnNames', OITableName, SQLTableName, False$) MappedSQLColumnNames = SQL_Services('GetMappedSQLColumnNames', OITableName, SQLTableName, '', False$) FieldArray = Database_Services('ReadDataRow', 'DICT.' : OITablename, '%FIELDS%') If Error_Services('NoError') then For Each SQLRow in SQLData using @RM setting ValuePos For Each SQLColumnName in MappedSQLColumnNames using @FM setting fPos OIColumnName = MappedOIColumnNames Locate OIColumnName in FieldArray using @VM setting vPos then OIColumnType = FieldArray OIColumnPos = FieldArray If OIColumnType EQ 'F' AND OIColumnPos NE 0 then OIColumnToSQLMap = SQL_Services('GetOIColumnToSQLMap', OITableName, OIColumnName) If Error_Services('NoError') then If SRP_JSON(MapObj, 'PARSE', OIColumnToSQLMap) EQ '' then SQLColumnType = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnType') OIColumnValue = SQLRow Swap '<@VM>' with @VM in OIColumnValue Swap @SVM with '<@SVM>' in OIColumnValue Swap @TM with '<@TM>' in OIColumnValue Swap @STM with '<@STM>' in OIColumnValue Begin Case Case InList('varchar,nvarchar,char,nchar', SQLColumnType, ',') // Single quote the value. OIColumnConv = FieldArray If OIColumnConv NE '' then OIColumnValue = Iconv(OIColumnValue, OIColumnConv) end Case InList('tinyint,smallint,bigint,int', SQLColumnType, ',') // Treat as an integer. OIColumnConv = 'MD0' If OIColumnConv NE '' then OIColumnValue = Iconv(OIColumnValue, OIColumnConv) end Case InList('decimal,numeric,float,real', SQLColumnType, ',') // Treat as a floating point number using any OI column output conversion if it // exists. OIColumnConv = FieldArray If OIColumnConv NE '' then OIColumnValue = Iconv(OIColumnValue, OIColumnConv) end Case SQLColumnType _EQC 'date' OIColumnValue = SRP_Date('Parse', OIColumnValue, 'MM/DD/YYYY') Case SQLColumnType _EQC 'datetime' OIColumnValue = SRP_DateTime('Parse', OIColumnValue, 'MM/DD/YYYY hh:mm:ss') Case SQLColumnType _EQC 'time' OIColumnValue = SRP_Time('Parse', OIColumnValue, 'hh:mm:ss') Case Otherwise$ // Treat as a character type. OIColumnConv = FieldArray If OIColumnConv NE '' then OIColumnValue = Iconv(OIColumnValue, OIColumnConv) end End Case OIRow = OIColumnValue end SRP_JSON(MapObj, 'RELEASE') end end end Next SQLColumnName Next SQLRow end end else Error_Services('Add', 'The SQLTableName, SQLData, or OITableName argument was missing in the ' : Service : ' service.') end Response = OIRow end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedSQLColumnNames // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // OIColumns - An @FM delimited list of OpenInsight table columns that should only be used to write to // SQL. If empty, all columns that have a map defintion will be used. - [Optional] // ExcludeJoinedColumns - Boolean flag indicating if the columns used for the join should be excluded from the // list of columns returned. This would be done if the columns are used to insert or update // the SQL table. Default is true. - [Optional] // // Returns an @FM delimited list of SQL column names from the indicated table that are mapped from the indicated // OpenInsight table and associated OpenInsight columns. //---------------------------------------------------------------------------------------------------------------------- Service GetMappedSQLColumnNames(OITableName, SQLTableName, OIColumns, ExcludeJoinedColumns) Convert @Lower_Case to @Upper_Case in OITableName If ExcludeJoinedColumns NE False$ then ExcludeJoinedColumns = True$ ServiceKeyID := '*' : OITableName : '*' : SQLTableName : '*' : ExcludeJoinedColumns ColumnNames = Memory_Services('GetValue', ServiceKeyID) If ColumnNames EQ '' then If (OITableName NE '') AND (SQLTableName NE '') then If OIColumns NE '' then Transfer OIColumns to OIColumnNames end else // The GetMappedOIColumnNames service will automatically remove any columns that are also mapped in // a join clause with the "Column Data" return value attribute. OIColumnNames = SQL_Services('GetMappedOIColumnNames', OITableName, SQLTableName, ExcludeJoinedColumns) end If OIColumnNames NE '' then For Each OIColumnName in OIColumnNames using @FM setting fPos OIColumnToSQLMap = SQL_Services('GetOIColumnToSQLMap', OITableName, OIColumnName) If Error_Services('NoError') then If SRP_JSON(MapObj, 'PARSE', OIColumnToSQLMap) EQ '' then MappedSQLTableName = SRP_JSON(MapObj, 'GETVALUE', 'SQLTableName') MappedSQLColumnName = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnName') If (MappedSQLTableName EQ SQLTablename) AND (MappedSQLColumnName NE '') then ColumnNames := MappedSQLColumnName : @FM end SRP_JSON(MapObj, 'RELEASE') end end Next OIColumnName end ColumnNames[-1, 1] = '' If ColumnNames NE '' then Memory_Services('SetValue', ServiceKeyID, ColumnNames) end else Error_Services('Add', 'The OITableName or SQLTableName argument was missing in the ' : Service : ' service.') end end Response = ColumnNames end service //---------------------------------------------------------------------------------------------------------------------- // GetMappedSQLColumnValues // // OITableName - The name of the OpenInsight table that is mapped to the SQL table to. - [Required] // SQLTableName - The name of the SQL table that the Openinsight table is mapped to. - [Required] // OIKeyID - The Key ID to the OpenInsight row being written to SQL. - [Required] // OIRow - The OpenInsight row being written to SQL. - [Required] // AMVPosition - The position within the multivalue column that should be used in the join clause if the OpenInsight // column is supposed to use its Index Position. - [Optional] // OIColumns - An @FM delimited list of OpenInsight table columns that should only be used to write to SQL. If empty, // all columns that have a map defintion will be used. - [Optional] // // Returns an @FM delimited list of SQL column values for the indicated table that are derived from the indicated // OpenInsight table and associated OpenInsight columns. This service is normally called to create a fully formed Insert // query statement. //---------------------------------------------------------------------------------------------------------------------- Service GetMappedSQLColumnValues(OITableName, SQLTableName, OIKeyID, OIRow, AMVPosition, OIColumns) Convert @Lower_Case to @Upper_Case in OITableName If Num(AMVPosition) else AMVPosition = '' ColumnValues = '' If (OITableName NE '') AND (SQLTableName NE '') AND (OIKeyID NE '') AND (OIRow NE '') then FieldArray = Database_Services('ReadDataRow', 'DICT.' : OITablename, '%FIELDS%') If OIColumns NE '' then Transfer OIColumns to OIColumnNames end else // The GetMappedOIColumnNames service will automatically remove any columns that are also mapped in // a join clause with the "Column Data" return value attribute. OIColumnNames = SQL_Services('GetMappedOIColumnNames', OITableName, SQLTableName, True$) end If OIColumnNames NE '' then For Each OIColumnName in OIColumnNames using @FM setting fPos Locate OIColumnName in FieldArray using @VM setting vPos then OIColumnToSQLMap = SQL_Services('GetOIColumnToSQLMap', OITableName, OIColumnName) If Error_Services('NoError') then If SRP_JSON(MapObj, 'PARSE', OIColumnToSQLMap) EQ '' then MappedSQLTableName = SRP_JSON(MapObj, 'GETVALUE', 'SQLTableName') If MappedSQLTableName EQ SQLTablename then SQLColumnType = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnType') OIColumnType = FieldArray IsOIKey = False$ ; // Assume false for now. If OIColumnType EQ 'F' then OIColumnPos = FieldArray If OIColumnPos GT 0 then OIColumnValue = OIRow end else IsOIKey = True$ OIKeyPart = FieldArray OIColumnValue = Field(OIKeyID, '*', OIKeyPart, 1) If OIColumnValue EQ '' then Error_Services('Add', 'Key ID Column ' : OIColumnName : ' was assigned an empty string value in ' : Service : '.') end end end else // OIColumnValue = Calculate(OIColumnName) ; // Actual logic used in MFS OIColumnValue = Xlate(OITablename, OIKeyID, OIColumnName, 'X') end If (AMVPosition NE '') AND (IsOIKey NE True$) then OIColumnValue = OIColumnValue<0, AMVPosition> end Begin Case Case SQLColumnType _EQC 'uniqueidentifier' OIColumnValue = 'NEWID()' Case OIColumnValue EQ '' // Empty strings are treated as NULL values. OIColumnValue = 'NULL' Case InList('varchar,nvarchar,char,nchar', SQLColumnType, ',') // Single quote the value. SQLColumnLength = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnLength') OIColumnConv = FieldArray If OIColumnConv NE '' then OIColumnValue = Fmt(OIColumnValue, OIColumnConv) end If (SQLColumnLength EQ '') OR (SQLColumnLength EQ '-1') then SQLColumnLength = Len(OIColumnValue) OIColumnValue = OIColumnValue[1, SQLColumnLength, 1] Swap "'" with "''" in OIColumnValue OIColumnValue = "'" : OIColumnValue : "'" Case InList('tinyint,smallint,bigint,int', SQLColumnType, ',') // Treat as an integer. OIColumnConv = 'MD0' If Len(OIColumnConv) then OIColumnValue = Fmt(OIColumnValue, OIColumnConv) If Not(Num(OIColumnValue)) then // Not a true number so format like a string. OIColumnValue = "'" : OIColumnValue : "'" end end else // Empty value so treat it as a NULL value. OIColumnValue = 'NULL' end Case InList('decimal,numeric,float,real', SQLColumnType, ',') // Treat as a floating point number using any OI column output conversion if it // exists. OIColumnConv = FieldArray Convert 'Z' to '' in OIColumnConv ; // No empty strings with numeric columns. If Len(OIColumnConv) then OIColumnValue = Fmt(OIColumnValue, OIColumnConv) If Not(Num(OIColumnValue)) then // Not a true number so format like a string. OIColumnValue = "'" : OIColumnValue : "'" end end else // Empty value so treat it as a NULL value. OIColumnValue = 'NULL' end Case SQLColumnType _EQC 'bit' // Treat as a Boolean, but only return a 1, 0, or NULL. If OIColumnValue EQ '' then OIColumnValue = 'NULL' end else If OIColumnValue NE False$ then OIColumnValue = True$ end Case SQLColumnType _EQC 'date' OIColumnValue = "'" : (SRP_Date('Format', OIColumnValue, 'YYYY-MM-DD')) : "'" Case SQLColumnType _EQC 'datetime' OIColumnValue = "'" : (SRP_DateTime('Format', OIColumnValue, 'YYYY-MM-DD hh:mm:ss')) : "'" Case SQLColumnType _EQC 'time' OIColumnValue = "'" : (SRP_Time('Format', OIColumnValue, 'hh:mm:ss')) : "'" Case Otherwise$ // Treat as a character type. SQLColumnLength = SRP_JSON(MapObj, 'GETVALUE', 'SQLColumnLength') OIColumnConv = FieldArray If OIColumnConv NE '' then OIColumnValue = Fmt(OIColumnValue, OIColumnConv) end If (SQLColumnLength EQ '') OR (SQLColumnLength EQ '-1') then SQLColumnLength = Len(OIColumnValue) OIColumnValue = OIColumnValue[1, SQLColumnLength, 1] Swap "'" with "''" in OIColumnValue OIColumnValue = "'" : OIColumnValue : "'" End Case // Basic conversion rules. Convert \09\ to ' ' in OIColumnValue Swap \0D0A\ with ' ' in OIColumnValue Convert @VM to '|' in OIColumnValue Convert @SVM to ' ' in OIColumnValue Convert @TM to ' ' in OIColumnValue Convert @STM to ' ' in OIColumnValue ColumnValues := OIColumnValue : @FM end SRP_JSON(MapObj, 'RELEASE') end Error_Services('Clear') ; // Any errors at this point would have been created during calculated column logic, which is unrelated to this service. end end While Error_Services('NoError') Next OIColumnName end ColumnValues[-1, 1] = '' end else Error_Services('Add', 'The OITableName, SQLTableName, OIKeyID, or OIRow argument was missing in the ' : Service : ' service.') end Response = ColumnValues end service //---------------------------------------------------------------------------------------------------------------------- // GetSQLInsertStatements // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // OIKeyID - The Key ID to the OpenInsight row being deleted from SQL. - [Required] // OIRow - The OpenInsight row associated with the OpenInsight Key ID. - [Optional] // OIColumns - An @FM delimited list of OpenInsight table columns that should only be used to write to SQL. If empty, // all columns that have a map defintion will be used. - [Optional] // // Returns an @FM delimited list of SQL insert statements for the SQL table mapped to the indicated OpenInsight table. // This will automatically create all SQL insert statements for secondary SQL tables as well. //---------------------------------------------------------------------------------------------------------------------- Service GetSQLInsertStatements(OITableName, OIKeyID, OIRow, OIColumns) Convert @Lower_Case to @Upper_Case in OITableName SQLInsertStatements = '' If (OITableName NE '') AND (OIKeyID NE '') AND (OIRow NE '') then // Start with the primary SQL table that is mapped to this OpenInsight table. PrimarySQLTableName = SQL_Services('GetPrimarySQLTable', OITableName) MappedSQLColumnNames = SQL_Services('GetMappedSQLColumnNames', OITableName, PrimarySQLTableName, OIColumns) If MappedSQLColumnNames NE '' then MappedSQLColumnNames := @FM MappedSQLColumnValues = SQL_Services('GetMappedSQLColumnValues', OITablename, PrimarySQLTableName, OIKeyID, OIRow, '', OIColumns) If MappedSQLColumnValues NE '' then MappedSQLColumnValues := @FM JoinedSQLColumnNames = SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, PrimarySQLTableName) If JoinedSQLColumnNames NE '' then MappedSQLColumnNames := JoinedSQLColumnNames : @FM JoinedSQLColumnValues = SQL_Services('GetMappedJoinedSQLColumnValues', OITableName, PrimarySQLTableName, OIKeyID, OIRow) MappedSQLColumnValues := JoinedSQLColumnValues : @FM end StaticSQLColumnNames = SQL_Services('GetStaticSQLColumnNames', OITableName) If StaticSQLColumnNames NE '' then MappedSQLColumnNames := StaticSQLColumnNames : @FM StaticSQLColumnValues = SQL_Services('GetStaticSQLColumnValues', OITableName) MappedSQLColumnValues := StaticSQLColumnValues : @FM end MappedSQLColumnNames[-1, 1] = '' MappedSQLColumnValues[-1, 1] = '' Swap @FM with ', ' in MappedSQLColumnNames Swap @FM with ", " in MappedSQLColumnValues SQLInsertStatement = 'INSERT INTO ' : PrimarySQLTableName : ' ' SQLInsertStatement := '(' SQLInsertStatement := MappedSQLColumnNames SQLInsertStatement := ') VALUES (' SQLInsertStatement := MappedSQLColumnValues SQLInsertStatement := ')' SQLInsertStatements := SQLInsertStatement : @FM If Error_Services('NoError') then // Add any secondary SQL table inserts that might be required. SecondarySQLTableNames = SQL_Services('GetSecondarySQLTables', OITableName) If SecondarySQLTableNames NE '' then For Each SecondarySQLTableName in SecondarySQLTableNames using @FM OIColumnValue = '' ; // Default to empty string. Update if AMV Master is found. NumPositions = 1 ; // Default to only 1 index position. Update if AMV Master is found. AMVMaster = SQL_Services('GetAMVMaster', OITableName, SecondarySQLTableName) If AMVMaster NE '' then FieldArray = Database_Services('ReadDataRow', 'DICT.' : OITablename, '%FIELDS%') If Error_Services('NoError') then Locate AMVMaster in FieldArray using @VM setting vPos then OIColumnType = FieldArray If OIColumnType EQ 'F' then OIColumnPos = FieldArray If OIColumnPos GT 0 then OIColumnValue = OIRow end else OIKeyPart = FieldArray OIColumnValue = Field(OIKeyID, '*', OIKeyPart, 1) end end else // OIColumnValue = Calculate(OIColumnName) ; // Actual logic used in MFS OIColumnValue = Xlate(OITablename, OIKeyID, OIColumnName, 'X') end NumPositions = DCount(OIColumnValue, @VM) end end end MappedSQLColumnNames = SQL_Services('GetMappedSQLColumnNames', OITableName, SecondarySQLTableName) If MappedSQLColumnNames NE '' then JoinedSQLColumnNames = SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, SecondarySQLTableName) If JoinedSQLColumnNames NE '' then MappedSQLColumnNames := @FM : JoinedSQLColumnNames end Swap @FM with ', ' in MappedSQLColumnNames For AMVPosition = 1 to NumPositions If OIColumnValue<0, AMVPosition> NE '' then MappedSQLColumnValues = SQL_Services('GetMappedSQLColumnValues', OITablename, SecondarySQLTableName, OIKeyID, OIRow, AMVPosition) If JoinedSQLColumnNames NE '' then JoinedSQLColumnValues = SQL_Services('GetMappedJoinedSQLColumnValues', OITableName, SecondarySQLTableName, OIKeyID, OIRow, AMVPosition) MappedSQLColumnValues := @FM : JoinedSQLColumnValues end Swap @FM with ', ' in MappedSQLColumnValues SQLInsertStatement = 'INSERT INTO ' : SecondarySQLTableName : ' ' SQLInsertStatement := '(' SQLInsertStatement := MappedSQLColumnNames SQLInsertStatement := ') VALUES (' SQLInsertStatement := MappedSQLColumnValues SQLInsertStatement := ')' SQLInsertStatements := SQLInsertStatement : @FM end Next AMVPosition end Next SecondarySQLTableName end end SQLInsertStatements[-1, 1] = '' end else Error_Services('Add', 'The OITableName, OIKeyID, or OIRow argument was missing in the ' : Service : ' service.') end Response = SQLInsertStatements end service //---------------------------------------------------------------------------------------------------------------------- // GetSQLUpdateStatements // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // OIKeyID - The Key ID to the OpenInsight row being deleted from SQL. - [Required] // OIRow - The OpenInsight row associated with the OpenInsight Key ID. - [Optional] // OIColumns - An @FM delimited list of OpenInsight table columns that should only be used to write to SQL. If empty, // all columns that have a map defintion will be used. - [Optional] // // Returns an @FM delimited list of SQL update statements for the SQL table mapped to the indicated OpenInsight table. // This will automatically create all SQL update statements for secondary SQL tables as well. //---------------------------------------------------------------------------------------------------------------------- Service GetSQLUpdateStatements(OITableName, OIKeyID, OIRow, OIColumns) Convert @Lower_Case to @Upper_Case in OITableName SQLUpdateStatements = '' If (OITableName NE '') AND (OIKeyID NE '') AND (OIRow NE '') then // Start with the primary SQL table that is mapped to this OpenInsight table. PrimarySQLTableName = SQL_Services('GetPrimarySQLTable', OITableName) JoinClause = SQL_Services('GetJoinClause', OITableName, PrimarySQLTableName, OIKeyID, OIRow) MappedSQLColumnNames = SQL_Services('GetMappedSQLColumnNames', OITableName, PrimarySQLTableName, OIColumns) If MappedSQLColumnNames NE '' then MappedSQLColumnNames := @FM MappedSQLColumnValues = SQL_Services('GetMappedSQLColumnValues', OITablename, PrimarySQLTableName, OIKeyID, OIRow, '', OIColumns) If MappedSQLColumnValues NE '' then MappedSQLColumnValues := @FM JoinedSQLColumnNames = SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, PrimarySQLTableName) StaticSQLColumnNames = SQL_Services('GetStaticSQLColumnNames', OITableName) If StaticSQLColumnNames NE '' then MappedSQLColumnNames := StaticSQLColumnNames : @FM StaticSQLColumnValues = SQL_Services('GetStaticSQLColumnValues', OITableName) MappedSQLColumnValues := StaticSQLColumnValues : @FM end MappedSQLColumnNames[-1, 1] = '' MappedSQLColumnValues[-1, 1] = '' SQLUpdateStatement = '' If MappedSQLColumnNames NE '' then SQLUpdateStatement := 'UPDATE ' : PrimarySQLTableName : ' SET ' For Each SQLColumnName in MappedSQLColumnNames using @FM setting fPos SQLUpdateStatement := SQLColumnName : '=' : MappedSQLColumnValues : ', ' Next SQLColumnName SQLUpdateStatement[-2, 1] = '' SQLUpdateStatement := 'WHERE ' SQLUpdateStatement := JoinClause : ' ' SQLUpdateStatements := SQLUpdateStatement : @FM end If Error_Services('NoError') then // Add any secondary SQL table inserts that might be required. SecondarySQLTableNames = SQL_Services('GetSecondarySQLTables', OITableName) If SecondarySQLTableNames NE '' then For Each SecondarySQLTableName in SecondarySQLTableNames using @FM OIColumnValue = '' ; // Default to empty string. Update if AMV Master is found. NumPositions = 1 ; // Default to only 1 index position. Update if AMV Master is found. AMVMaster = SQL_Services('GetAMVMaster', OITableName, SecondarySQLTableName) If AMVMaster NE '' then FieldArray = Database_Services('ReadDataRow', 'DICT.' : OITablename, '%FIELDS%') If Error_Services('NoError') then Locate AMVMaster in FieldArray using @VM setting vPos then OIColumnType = FieldArray If OIColumnType EQ 'F' then OIColumnPos = FieldArray If OIColumnPos GT 0 then OIColumnValue = OIRow end else OIKeyPart = FieldArray OIColumnValue = Field(OIKeyID, '*', OIKeyPart, 1) end end else // OIColumnValue = Calculate(OIColumnName) ; // Actual logic used in MFS OIColumnValue = Xlate(OITablename, OIKeyID, OIColumnName, 'X') end NumPositions = DCount(OIColumnValue, @VM) end end end // Remove all rows from the secondary table. These will be added back using the INSERT statements as needed. SQLUpdateStatement = 'DELETE FROM ' : SecondarySQLTableName : ' ' SQLUpdateStatement := 'WHERE ' SQLUpdateStatement := JoinClause SQLUpdateStatements := SQLUpdateStatement : @FM MappedSQLColumnNames = SQL_Services('GetMappedSQLColumnNames', OITableName, SecondarySQLTableName) If MappedSQLColumnNames NE '' then JoinedSQLColumnNames = SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, SecondarySQLTableName) If JoinedSQLColumnNames NE '' then MappedSQLColumnNames := @FM : JoinedSQLColumnNames end Swap @FM with ', ' in MappedSQLColumnNames For AMVPosition = 1 to NumPositions If OIColumnValue<0, AMVPosition> NE '' then MappedSQLColumnValues = SQL_Services('GetMappedSQLColumnValues', OITablename, SecondarySQLTableName, OIKeyID, OIRow, AMVPosition) If JoinedSQLColumnNames NE '' then JoinedSQLColumnValues = SQL_Services('GetMappedJoinedSQLColumnValues', OITableName, SecondarySQLTableName, OIKeyID, OIRow, AMVPosition) MappedSQLColumnValues := @FM : JoinedSQLColumnValues end Swap @FM with ', ' in MappedSQLColumnValues SQLUpdateStatement = 'INSERT INTO ' : SecondarySQLTableName : ' ' SQLUpdateStatement := '(' SQLUpdateStatement := MappedSQLColumnNames SQLUpdateStatement := ') VALUES (' SQLUpdateStatement := MappedSQLColumnValues SQLUpdateStatement := ')' SQLUpdateStatements := SQLUpdateStatement : @FM end Next AMVPosition end Next SecondarySQLTableName end end SQLUpdateStatements[-1, 1] = '' end else Error_Services('Add', 'The OITableName, OIKeyID, or OIRow argument was missing in the ' : Service : ' service.') end Response = SQLUpdateStatements end service //---------------------------------------------------------------------------------------------------------------------- // GetSQLMergeStatements // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // OIKeyID - The Key ID to the OpenInsight row being deleted from SQL. - [Required] // OIRow - The OpenInsight row associated with the OpenInsight Key ID. - [Optional] // OIColumns - An @FM delimited list of OpenInsight table columns that should only be used to write to SQL. If empty, // all columns that have a map defintion will be used. - [Optional] // // Returns an @FM delimited list of SQL insert statements for the SQL table mapped to the indicated OpenInsight table. // This will automatically create all SQL insert statements for secondary SQL tables as well. //---------------------------------------------------------------------------------------------------------------------- Service GetSQLMergeStatements(OITableName, OIKeyID, OIRow, OIColumns) Convert @Lower_Case to @Upper_Case in OITableName SQLInsertStatements = '' If (OITableName NE '') AND (OIKeyID NE '') AND (OIRow NE '') then // Start with the primary SQL table that is mapped to this OpenInsight table. PrimarySQLTableName = SQL_Services('GetPrimarySQLTable', OITableName) MappedSQLColumnNames = SQL_Services('GetMappedSQLColumnNames', OITableName, PrimarySQLTableName, OIColumns) MergeClause = SQL_Services('GetMergeClause', OITableName, PrimarySQLTableName, OIKeyID, OIRow) If MappedSQLColumnNames NE '' then MappedSQLColumnNames := @FM MappedSQLColumnValues = SQL_Services('GetMappedSQLColumnValues', OITablename, PrimarySQLTableName, OIKeyID, OIRow, '', OIColumns) If MappedSQLColumnValues NE '' then MappedSQLColumnValues := @FM JoinedSQLColumnNames = SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, PrimarySQLTableName) If JoinedSQLColumnNames NE '' then MappedSQLColumnNames := JoinedSQLColumnNames : @FM JoinedSQLColumnValues = SQL_Services('GetMappedJoinedSQLColumnValues', OITableName, PrimarySQLTableName, OIKeyID, OIRow) MappedSQLColumnValues := JoinedSQLColumnValues : @FM end StaticSQLColumnNames = SQL_Services('GetStaticSQLColumnNames', OITableName) If StaticSQLColumnNames NE '' then MappedSQLColumnNames := StaticSQLColumnNames : @FM StaticSQLColumnValues = SQL_Services('GetStaticSQLColumnValues', OITableName) MappedSQLColumnValues := StaticSQLColumnValues : @FM end MappedSQLColumnNames[-1, 1] = '' MappedSQLColumnValues[-1, 1] = '' Swap @FM with ', ' in MappedSQLColumnNames Swap @FM with ", " in MappedSQLColumnValues SQLInsertStatement = 'BEGIN ' SQLInsertStatement := 'SET NOCOUNT ON; ' SQLInsertStatement := 'MERGE ':PrimarySQLTableName:' AS tgt ' SQLInsertStatement := 'USING (VALUES (':MappedSQLColumnValues:')) AS src (':MappedSQLColumnNames:') ' SQLInsertStatement := 'ON (':MergeClause:') ' SQLInsertStatement := 'WHEN MATCHED THEN ' SQLInsertStatement := ' UPDATE SET ' For Each SQLColumnName in MappedSQLColumnNames using ','setting fPos SQLColumnName = Trim(SQLColumnName) SQLInsertStatement := SQLColumnName : ' = src.' : SQLColumnName : ', ' Next SQLColumnName SQLInsertStatement[-2, 1] = '' SQLInsertStatement := 'WHEN NOT MATCHED THEN ' SQLInsertStatement := ' INSERT (':MappedSQLColumnNames:') ' SQLInsertStatement := ' VALUES (':MappedSQLColumnValues:'); ' SQLInsertStatement := 'END;' SQLInsertStatements := SQLInsertStatement : @FM If Error_Services('NoError') then // Add any secondary SQL table inserts that might be required. SecondarySQLTableNames = SQL_Services('GetSecondarySQLTables', OITableName) If SecondarySQLTableNames NE '' then For Each SecondarySQLTableName in SecondarySQLTableNames using @FM OIColumnValue = '' ; // Default to empty string. Update if AMV Master is found. NumPositions = 1 ; // Default to only 1 index position. Update if AMV Master is found. AMVMaster = SQL_Services('GetAMVMaster', OITableName, SecondarySQLTableName) If AMVMaster NE '' then FieldArray = Database_Services('ReadDataRow', 'DICT.' : OITablename, '%FIELDS%') If Error_Services('NoError') then Locate AMVMaster in FieldArray using @VM setting vPos then OIColumnType = FieldArray If OIColumnType EQ 'F' then OIColumnPos = FieldArray If OIColumnPos GT 0 then OIColumnValue = OIRow end else OIKeyPart = FieldArray OIColumnValue = Field(OIKeyID, '*', OIKeyPart, 1) end end else // OIColumnValue = Calculate(OIColumnName) ; // Actual logic used in MFS OIColumnValue = Xlate(OITablename, OIKeyID, OIColumnName, 'X') end NumPositions = DCount(OIColumnValue, @VM) end end end MappedSQLColumnNames = SQL_Services('GetMappedSQLColumnNames', OITableName, SecondarySQLTableName) If MappedSQLColumnNames NE '' then JoinedSQLColumnNames = SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, SecondarySQLTableName) If JoinedSQLColumnNames NE '' then MappedSQLColumnNames := @FM : JoinedSQLColumnNames end Swap @FM with ', ' in MappedSQLColumnNames For AMVPosition = 1 to NumPositions If OIColumnValue<0, AMVPosition> NE '' then MergeClause = SQL_Services('GetMergeClause', OITableName, SecondarySQLTableName, OIKeyID, OIRow) MappedSQLColumnValues = SQL_Services('GetMappedSQLColumnValues', OITablename, SecondarySQLTableName, OIKeyID, OIRow, AMVPosition) If JoinedSQLColumnNames NE '' then JoinedSQLColumnValues = SQL_Services('GetMappedJoinedSQLColumnValues', OITableName, SecondarySQLTableName, OIKeyID, OIRow, AMVPosition) MappedSQLColumnValues := @FM : JoinedSQLColumnValues end Swap @FM with ', ' in MappedSQLColumnValues SQLInsertStatement = 'BEGIN ' SQLInsertStatement := 'SET NOCOUNT ON; ' SQLInsertStatement := 'MERGE ':SecondarySQLTableName:' AS tgt ' SQLInsertStatement := 'USING (VALUES (':MappedSQLColumnValues:')) AS src (':MappedSQLColumnNames:') ' SQLInsertStatement := 'ON (':MergeClause:') ' SQLInsertStatement := 'WHEN MATCHED THEN ' SQLInsertStatement := ' UPDATE SET ' For Each SQLColumnName in MappedSQLColumnNames using ',' setting fPos SQLColumnName = Trim(SQLColumnName) SQLInsertStatement := SQLColumnName : ' = src.' : SQLColumnName : ', ' Next SQLColumnName SQLInsertStatement[-2, 1] = '' SQLInsertStatement := 'WHEN NOT MATCHED THEN ' SQLInsertStatement := ' INSERT (':MappedSQLColumnNames:') ' SQLInsertStatement := ' VALUES (':MappedSQLColumnValues:'); ' SQLInsertStatement := 'END;' SQLInsertStatements := SQLInsertStatement : @FM end Next AMVPosition end Next SecondarySQLTableName end end SQLInsertStatements[-1, 1] = '' end else Error_Services('Add', 'The OITableName, OIKeyID, or OIRow argument was missing in the ' : Service : ' service.') end Response = SQLInsertStatements end service //---------------------------------------------------------------------------------------------------------------------- // GetSQLSelectStatement // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // OIKeyID - The Key ID to the OpenInsight row being deleted from SQL. - [Required] // OIRow - The OpenInsight row associated with the OpenInsight Key ID. - [Optional] // // Returns the SQL select statement for the indicated SQL table based on its mapping to the indicated OpenInsight table. //---------------------------------------------------------------------------------------------------------------------- Service GetSQLSelectStatement(OITableName, SQLTableName, OIKeyID, OIRow) Convert @Lower_Case to @Upper_Case in OITableName SQLSelectStatement = '' If (OITableName NE '') AND (SQLTableName NE '') AND (OIKeyID NE '') then JoinClause = SQL_Services('GetJoinClause', OITableName, SQLTableName, OIKeyID, OIRow, '', True$) If JoinClause NE '' then MappedSQLColumnNames = SQL_Services('GetMappedSQLColumnNames', OITableName, SQLTableName) If MappedSQLColumnNames NE '' then // Include the join columns among the columns being returned so their values can be updated in their // joined OpenInsight columns (if applicable). MappedSQLColumnNames := @FM : SQL_Services('GetMappedJoinedSQLColumnNames', OITableName, SQLTableName) Swap @FM with ', ' in MappedSQLColumnNames SQLSelectStatement := 'SELECT ' SQLSelectStatement := MappedSQLColumnNames : ' ' SQLSelectStatement := 'FROM ' : SQLTableName : ' ' SQLSelectStatement := 'WHERE ' SQLSelectStatement := JoinClause : ' ' end end end else Error_Services('Add', 'The OITableName, SQLTableName, or OIKeyID argument was missing in the ' : Service : ' service.') end Response = SQLSelectStatement end service //---------------------------------------------------------------------------------------------------------------------- // GetSQLDeleteStatements // // OITableName - The name of the OpenInsight table that is mapped to the SQL table. - [Required] // OIKeyID - The Key ID to the OpenInsight row being deleted from SQL. - [Required] // OIRow - The OpenInsight row associated with the OpenInsight Key ID. - [Optional] // // Returns an @FM delimited list of SQL delete statements for the SQL table mapped to the indicated OpenInsight table. // This will automatically create all SQL delete statements for secondary SQL tables as well. Note: OIRow will likely be // an empty string since most join clauses will be based on the OpenInsight Key ID. //---------------------------------------------------------------------------------------------------------------------- Service GetSQLDeleteStatements(OITableName, OIKeyID, OIRow) Convert @Lower_Case to @Upper_Case in OITableName SQLDeleteStatements = '' If (OITableName NE '') AND (OIKeyID NE '') then // Start with the primary SQL table that is mapped to this OpenInsight table. PrimarySQLTableName = SQL_Services('GetPrimarySQLTable', OITableName) JoinClause = SQL_Services('GetJoinClause', OITableName, PrimarySQLTableName, OIKeyID, OIRow, '', True$) SQLDeleteStatement = 'DELETE FROM ' : PrimarySQLTableName : ' ' SQLDeleteStatement := 'WHERE ' SQLDeleteStatement := JoinClause SQLDeleteStatements := SQLDeleteStatement : @FM // Add any secondary SQL table inserts that might be required. SecondarySQLTableNames = SQL_Services('GetSecondarySQLTables', OITableName) If SecondarySQLTableNames NE '' then For Each SecondarySQLTableName in SecondarySQLTableNames using @FM JoinClause = SQL_Services('GetJoinClause', OITableName, SecondarySQLTableName, OIKeyID, OIRow, '', True$) SQLDeleteStatement = 'DELETE FROM ' : SecondarySQLTableName : ' ' SQLDeleteStatement := 'WHERE ' SQLDeleteStatement := JoinClause SQLDeleteStatements := SQLDeleteStatement : @FM Next SecondarySQLTableName end SQLDeleteStatements[-1, 1] = '' end else Error_Services('Add', 'The OITableName or OIKeyID argument was missing in the ' : Service : ' service.') end Response = SQLDeleteStatements end service //---------------------------------------------------------------------------------------------------------------------- // PostSQLRequest // // This service can be used to post SQL queries to databases that are not reachable from the originating server. // Requests are processed within the ProcessSQLRequests service. // // Input: // ServerID - Key to SERVERS record containing external SQL database connection string // Query - SQL query to execute // // Output: // Response - Query response //---------------------------------------------------------------------------------------------------------------------- Service PostSQLRequest(ServerID, Query) Response = '' If (ServerID NE '') and (Query NE '') then RequestDate = Date() RequestTime = Time() RequestKeyID = @Station:'*':RequestDate :'*':RequestTime RequestRow = '' RequestRow = ServerID RequestRow = Query Database_Services('WriteDataRow', 'SQL_REQUESTS', RequestKeyID, RequestRow, True$, False$, True$) If Error_Services('NoError') then TimeExpired = False$ Start = GetTickCount() Loop RequestRow = Database_Services('ReadDataRow', 'SQL_REQUESTS', RequestKeyID) ResponseDate = RequestRow If ResponseDate NE '' then Response = RequestRow Response = SRP_Decode(Response) end // Time will expire after 60 seconds. If GetTickCount() - Start GE 60000 then TimeExpired = True$ Until (ResponseDate NE '') OR TimeExpired Sleepery(10) WinYield() Yield();Yield();Yield();Yield();Yield();Yield();Yield();Yield() Repeat If TimeExpired then Error_Services('Add', 'SQL request timed out in the ' : Service : ' service.') end Open 'SQL_REQUESTS' to hSQLRequests then Delete hSQLRequests, RequestKeyID else Null //Error_Services('Add', 'Error in ':Service:' service. Failed to delete SQL_REQUESTS ':RequestKeyID) end end end end else If RowExists('SQL_REQUESTS', RequestKeyID) then Open 'SQL_REQUESTS' to hSQLRequests then Delete hSQLRequests, RequestKeyID else Null //Error_Services('Add', 'Error in ':Service:' service. Failed to delete SQL_REQUESTS ':RequestKeyID) end end end Error_Services('Add', 'Null parameter passed into service call. All parameters are required.') end return //---------------------------------------------------------------------------------------------------------------------- // PostSQLStatement // // This service can be used to post SQL statements to databases that are not reachable from the originating server. // Requests are processed within the ProcessSQLRequests service. // // Input: // ServerID - Key to SERVERS record containing external SQL database connection string // Statement - SQL statement to execute // // Output: // Response - Query response //---------------------------------------------------------------------------------------------------------------------- Service PostSQLStatement(ServerID, Statement) Response = '' If (ServerID NE '') and (Statement NE '') then RequestDate = Date() RequestTime = Time() RequestKeyID = @Station:'*':RequestDate :'*':RequestTime RequestRow = '' RequestRow = ServerID RequestRow = Statement Database_Services('WriteDataRow', 'SQL_REQUESTS', RequestKeyID, RequestRow, True$, False$, True$) If Error_Services('HasError') then Error_Services('Add', 'Error in ':Service:' service. Failed to post SQL statement to queue!') end end else If RowExists('SQL_REQUESTS', RequestKeyID) then Open 'SQL_REQUESTS' to hSQLRequests then Delete hSQLRequests, RequestKeyID else Error_Services('Add', 'Error in ':Service:' service. Failed to delete SQL_REQUESTS ':RequestKeyID) end end end Error_Services('Add', 'Null parameter passed into service call. All parameters are required.') end return //---------------------------------------------------------------------------------------------------------------------- // ProcessSQLRequests // // Service that attempts to process external SQL requests. These requests are queued in the SQL_REQUESTS table. //---------------------------------------------------------------------------------------------------------------------- Service ProcessSQLRequests() hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') Lock hSysLists, ServiceKeyID then Tablename = 'SQL_REQUESTS' hSQLRequests = Database_Services('GetTableHandle', Tablename) If Error_Services('NoError') then GoSub ClearCursors Sentence = 'SELECT ':Tablename:' WITH RESPONSE_DATE EQ "" BY REQUEST_DATE BY REQUEST_TIME' Set_Status(0) Update_Index(Tablename, 'REQUEST_DATE', False$, True$) Update_Index(Tablename, 'REQUEST_TIME', False$, True$) Update_Index(Tablename, 'RESPONSE_DATE', False$, True$) Update_Index(Tablename, 'RESPONSE_TIME', False$, True$) RList(Sentence, TARGET_ACTIVELIST$, '', '', '') EOF = False$ Loop ReadNext RequestKeyID else EOF = True$ Until EOF RequestRow = Database_Services('ReadDataRow', 'SQL_REQUESTS', RequestKeyID) ServerID = RequestRow Query = RequestRow Response = SQL_Services('GetDataRows', ServerID, Query, 3) Response = SRP_Encode(Response) RequestRow = Date() RequestRow = Time() RequestRow = Response Database_Services('WriteDataRow', 'SQL_REQUESTS', RequestKeyID, RequestRow, True$, False$, True$) KeyLocked = Database_Services('IsKeyIDLocked', 'SQL_REQUESTS', RequestKeyID) If KeyLocked then Database_Services('ReleaseKeyIDLock', 'SQL_REQUESTS', RequestKeyID) Repeat // Cleanup really old requests (i.e. those that are older than 48 hours) GoSub ClearCursors Set_Status(0) CleanDate = Date() - 1 Sentence = 'SELECT ':Tablename:' WITH RESPONSE_DATE NE "" AND WITH RESPONSE_DATE LT ':Quote(OConv(CleanDate, 'D4/')) RList(Sentence, TARGET_ACTIVELIST$, '', '', '') EOF = False$ Loop ReadNext RequestKeyID else EOF = True$ Until EOF Database_Services('DeleteDataRow', 'SQL_REQUESTS', RequestKeyID) KeyLocked = Database_Services('IsKeyIDLocked', 'SQL_REQUESTS', RequestKeyID) If KeyLocked then Database_Services('ReleaseKeyIDLock', 'SQL_REQUESTS', RequestKeyID) Repeat // Cleanup old requests that may have been "abandoned" by the requesting process (i.e. those that are older // than two minutes). GoSub ClearCursors Set_Status(0) CleanTime = Time() - 240 Sentence = 'SELECT ':Tablename:' WITH RESPONSE_DATE NE "" AND WITH REQUEST_TIME LT ':Quote(OConv(CleanTime, 'MT')) RList(Sentence, TARGET_ACTIVELIST$, '', '', '') EOF = False$ Loop ReadNext RequestKeyID else EOF = True$ Until EOF Database_Services('DeleteDataRow', 'SQL_REQUESTS', RequestKeyID) KeyLocked = Database_Services('IsKeyIDLocked', 'SQL_REQUESTS', RequestKeyID) If KeyLocked then Database_Services('ReleaseKeyIDLock', 'SQL_REQUESTS', RequestKeyID) Repeat end else ErrorMsg = Error_Services('GetMessage') end Unlock hSysLists, ServiceKeyID else Null end end service //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ClearCursors: For counter = 0 to 8 ClearSelect counter Next counter return WriteLog: Declare function Environment_Services, Logging_Services Declare subroutine Logging_Services LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Replication' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' WRITE_OI_Error.csv' Headers = 'Logging DTM' : @FM : 'User' : @FM : 'Table' :@FM : 'Key' objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM LogData = '' LogData<1, 1> = LoggingDTM LogData<1, 2> = @User4 LogData<1, 3> = OITableName LogData<1, 4> = OIKeyID LogData<1, 5> = Message Logging_Services('AppendLog', objLog, LogData, @FM, @VM) return