[IGN-5581]PyDataset over received from sendRequest behaves differently

I have setup this test to demonstrate an odd behavior I ran into today. Can anyone help explain what’s happening?

I have two buttons: local and gateway that have the following scripts on their respective actionPerformed event.

image

# Local Button
data = system.db.runPrepQuery('Select 1 WHERE 1=?',[1],'Ignition_Data')
print("# Local Return")
print data
print type(data)
print dir(data)
print data[0][0]
# Gateway Button
data = system.util.sendRequest(
	system.project.getProjectName(),
	'queryTest',
	{}
)
print('# gateway return')
print data
print type(data)
print dir(data)
print data[0][0]

The message handler has the following script:

	_l = system.util.getLogger('Query Test')
	_l.info('Message handler called successfully!')
	return system.db.runPrepQuery('Select 1 WHERE 1=?',[1],'Ignition_Data')

When I push ‘local’ I get this in the diagnostics window:

# Local Return
<PyDataset rows:1 cols:1>
<type 'com.inductiveautomation.ignition.common.script.builtin.DatasetUtilities$PyDataSet'>
['__add__', '__class__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__ensure_finalizer__', '__eq__', '__finditem__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__', '__subclasshook__', 'binarySearch', 'columnCount', 'columnNames', 'columnTypes', 'data', 'getColumnAsList', 'getColumnCount', 'getColumnIndex', 'getColumnName', 'getColumnNames', 'getColumnType', 'getColumnTypes', 'getPrimitiveValueAt', 'getQualityAt', 'getRowCount', 'getUnderlyingDataset', 'getValueAt', 'hasQualityData', 'isSequenceType', 'rowCount', 'sequenceType', 'setData', 'toString', 'underlyingDataset']
1

When I push ‘global’ I get this:

# gateway return
<PyDataset rows:1 cols:1>
<type 'com.inductiveautomation.ignition.common.script.builtin.DatasetUtilities$PyDataSet'>
['__add__', '__class__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__ensure_finalizer__', '__eq__', '__finditem__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__', '__subclasshook__', 'binarySearch', 'columnCount', 'columnNames', 'columnTypes', 'data', 'getColumnAsList', 'getColumnCount', 'getColumnIndex', 'getColumnName', 'getColumnNames', 'getColumnType', 'getColumnTypes', 'getPrimitiveValueAt', 'getQualityAt', 'getRowCount', 'getUnderlyingDataset', 'getValueAt', 'hasQualityData', 'isSequenceType', 'rowCount', 'sequenceType', 'setData', 'toString', 'underlyingDataset']
12:10:30.279 [AWT-EventQueue-0] ERROR com.inductiveautomation.ignition.client.util.gui.ErrorUtil - <HTML>Error executing script for event:&nbsp;<code><b>actionPerformed</b></code><BR>on component:&nbsp;<code><b>Button 1</b></code>.
com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last):
  File "<event:actionPerformed>", line 11, in <module>
java.lang.NullPointerException
	at com.inductiveautomation.ignition.common.script.builtin.DatasetUtilities$PyDataSet.pyget(DatasetUtilities.java:123)
	at org.python.core.PySequence$DefaultIndexDelegate.getItem(PySequence.java:532)
	at org.python.core.SequenceIndexDelegate.checkIdxAndFindItem(SequenceIndexDelegate.java:88)
	at org.python.core.SequenceIndexDelegate.checkIdxAndFindItem(SequenceIndexDelegate.java:70)
	at org.python.core.SequenceIndexDelegate.checkIdxAndGetItem(SequenceIndexDelegate.java:61)
	at org.python.core.PySequence.seq___getitem__(PySequence.java:377)
	at org.python.core.PySequence.__getitem__(PySequence.java:373)
	at org.python.pycode._pyx6.f$0(<event:actionPerformed>:11)
	at org.python.pycode._pyx6.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:171)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1614)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:799)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:206)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:297)
	at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:57)
	at com.sun.proxy.$Proxy40.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
java.lang.NullPointerException: java.lang.NullPointerException

	at org.python.core.Py.JavaError(Py.java:552)
	at org.python.core.PyTableCode.call(PyTableCode.java:180)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1614)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:799)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:206)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:297)
	at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:57)
	at com.sun.proxy.$Proxy40.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Caused by: org.python.core.PyException: Traceback (most recent call last):
  File "<event:actionPerformed>", line 11, in <module>
java.lang.NullPointerException
	at com.inductiveautomation.ignition.common.script.builtin.DatasetUtilities$PyDataSet.pyget(DatasetUtilities.java:123)
	at org.python.core.PySequence$DefaultIndexDelegate.getItem(PySequence.java:532)
	at org.python.core.SequenceIndexDelegate.checkIdxAndFindItem(SequenceIndexDelegate.java:88)
	at org.python.core.SequenceIndexDelegate.checkIdxAndFindItem(SequenceIndexDelegate.java:70)
	at org.python.core.SequenceIndexDelegate.checkIdxAndGetItem(SequenceIndexDelegate.java:61)
	at org.python.core.PySequence.seq___getitem__(PySequence.java:377)
	at org.python.core.PySequence.__getitem__(PySequence.java:373)
	at org.python.pycode._pyx6.f$0(<event:actionPerformed>:11)
	at org.python.pycode._pyx6.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:171)
	at org.python.core.PyCode.call(PyCode.java:18)
	at org.python.core.Py.runCode(Py.java:1614)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:799)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.runActions(ActionAdapter.java:206)
	at com.inductiveautomation.factorypmi.application.binding.action.ActionAdapter.invoke(ActionAdapter.java:297)
	at com.inductiveautomation.factorypmi.application.binding.action.RelayInvocationHandler.invoke(RelayInvocationHandler.java:57)
	at com.sun.proxy.$Proxy40.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
java.lang.NullPointerException: java.lang.NullPointerException

	... 44 common frames omitted
Caused by: java.lang.NullPointerException: null
	at com.inductiveautomation.ignition.common.script.builtin.DatasetUtilities$PyDataSet.pyget(DatasetUtilities.java:123)
	at org.python.core.PySequence$DefaultIndexDelegate.getItem(PySequence.java:532)
	at org.python.core.SequenceIndexDelegate.checkIdxAndFindItem(SequenceIndexDelegate.java:88)
	at org.python.core.SequenceIndexDelegate.checkIdxAndFindItem(SequenceIndexDelegate.java:70)
	at org.python.core.SequenceIndexDelegate.checkIdxAndGetItem(SequenceIndexDelegate.java:61)
	at org.python.core.PySequence.seq___getitem__(PySequence.java:377)
	at org.python.core.PySequence.__getitem__(PySequence.java:373)
	at org.python.pycode._pyx6.f$0(<event:actionPerformed>:11)
	at org.python.pycode._pyx6.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:171)
	... 42 common frames omitted

and the logging from the message handler is performed as expected

Why do two PyDataset objects that claim to be the same type with the same python methods behave differently when trying to access data? I know that the queries are called from different scopes (client vs gateway), but I wouldn’t think the origin would matter for data of the same type.

Ignition Version: 8.1.5
Edit: Added Database name to both runPrepQuery calls because documentation suggests it’s required in the gateway scope. It didn’t seem to make a difference.

I'm pretty sure this is just a bug in our code. I'm going to mock up in the latest version, in case it's been incidentally fixed, but I think it's still possible.

As a work-around, convert from PyDataset to Dataset before returning from the message handler, and convert back to a PyDataset locally (if you need to).

2 Likes

Yeah, it’s just a bug in our code. I filed a ticket to get it fixed, but the easiest solution is to wrap in a standard dataset, then convert back if required.

1 Like

That worked. Thank you.