go to post Joel Solon · Jan 3, 2024 Some more thoughts on this: If the 3rd party system claims that they're not starting a transaction, but you have evidence that a transaction is starting, it would be good to try to work together to get to the bottom of that. Of course that's up to you. It's best to get the WRC involved. Transactions are an application thing, not a user-oriented thing. There is no way to say "prevent user X or role Y from starting a transaction." There is a potential reason for the 3rd party system to be using transactions even when simply reading data with SELECT, known as Isolation Level. Read about it here. To establish Isolation Level, you can use SET TRANSACTION (which doesn't start a transaction), or START TRANSACTION (which obviously does start a transaction). By default, a SELECT shows you all the matching rows, even rows that are uncommitted (changes to those rows could be rolled back). ISOLATION LEVEL READ COMMITTED is used when you want to guarantee that a SELECT shows you only committed data, although this may result in the SELECT failing to complete when it reaches a row that has not been committed yet. So maybe the 3rd party system is using START TRANSACTION for that. Maybe they could switch to SET TRANSACTION instead. Edit: Unfortunately, IRIS does not provide the ability to GRANT or REVOKE the ability to use SET/START TRANSACTION. You wrote "If they have a process that is starting a transaction, i want it to fail/return an error to them." But wouldn't that prevent any of their queries from running? In other words, since the 3rd party system always starts a transaction, and that behavior can't be turned off, IRIS would return an error every time, and the query wouldn't run.
go to post Joel Solon · Dec 29, 2023 I edited this post and made some corrections below. I think the Community needs more information in order to help you. Data for %Persistent classes is stored in globals. Data for %SerialObject classes is also stored in globals. Properties of %Persistent classes can reference %SerialObject classes, and when the %Persistent data is saved, the referenced %SerialObject data is also stored in globals. The decision about whether to create %Persistent or %SerialObject classes for storing data is an object modeling decision, unrelated to the need to purge data on some schedule. Changing classes from %Persistent to %SerialObject (or vice versa) for an existing application is a major design change which would probably require plenty of code rewrites. I don't think anyone would do that work just for the sake of purging. There must be something else going on. Semi-educated guess: Maybe when you say "purging" you're talking about purging messages in interoperability productions. These messages have message headers, message bodies, and the bodies may have properties that reference %Persistent or %SerialObject objects. When you purge those messages, you have the option to purge message bodies, but if the bodies reference %Persistent objects, the referenced objects are not purged. Maybe that's what you're seeing, and maybe that's why you're thinking of switching storage definitions. There is certainly a way to make sure that any referenced objects get purged when messages are purged, documented (briefly) here. The WRC can also offer assistance. Please tell us if my semi-educated guess is correct, or if not, please give us more information. Happy New Year!
go to post Joel Solon · Dec 19, 2023 Very interesting question! In case anyone is wondering, in Studio you can access this info in the Workspace View on the Namespace tab or the Project tab. Right-click on the package name, and click Package Information. The information entered here is stored in the ^oddPKG global, subscripted by package name. There doesn't appear to be a way to access this information in VS Code. I think it's worth creating an issue for this here (VS Code ObjectScript issues) and see what happens.
go to post Joel Solon · Dec 18, 2023 I'm not exactly sure what fast shutdown is so I don't know the answer. I'm also not sure if "iris force" is the same as fast shutdown. I suppose they could be similar. When you do "iris force" IRIS runs an irisstat to capture the pre-force state and writes it to messages.log; fast shutdown doesn't do that. Edit: I also learned that fast shutdown waits for our system daemons to quiesce whereas iris force doesn't wait. @Eduard Lebedyuk: despite that behavior, maybe iris force takes longer because it runs irisstat.
go to post Joel Solon · Dec 18, 2023 It is ideal to stop IRIS before stopping the OS. However, if you stop the OS while IRIS is still running, IRIS can handle it. Check the IRIS messages.log after you shut down the OS, and you'll see lines like these: 10/16/23-18:11:04.649 (5940) 1 [Generic.Event] Operating System shutdown! InterSystems IRIS performing fast shutdown. 10/16/23-18:11:06.001 (5940) 1 [Generic.Event] Fast shutdown complete If your plan is to stop the OS and change the machine name, then definitely shut down IRIS in advance of stopping the OS.
go to post Joel Solon · Dec 13, 2023 I think it's really important that you find out why the tool is written to start a transaction before every query.
go to post Joel Solon · Oct 16, 2023 The three techniques for using SQL in your code (Class queries, Dynamic SQL, Embedded SQL) each have their pros and cons. The %ObjectSelectMode and tResult.<column> (instead of tResult.%Get("<column>") ) features only work with Dynamic SQL.
go to post Joel Solon · Oct 16, 2023 Thanks Mihoko! Also note: the argument with ... after its name doesn't have to be the only argument to the method; it must be the last argument to the method. So NewMethod1()'s signature could be: ClassMethod NewMethod1(a as %String, b as %String, c... as %String) { kill ^a, ^b, ^c set ^a = a, ^b = b merge ^c = c } Running it like this: USER>DO ##class(TEST.ARGTEST1).NewMethod1(1,2,3,4,5,6,7) USER>ZWRITE ^a, ^b, ^c ^a=1 ^b=2 ^c=5 ^c(1)=3 ^c(2)=4 ^c(3)=5 ^c(4)=6 ^c(5)=7
go to post Joel Solon · Sep 13, 2023 So...if Person #1 in the above example references demo.intersystems.Car #54, the "Dan P big secretly loaded" copy of that Person object also references the same Car #54, right? @Timothy Leavitt, is that good or bad for your use case? Doesn't %ConstructClone(1) give you what you need? If not, where does it fall short?
go to post Joel Solon · Aug 24, 2023 Does this example make it clear? Does this meet your needs? USER>set human = ##class(Simple.Human).%OpenId(1) USER>zw human human=20@Simple.Human ; <OREF> +----------------- general information --------------- | oref value: 20 | class name: Simple.Human | %%OID: $lb("1","Simple.Human") | reference count: 2 +----------------- attribute values ------------------ | %Concurrency = 1 <Set> | Company = "GlobaDyne Inc." | Name = "Smith,John" | Phone = "265-288-5681" | Version = 2 +----------------- swizzled references --------------- | i%Home = $lb("6489 Clinton Street","Denver","NJ",26882) <Set> | r%Home = "" <Set> | i%Work = $lb("9353 Main Drive","Hialeah","MI",72997) <Set> | r%Work = "" <Set> +----------------------------------------------------- USER>write human.%IsModified() 0 USER>write human.PhoneIsModified() 0 USER>set human.Phone = "111-222-3333" USER>write human.%IsModified() 1 USER>write human.PhoneIsModified() 1 USER>write human.Home.Street 6489 Clinton Street USER>write human.Home.StreetIsModified() 0 USER>set human.Home.Street = "111 High Street" USER>write human.Home.StreetIsModified() 1 USER>
go to post Joel Solon · Aug 23, 2023 I think it would be great if you would explain the use case to the community. Why do you need to do your own property-by-property validation separate from %ValidateObject() Why are you using "m%"_Property and not just Property? Why can't you use the built-in propertyIsModified() method to verify if a property is modified?
go to post Joel Solon · Aug 7, 2023 After reading through this thread, it seems like there are two questions: What is the correct syntax for calling a method? That question has been answered by several posts. It's either using ..method2() if method2() is in the same class as method1(), or ##class(package.class).method2() if method2() is in a different package.class. Use "do" to call the method, or "set retval = " to call the method and capture the returned value. Why when I run method1() I get data, but when I add a call to method2() from inside method1() I get no data? As Davide suggested, using "adm" as an embedded SQL cursor in the GetDataExecute() method and the GetSphereJauh() method is probably causing the problem, so try changing the cursor name to "juah" in the declare, open, fetch and close statements in GetSphereJauh(). If that doesn't help, you should probably contact TrakCare Support and get their help.
go to post Joel Solon · Aug 7, 2023 Would it be possible for you to share your reason for wanting to do this with the community?
go to post Joel Solon · Jul 31, 2023 %Library.ResultSet (aka %ResultSet) is deprecated. You should switch to using %SQL.Statement instead. It's better in every way. Doc is here: Dynamic SQL and within that there's a section on Metadata.
go to post Joel Solon · Jun 8, 2023 Anything can be achieved without instance methods. The point here is that instance methods exist in object-oriented systems because they are considered a good, straightforward way to achieve certain things. In the case of unit tests sharing information using properties, that approach saves you from having to pass info around as method arguments, or declaring a list of public variables.
go to post Joel Solon · May 24, 2023 I've also used Studio for 20+ years. I can still remember how much better it was than what we had before. We can all still use Studio if we want; it's not a forced divorce. But we hope that VS Code -- ObjectScript's features will make you comfortable enough to decide to do a conscious uncoupling. And as Frank Sinatra sang: "Love's much lovelier, the second time around." And he could have sung that at the Diplomat Hotel in Fort Lauderdale in 1974, where coincidentally InterSystems is hosting our Global Summit this year!
go to post Joel Solon · May 24, 2023 In the interest of accuracy, Studio does allow looking at OREFS to see their properties (View As > Object, or Dump object).
go to post Joel Solon · May 23, 2023 Why are unit test methods instance methods? Since a running unit test is an instantiated object (%RegisteredObject), the unit test class itself can have custom properties, and the instance methods can use those properties as a way to share information. For example, initialize the properties in %OnBeforeAllTests(), and then access/change the properties in the test methods.
go to post Joel Solon · Apr 10, 2023 LAST_IDENTITY() returns the ID of the last record inserted, updated, or deleted. This is very useful from ODBC/JDBC. From within an ObjectScript method, you can access this directly instead of running an additional SELECT statement: For Embedded SQL, you can use the %ROWID variable. For Dynamic SQL, you can use the resultset.%ROWID property.