You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache Ignite含TOP关键字的SQL查询执行报错问题

问题:Apache Ignite含TOP关键字的SQL查询在Continuous Query中报错

问题背景

普通SQL查询在Apache Ignite中可正常执行,但包含TOP关键字的查询在Continuous Query场景下报错。

报错查询语句

SELECT TOP(5) a.* FROM "Orders".ORDER a WHERE IsOptionTrade=FALSE AND (ACCOUNT IN ('10001', '10002', '10003'))

报错发生的代码片段

public IEnumerable QueryContinous(string initalquery, string predicateExpression, string queryKey, ref long seekinfo)
{
    if (string.IsNullOrEmpty(predicateExpression))
        predicateExpression = "1 == 1";

    if (ListenerLookup.ContainsKey(queryKey))
    {
        if (predicateExpression == ListenerLookup[queryKey].PredicateExpr)
            return Query(initalquery, ref seekinfo);
        else
        {
            logger.Warn($"PredicateExpression:{predicateExpression} is Different from ListenerLookUp PredicateExpression:{ListenerLookup[queryKey].PredicateExpr}");
            Unsubscribe(queryKey);
        }
        
    }

    var listener = new Listener(queryKey);
    listener.OnUpdate += Listener_OnUpdate;

    var qry = new ContinuousQuery(listener)
    {
        Filter = new RemoteFilter()
        {
            Query = predicateExpression,
            IsWildListener = string.IsNullOrEmpty(predicateExpression)
        }
        
    };

    var initialQry = new SqlQuery(typeof(TV), initalquery);
    var queryHandle = Cache.QueryContinuous(qry, initialQry);// **报错发生位置**

    var listenerDetails = new ListenerDetails()
    {
        QueryHandle = queryHandle,
        listener = listener

    };


    listenerDetails.PredicateExpr = predicateExpression;
    listenerDetails.Predicate = System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(ParsingConfig.Default, true, predicateExpression).Compile();

    
    ListenerLookup.Add(queryKey, listenerDetails);

    return createList(queryHandle.GetInitialQueryCursor(), ref seekInfo);
}

错误信息

* Error Message : Apache.Ignite.Core.Common.IgniteException: Failed to parse query. Syntax error in SQL statement SELECT TOP 10 A._KEY, TOP 10[*] A._VAL FROM ""Orders""".""ORDER"" A WHERE ISOPTIONTRADE=FALSE AND  ( ACCOUNT IN (  '10001', '10002', '10003' ) ) ; 
 SQL statement: SELECT TOP 10 a._KEY, TOP 10 a._VAL FROM "Orders"."ORDER" a WHERE IsOptionTrade=FALSE AND  ( Account IN (  '10001', '10002', '10003' ) ) [42000-197] ---> Apache.Ignite.Core.Common.JavaException: class org.apache.ignite.IgniteCheckedException: Failed to parse query. Syntax error in SQL statement SELECT TOP 10 A._KEY, TOP 10[*] A._VAL FROM ""Orders""".""ORDER"" A WHERE ISOPTIONTRADE=FALSE AND  ( ACCOUNT IN (  '10001', '10002', '10003' ) ) ; 
 SQL statement:SELECT TOP 10 a._KEY, TOP 10 a._VAL FROM "Orders"."ORDER" a WHERE IsOptionTrade=FALSE AND  ( Account IN (  '10001', '10002','10003') ) [42000-197] 
 at org.apache.ignite.internal.processors.platform.utils.PlatformUtils.unwrapQueryException(PlatformUtils.java:520) 
 at org.apache.ignite.internal.processors.platform.cache.PlatformCache.runQuery(PlatformCache.java:1242) 
 at org.apache.ignite.internal.processors.platform.cache.PlatformCache.processInStreamOutObject(PlatformCache.java:883) 
 at org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.inStreamOutObject(PlatformTargetProxyImpl.java:79)
* Caused by: javax.cache.CacheException: Failed to parse query.Syntax error in SQL statement SELECT TOP 10 A._KEY, TOP 10[*] A._VAL FROM ""Orders""".""ORDER"" A WHERE ISOPTIONTRADE=FALSE AND  ( ACCOUNT IN (  '10001', '10002', '10003' ) ) ; 
SQL statement: SELECT TOP 10 a._KEY, TOP 10 a._VAL FROM "Orders"."ORDER" a WHERE IsOptionTrade=FALSE AND  ( Account IN (  '10001', '10002', '10003' ) ) [42000-197] 
 at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.query(IgniteCacheProxyImpl.java:697) 
 at org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.query(GatewayProtectedCacheProxy.java:376) 
 at org.apache.ignite.internal.processors.platform.cache.PlatformCache.runQuery(PlatformCache.java:1236)
... 2 more
* Caused by: class org.apache.ignite.internal.processors.query.IgniteSQLException: Failed to parse query. Syntax error in SQL statement SELECT TOP 10 A._KEY, TOP 10[*] A._VAL FROM ""Orders""".""ORDER"" A WHERE ISOPTIONTRADE=FALSE AND  ( ACCOUNT IN (  '10001', '10002', '10003' ) ) ; 
SQL statement:SELECT TOP 10 a._KEY, TOP 10 a._VAL FROM "Orders"."ORDER" a WHERE IsOptionTrade=FALSE AND  ( Account IN (  '10001', '10002', '10003' ) ) [42000-197] 
 at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepareStatementAndCaches(IgniteH2Indexing.java:2653) 
 at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.parseAndSplit(IgniteH2Indexing.java:2356) 
 at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.querySqlFields(IgniteH2Indexing.java:2196) 
 at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.queryDistributedSql(IgniteH2Indexing.java:1873) 
 at org.apache.ignite.internal.processors.query.GridQueryProcessor$7.applyx(GridQueryProcessor.java:2282) 
 at org.apache.ignite.internal.processors.query.GridQueryProcessor$7.applyx(GridQueryProcessor.java:2280) 
 at org.apache.ignite.internal.util.lang.IgniteOutClosureX.apply(IgniteOutClosureX.java:36) 
 at org.apache.ignite.internal.processors.query.GridQueryProcessor.executeQuery(GridQueryProcessor.java:2693) 
 at org.apache.ignite.internal.processors.query.GridQueryProcessor.queryDistributedSql(GridQueryProcessor.java:2279) 
 at org.apache.ignite.internal.processors.query.GridQueryProcessor.querySql(GridQueryProcessor.java:2260) 
 at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.query(IgniteCacheProxyImpl.java:682)
... 4 more
* Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement SELECT TOP 10 A._KEY, TOP 10[*] A._VAL FROM ""Orders""".""ORDER"" A WHERE ISOPTIONTRADE=FALSE AND  ( ACCOUNT IN (  '10001', '10002', '10003' ) ) ;
 SQL statement: SELECT TOP 10 a._KEY, TOP 10 a._VAL FROM "Orders"."ORDER" a WHERE IsOptionTrade=FALSE AND  ( Account IN (  '10001', '10002', '10003' ) ) [42000-197] 
 at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
 at org.h2.message.DbException.get(DbException.java:179)
 at org.h2.message.DbException.get(DbException.java:155)
 at org.h2.message.DbException.getSyntaxError(DbException.java:203)
 at org.h2.command.Parser.getSyntaxError(Parser.java:548)
 at org.h2.command.Parser.prepareCommand(Parser.java:281)
 at org.h2.engine.Session.prepareLocal(Session.java:611)
 at org.h2.engine.Session.prepareCommand(Session.java:549)
 at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1247)
 at org.h2.jdbc.JdbcPreparedStatement.(JdbcPreparedStatement.java:76)
 at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:694)
 at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepare0(IgniteH2Indexing.java:539) 
 at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepareStatement(IgniteH2Indexing.java:509) 
 at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepareStatement(IgniteH2Indexing.java:476) 
 at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepareStatementAndCaches(IgniteH2Indexing.java:2635)
... 14 more
 at Apache.Ignite.Core.Impl.Unmanaged.Jni.Env.ExceptionCheck()
 at Apache.Ignite.Core.Impl.Unmanaged.Jni.Env.CallObjectMethod(GlobalRef obj, IntPtr methodId, Int64* argsPtr)
 at Apache.Ignite.Core.Impl.Unmanaged.UnmanagedUtils.TargetInStreamOutObject(GlobalRef target, Int32 opType, Int64 inMemPtr)
 at Apache.Ignite.Core.Impl.PlatformJniTarget.InStreamOutObject(Int32 type, Action`1 writeAction)

报错原因分析

从错误信息可见,Ignite自动将原始查询转换为SELECT TOP 10 a._KEY, TOP 10 a._VAL FROM ...的形式——TOP关键字被错误地重复应用到每个查询字段前,违反SQL语法规范,导致H2解析器报错。

问题根源是使用SqlQuery类作为Continuous Query的初始查询时,Ignite会自动将用户提供的SELECT ...语句转换为查询缓存内部_KEY和_VAL字段的语句,但未正确处理TOP关键字的位置,导致TOP被错误添加到每个字段上。

解决方法

方法1:改用SqlFieldsQuery替代SqlQuery

SqlFieldsQuery不会自动修改用户提供的SQL语句,直接执行原始查询,避免Ignite自动转换逻辑带来的问题。

修改代码中的初始查询创建逻辑:

// 替换原有SqlQuery创建代码
// var initialQry = new SqlQuery(typeof(TV), initalquery);
var initialQry = new SqlFieldsQuery(initalquery);

注意:使用SqlFieldsQuery后,GetInitialQueryCursor()返回IFieldsQueryCursor<IList<object>>,需调整createList方法实现,适配字段集合的处理逻辑。

方法2:替换TOP为标准SQL的LIMIT子句

Ignite支持标准SQL的LIMIT语法,将查询语句中的TOP替换为LIMIT,可避免Ignite转换查询时的语法错误:

SELECT a.* FROM "Orders".ORDER a WHERE IsOptionTrade=FALSE AND (ACCOUNT IN ('10001', '10002', '10003')) LIMIT 5

内容的提问来源于stack exchange,提问作者adnan zafar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:35:29