java.sql.SQLSyntaxErrorException with PersistentRecord

I’m trying to use a PersistentRecord to store settings for a web service.

Here’s the record:

[code]public class TierInterfaceSettingsRecord extends PersistentRecord {

private static final long serialVersionUID = 5609419912765113584L;
public static final RecordMeta<TierInterfaceSettingsRecord> META = new RecordMeta<TierInterfaceSettingsRecord>(TierInterfaceSettingsRecord.class, "TierInterfaceSettings");
public static final IntField Port = new IntField(META, "Port").setDefault(2000);

public Integer getPort() {
	return getInt(Port);
}

public void setPort(Integer port) {
	setInt(Port, port);
}

@Override
public RecordMeta<TierInterfaceSettingsRecord> getMeta() {
	return META;
}

}[/code]

Here’s my gateway hook:

public class IgnitionCellTier extends AbstractGatewayModuleHook { private Logger logger; private WebServiceManager wsm; private GatewayContext context; /* (non-Javadoc) * @see com.inductiveautomation.ignition.gateway.model.GatewayModuleHook#setup(com.inductiveautomation.ignition.gateway.model.GatewayContext) */ @Override public void setup(GatewayContext context) { this.context = context; logger = Logger.getLogger(getClass()); try { this.context.getSchemaUpdater().updatePersistentRecords(TierInterfaceSettingsRecord.META); } catch (SQLException e) { logger.error("Unable to update persistent record for tier interface settings.",e); } } .... }

That logger records this exception:

java.sql.SQLSyntaxErrorException: unexpected token: )

Any ideas where I went wrong here?

Hmm, looks good to me. Can you provide the stack trace for that error?

Regards,

Here you go:

java.sql.SQLSyntaxErrorException: unexpected token: ) at org.hsqldb.jdbc.Util.sqlException(Util.java:350) at org.hsqldb.jdbc.Util.sqlException(Util.java:227) at org.hsqldb.jdbc.JDBCStatement.fetchResult(JDBCStatement.java:1830) at org.hsqldb.jdbc.JDBCStatement.executeUpdate(JDBCStatement.java:207) at org.apache.commons.dbcp.DelegatingStatement.executeUpdate(DelegatingStatement.java:228) at com.inductiveautomation.ignition.gateway.localdb.hsql.DelegatingDataSource$DelegatingConnection$DelegatingStatement.executeUpdate(DelegatingDataSource.java:392) at com.inductiveautomation.ignition.gateway.localdb.DatasourceDBInterface.runUpdateQuery(DatasourceDBInterface.java:220) at com.inductiveautomation.ignition.gateway.localdb.LocalDBManagerImpl$SingleConnectionDBInterface.runUpdateQuery(LocalDBManagerImpl.java:489) at com.inductiveautomation.ignition.gateway.localdb.LocalDBManagerImpl.updatePersistentRecords(LocalDBManagerImpl.java:392) at com.inductiveautomation.ignition.gateway.localdb.LocalDBManagerImpl.updatePersistentRecords(LocalDBManagerImpl.java:334) at com.inductiveautomation.ignition.gateway.localdb.LocalDBManagerImpl.updatePersistentRecords(LocalDBManagerImpl.java:324) at com.company.project.cell.ignition.IgnitionCellTier.setup(Unknown Source) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl$LoadedModule.setup(ModuleManagerImpl.java:1970) at com.inductiveautomation.ignition.gateway.modules.ModuleManagerImpl.setup(ModuleManagerImpl.java:226) at com.inductiveautomation.ignition.gateway.SRContext.startupInternal(SRContext.java:919) at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl.startup(RedundancyManagerImpl.java:182) at com.inductiveautomation.ignition.gateway.SRContext.asyncInit(SRContext.java:708) at com.inductiveautomation.ignition.gateway.SRContext.access$200(SRContext.java:187) at com.inductiveautomation.ignition.gateway.SRContext$2.run(SRContext.java:536) at com.inductiveautomation.ignition.common.execution.impl.BasicExecutionEngine$ThrowableCatchingRunnable.run(BasicExecutionEngine.java:526) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) Caused by: org.hsqldb.HsqlException: unexpected token: ) at org.hsqldb.error.Error.parseError(Error.java:99) at org.hsqldb.ParserBase.unexpectedToken(ParserBase.java:795) at org.hsqldb.ParserBase.checkIsSimpleName(ParserBase.java:399) at org.hsqldb.ParserDQL.readColumnNameList(ParserDQL.java:679) at org.hsqldb.ParserDQL.readColumnNames(ParserDQL.java:660) at org.hsqldb.ParserDQL.readColumnNames(ParserDQL.java:651) at org.hsqldb.ParserDDL.compileAlterTableAddPrimaryKey(ParserDDL.java:3571) at org.hsqldb.ParserDDL.compileAlterTable(ParserDDL.java:662) at org.hsqldb.ParserDDL.compileAlter(ParserDDL.java:281) at org.hsqldb.ParserCommand.compilePart(ParserCommand.java:222) at org.hsqldb.ParserCommand.compileStatements(ParserCommand.java:91) at org.hsqldb.Session.executeDirectStatement(Session.java:1203) at org.hsqldb.Session.execute(Session.java:1002) at org.hsqldb.jdbc.JDBCStatement.fetchResult(JDBCStatement.java:1822) ... 25 more

Hi,

Looking at that stack trace, I suspect it’s probably trying to add a primary key to the table, where one isn’t defined. Off the top of my head I’m not sure if the ORM system requires a primary key on the table, but I wouldn’t be surprised. All of the PersistentRecord types I can find in Ignition have some sort of primary key. You might try adding one to your record:

public static final IdentityField Id = new IdentityField(META);

Beyond that, to see exactly what query is causing the problem, you would need to turn the logger for the class “LocalDBManagerImpl” to “DEBUG”, and then reload the module. You might be able to set the logger to this level in the gateway, and then republish your dev module, or you might need to set it in the log4j.properties file (add the following, the file is in the “data” folder) and restart the gateway:

log4j.logger.com.inductiveautomation.ignition.gateway.localdb.LocalDBManagerImpl=DEBUG

When your module starts, you’ll see a message like “Automatic schema update phase2:…” right before the error.

I recommend trying the identity field first, however. I really suspect that’s the culprit.

Regards,

That identity field seems to have done the trick, thanks!

Ok, good. If we’re going to require a primary key, we should probably throw an informative error, instead of simply running a bad query. I should probably also update the programmer’s guide and javadocs.

Regards,

Out of curiosity - is there anything like this for database connections other than the internal one? I was looking at the DatabaseRecord but am not quite sure if that’s the right direction. It insisted that the getMeta method return a RecordMeta instead of RecordMeta.

No, there isn’t an ORM system for regular database connections. I would imagine that it should be possible to find/pick one and work it in if you wanted, but that would probably be a bit of work.

In general, everything in Ignition is done with queries, built with some care and use of the DB Translators, in order to squeeze out maximum performance, which ORMs aren’t known for. However, for simply making it easy to work with database data, it probably is a little strange that we don’t have a system like this. But ultimately, I don’t really think we will be adding it anytime soon.

Regards,

[quote=“Colby.Clegg”]Ok, good. If we’re going to require a primary key, we should probably throw an informative error, instead of simply running a bad query. I should probably also update the programmer’s guide and javadocs.

Regards,[/quote]
Just a quick update - forgot this issue when working on extending the auth system in 7.4.2 and ran into the same exception for the “unexpected token”. Adding the primary key cleared it up again.