Merge branch 'ignite-1786' into ignite-2627
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/c16549cd Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/c16549cd Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/c16549cd Branch: refs/heads/ignite-1786 Commit: c16549cd8866929b7974c18c867954a4c8c2504a Parents: feb8350 b127a5d Author: isapego <[email protected]> Authored: Mon Feb 15 22:26:09 2016 +0300 Committer: isapego <[email protected]> Committed: Mon Feb 15 22:26:09 2016 +0300 ---------------------------------------------------------------------- .../apache/ignite/cache/CacheMemoryMode.java | 2 + .../internal/GridMessageListenHandler.java | 16 + .../apache/ignite/internal/IgniteKernal.java | 14 +- .../ignite/internal/binary/BinaryUtils.java | 4 +- .../binary/builder/BinaryBuilderSerializer.java | 16 +- .../binary/builder/BinaryObjectBuilderImpl.java | 12 +- .../binary/builder/BinaryValueWithType.java | 3 +- .../processors/cache/GridCacheAdapter.java | 11 +- .../cache/GridCacheClearAllRunnable.java | 2 +- .../processors/cache/GridCacheEntryEx.java | 11 +- .../processors/cache/GridCacheMapEntry.java | 102 ++-- .../processors/cache/GridCacheProcessor.java | 18 +- .../processors/cache/GridCacheSwapManager.java | 46 +- .../dht/GridDhtPartitionTopologyImpl.java | 7 +- .../GridDhtPartitionsExchangeFuture.java | 6 + .../continuous/GridContinuousProcessor.java | 48 +- .../processors/odbc/OdbcNioListener.java | 67 +-- .../processors/odbc/OdbcQueryCloseRequest.java | 7 + .../odbc/OdbcQueryExecuteRequest.java | 10 + .../processors/odbc/OdbcQueryFetchRequest.java | 7 + .../odbc/OdbcQueryGetColumnsMetaRequest.java | 6 + .../odbc/OdbcQueryGetTablesMetaRequest.java | 7 + .../processors/odbc/OdbcRequestHandler.java | 53 +- .../internal/processors/odbc/OdbcUtils.java | 13 + .../ignite/spi/discovery/tcp/ServerImpl.java | 5 + .../TcpDiscoveryCustomEventMessage.java | 10 +- .../apache/ignite/spi/indexing/IndexingSpi.java | 4 +- .../internal/GridAffinityNoCacheSelfTest.java | 8 +- .../internal/GridNodeMetricsLogSelfTest.java | 98 ++++ ...eClientReconnectContinuousProcessorTest.java | 32 +- .../BinaryObjectBuilderAdditionalSelfTest.java | 91 +++- ...naryObjectBuilderDefaultMappersSelfTest.java | 30 +- .../cache/CacheConfigurationLeakTest.java | 62 +++ .../GridCacheOffHeapValuesEvictionSelfTest.java | 43 +- .../processors/cache/GridCacheTestEntryEx.java | 5 +- .../GridCacheReplicatedPreloadSelfTest.java | 121 +++-- ...IgniteCacheContinuousQueryReconnectTest.java | 192 +++++++ .../GridSessionCheckpointAbstractSelfTest.java | 6 +- .../tcp/TcpClientDiscoverySpiSelfTest.java | 2 +- .../spi/discovery/tcp/TcpDiscoverySelfTest.java | 2 +- .../ignite/testsuites/IgniteBasicTestSuite.java | 2 + .../testsuites/IgniteCacheTestSuite2.java | 2 + .../p2p/CacheDeploymentAffinityKeyMapper.java | 35 ++ .../CacheDeploymentAlwaysTruePredicate2.java | 30 ++ ...oymentCacheEntryEventSerializableFilter.java | 32 ++ .../p2p/CacheDeploymentCacheEntryListener.java | 31 ++ ...CacheDeploymentCachePluginConfiguration.java | 74 +++ ...heDeploymentStoreSessionListenerFactory.java | 83 +++ .../query/h2/twostep/GridMergeIndex.java | 32 +- .../h2/twostep/GridMergeIndexUnsorted.java | 19 +- .../query/h2/twostep/GridMergeTable.java | 16 +- .../h2/twostep/GridReduceQueryExecutor.java | 2 +- .../CacheQueryOffheapEvictDataLostTest.java | 138 +++++ .../CacheRandomOperationsMultithreadedTest.java | 507 +++++++++++++++++++ .../near/IgniteCacheQueryNodeFailTest.java | 148 ++++++ .../IgniteCacheQuerySelfTestSuite.java | 7 + .../IgniteCacheWithIndexingTestSuite.java | 2 + modules/platforms/cpp/binary/Makefile.am | 4 +- .../platforms/cpp/binary/include/Makefile.am | 4 +- .../include/ignite/binary/binary_raw_reader.h | 42 +- .../include/ignite/binary/binary_raw_writer.h | 32 ++ .../include/ignite/binary/binary_reader.h | 44 ++ .../include/ignite/binary/binary_writer.h | 34 ++ .../platforms/cpp/binary/include/ignite/date.h | 138 +++++ .../include/ignite/impl/binary/binary_common.h | 6 + .../ignite/impl/binary/binary_reader_impl.h | 121 ++++- .../include/ignite/impl/binary/binary_utils.h | 34 ++ .../ignite/impl/binary/binary_writer_impl.h | 72 +++ .../cpp/binary/include/ignite/timestamp.h | 166 ++++++ .../cpp/binary/project/vs/binary.vcxproj | 4 + .../binary/project/vs/binary.vcxproj.filters | 12 + .../cpp/binary/src/binary/binary_raw_reader.cpp | 22 +- .../cpp/binary/src/binary/binary_raw_writer.cpp | 20 + .../cpp/binary/src/binary/binary_reader.cpp | 20 + .../cpp/binary/src/binary/binary_writer.cpp | 20 + modules/platforms/cpp/binary/src/date.cpp | 83 +++ .../src/impl/binary/binary_reader_impl.cpp | 144 ++++++ .../cpp/binary/src/impl/binary/binary_utils.cpp | 26 + .../src/impl/binary/binary_writer_impl.cpp | 148 +++++- modules/platforms/cpp/binary/src/timestamp.cpp | 117 +++++ .../cpp/core-test/config/cache-query.xml | 2 + .../include/ignite/binary_test_utils.h | 96 ++++ .../src/binary_reader_writer_raw_test.cpp | 124 +++++ .../core-test/src/binary_reader_writer_test.cpp | 192 +++++++ .../cpp/core-test/src/binary_session_test.cpp | 36 ++ .../cpp/core-test/src/cache_query_test.cpp | 269 ++++++++-- .../platforms/cpp/core-test/src/cache_test.cpp | 24 + .../Binary/BinaryStructureTest.cs | 38 +- .../Impl/Binary/BinaryReader.cs | 2 +- .../Common/IgniteConfigurationXmlSerializer.cs | 7 +- .../yardstick/cache/IgniteInvokeBenchmark.java | 65 +++ .../cache/IgniteInvokeTxBenchmark.java | 30 ++ .../tcp/ipfinder/zk/ZookeeperIpFinderTest.java | 2 +- 93 files changed, 4234 insertions(+), 325 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/c16549cd/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java ---------------------------------------------------------------------- diff --cc modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java index 1a7ece3,cf5585a..b0dc99e --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java @@@ -29,47 -28,54 +29,49 @@@ import org.apache.ignite.internal.proce import org.apache.ignite.internal.util.GridSpinBusyLock; import org.apache.ignite.internal.util.nio.GridNioServerListenerAdapter; import org.apache.ignite.internal.util.nio.GridNioSession; -import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.lang.IgniteBiTuple; +import org.apache.ignite.internal.util.typedef.internal.U; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.io.IOException; +import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; + import java.util.concurrent.atomic.AtomicLong; -import static org.apache.ignite.internal.processors.odbc.OdbcRequest.CLOSE_SQL_QUERY; -import static org.apache.ignite.internal.processors.odbc.OdbcRequest.EXECUTE_SQL_QUERY; -import static org.apache.ignite.internal.processors.odbc.OdbcRequest.FETCH_SQL_QUERY; -import static org.apache.ignite.internal.processors.odbc.OdbcRequest.GET_COLUMNS_META; -import static org.apache.ignite.internal.processors.odbc.OdbcRequest.GET_TABLES_META; - /** -- * SQL query handler. ++ * ODBC message listener. */ -public class OdbcNioListener extends GridNioServerListenerAdapter<OdbcRequest> { - /** Query ID sequence. */ - private static final AtomicLong QRY_ID_GEN = new AtomicLong(); +public class OdbcNioListener extends GridNioServerListenerAdapter<byte[]> { + /** Initial output stream capacity. */ + private static final int INIT_CAP = 1024; - /** Kernel context. */ - private final GridKernalContext ctx; + /** Request ID generator. */ + private static final AtomicLong REQ_ID_GEN = new AtomicLong(); - /** Kernel context. */ - private final GridKernalContext ctx; - /** Busy lock. */ private final GridSpinBusyLock busyLock; - /** Logger. */ - private final IgniteLogger log; - + /** Request handler. */ + private final OdbcRequestHandler handler; + + /** Marshaller. */ + private final GridBinaryMarshaller marsh; + + /** Logger. */ + private final IgniteLogger log; + - /** Current queries cursors. */ - private final ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs = new ConcurrentHashMap<>(); - /** -- * Constructor. -- * * @param ctx Context. ++ * @param busyLock Shutdown busy lock. ++ * @param handler Request handler. */ - public OdbcNioListener(final GridKernalContext ctx, final GridSpinBusyLock busyLock) { - this.ctx = ctx; + public OdbcNioListener(final GridKernalContext ctx, final GridSpinBusyLock busyLock, + final OdbcRequestHandler handler) { - this.ctx = ctx; this.busyLock = busyLock; + this.handler = handler; + - this.marsh = ((CacheObjectBinaryProcessorImpl)ctx.cacheObjects()).marshaller(); ++ CacheObjectBinaryProcessorImpl cacheObjProc = (CacheObjectBinaryProcessorImpl)ctx.cacheObjects(); ++ ++ marsh = cacheObjProc.marshaller(); this.log = ctx.log(getClass()); } @@@ -94,40 -97,27 +93,50 @@@ } /** {@inheritDoc} */ - @Override public void onMessage(GridNioSession ses, OdbcRequest req) { - assert req != null; + @Override public void onMessage(GridNioSession ses, byte[] msg) { + assert msg != null; - long reqId = REQ_ID_GEN.incrementAndGet(); - long startTime = 0; + try { ++ long reqId = REQ_ID_GEN.incrementAndGet(); ++ long startTime = 0; + - if (log.isDebugEnabled()) { - startTime = System.nanoTime(); + OdbcRequest req = decode(msg); - log.debug("ODBC request received [id=" + reqId + ", addr=" + ses.remoteAddress() + ", req=" + req + ']'); - } ++ if (log.isDebugEnabled()) { ++ startTime = System.nanoTime(); + - OdbcResponse res = handle(req); ++ log.debug("ODBC request received [id=" + reqId + ", addr=" + ses.remoteAddress() + ", req=" + req + ']'); ++ } + - if (log.isDebugEnabled()) { - long dur = (System.nanoTime() - startTime) / 1000; + OdbcResponse rsp = handle(req); + - if (log.isDebugEnabled()) - log.debug("Handling result: [res=" + rsp.status() + ']'); ++ if (log.isDebugEnabled()) { ++ long dur = (System.nanoTime() - startTime) / 1000; - log.debug("ODBC request processed [id=" + reqId + ", dur(mcs)=" + dur + ", res=" + res.status() + ']'); ++ log.debug("ODBC request processed [id=" + reqId + ", dur(mcs)=" + dur + ", rsp=" + rsp.status() + ']'); ++ } + byte[] outMsg = encode(rsp); + + ses.send(outMsg); - } - catch (Exception e) { ++ } catch (Exception e) { + trySendErrorMessage(ses, e.getMessage()); } + } + + /** + * Try to send simple response message to ODBC driver. + * @param ses Session. + * @param err Error message. + */ + private void trySendErrorMessage(GridNioSession ses, String err) { + log.error(err); - ses.send(res); + try { + ses.send(encode(new OdbcResponse(OdbcResponse.STATUS_FAILED, err))); + } + catch (Exception e) { + log.error("Can not send error response message: [err=" + e.getMessage() + ']'); + } } /** @@@ -345,31 -372,14 +354,23 @@@ } /** - * Checks whether string matches SQL pattern. + * Handle request. * - * @param str String. - * @param ptrn Pattern. - * @return Whether string matches pattern. + * @param req Request. + * @return Response. */ - private static boolean matches(String str, String ptrn) { - return str != null && (F.isEmpty(ptrn) || - str.toUpperCase().matches(ptrn.toUpperCase().replace("%", ".*").replace("_", "."))); + private OdbcResponse handle(OdbcRequest req) { + assert req != null; + - if (log.isDebugEnabled()) - log.debug("Received request from client: [req=" + req + ']'); - - if (!busyLock.enterBusy()) { - String errMsg = "Failed to handle request [req=" + req + - ", err=Received request while stopping grid]"; - - U.error(log, errMsg); - - return new OdbcResponse(OdbcResponse.STATUS_FAILED, errMsg); - } ++ if (!busyLock.enterBusy()) ++ return new OdbcResponse(OdbcResponse.STATUS_FAILED, ++ "Failed to handle ODBC request because node is stopping: " + req); + + try { + return handler.handle(req); + } + finally { + busyLock.leaveBusy(); + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/c16549cd/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java ---------------------------------------------------------------------- diff --cc modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java index a6e4493,0000000..6a00f13 mode 100644,000000..100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcRequestHandler.java @@@ -1,335 -1,0 +1,320 @@@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.odbc; + +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteLogger; +import org.apache.ignite.cache.query.QueryCursor; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; +import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.lang.IgniteBiTuple; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +import static org.apache.ignite.internal.processors.odbc.OdbcRequest.*; + +/** - * ODBC request handler. ++ * SQL query handler. + */ +public class OdbcRequestHandler { + /** Query ID sequence. */ - private static final AtomicLong qryIdGen = new AtomicLong(); ++ private static final AtomicLong QRY_ID_GEN = new AtomicLong(); ++ ++ /** Request ID generator. */ ++ private static final AtomicLong REQ_ID_GEN = new AtomicLong(); + + /** Kernel context. */ + private final GridKernalContext ctx; + + /** Logger. */ + private final IgniteLogger log; + + /** Current queries cursors. */ + private final ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCurs = new ConcurrentHashMap<>(); + + /** + * Constructor. + * + * @param ctx Context. + */ + public OdbcRequestHandler(final GridKernalContext ctx) { + this.ctx = ctx; + + this.log = ctx.log(getClass()); + } + + /** + * Handle request. + * + * @param req Request. + * @return Response. + */ + public OdbcResponse handle(OdbcRequest req) { + assert req != null; + + switch (req.command()) { + case EXECUTE_SQL_QUERY: + return executeQuery((OdbcQueryExecuteRequest)req); + + case FETCH_SQL_QUERY: + return fetchQuery((OdbcQueryFetchRequest)req); + + case CLOSE_SQL_QUERY: + return closeQuery((OdbcQueryCloseRequest)req); + + case GET_COLUMNS_META: + return getColumnsMeta((OdbcQueryGetColumnsMetaRequest) req); + + case GET_TABLES_META: + return getTablesMeta((OdbcQueryGetTablesMetaRequest) req); + } + - return new OdbcResponse(OdbcResponse.STATUS_FAILED, - "Failed to find registered handler for command: " + req.command()); ++ return new OdbcResponse(OdbcResponse.STATUS_FAILED, "Unsupported ODBC request: " + req); + } + + /** + * {@link OdbcQueryExecuteRequest} command handler. + * + * @param req Execute query request. + * @return Response. + */ + private OdbcResponse executeQuery(OdbcQueryExecuteRequest req) { - long qryId = qryIdGen.getAndIncrement(); ++ long qryId = QRY_ID_GEN.getAndIncrement(); + + try { + SqlFieldsQuery qry = new SqlFieldsQuery(req.sqlQuery()); + + qry.setArgs(req.arguments()); + + IgniteCache<Object, Object> cache = ctx.grid().cache(req.cacheName()); + + if (cache == null) + return new OdbcResponse(OdbcResponse.STATUS_FAILED, - "Failed to find cache with name: " + req.cacheName()); ++ "Cache doesn't exist (did you configure it?): " + req.cacheName()); + + QueryCursor qryCur = cache.query(qry); + - Iterator cur = qryCur.iterator(); ++ Iterator iter = qryCur.iterator(); + - qryCurs.put(qryId, new IgniteBiTuple<>(qryCur, cur)); ++ qryCurs.put(qryId, new IgniteBiTuple<>(qryCur, iter)); + + List<?> fieldsMeta = ((QueryCursorImpl) qryCur).fieldsMeta(); + - if (log.isDebugEnabled()) - log.debug("Field meta: [meta: " + fieldsMeta + ']'); - + OdbcQueryExecuteResult res = new OdbcQueryExecuteResult(qryId, convertMetadata(fieldsMeta)); + + return new OdbcResponse(res); + } + catch (Exception e) { + qryCurs.remove(qryId); + + return new OdbcResponse(OdbcResponse.STATUS_FAILED, e.getMessage()); + } + } + + /** + * {@link OdbcQueryCloseRequest} command handler. + * + * @param req Execute query request. + * @return Response. + */ + private OdbcResponse closeQuery(OdbcQueryCloseRequest req) { + try { + QueryCursor cur = qryCurs.get(req.queryId()).get1(); + + if (cur == null) + return new OdbcResponse(OdbcResponse.STATUS_FAILED, "Failed to find query with ID: " + req.queryId()); + + cur.close(); + + qryCurs.remove(req.queryId()); + + OdbcQueryCloseResult res = new OdbcQueryCloseResult(req.queryId()); + + return new OdbcResponse(res); + } + catch (Exception e) { + qryCurs.remove(req.queryId()); + + return new OdbcResponse(OdbcResponse.STATUS_FAILED, e.getMessage()); + } + } + + /** + * {@link OdbcQueryFetchRequest} command handler. + * + * @param req Execute query request. + * @return Response. + */ + private OdbcResponse fetchQuery(OdbcQueryFetchRequest req) { + try { + Iterator cur = qryCurs.get(req.queryId()).get2(); + + if (cur == null) - return new OdbcResponse(OdbcResponse.STATUS_FAILED, - "Failed to find query with ID: " + req.queryId()); ++ return new OdbcResponse(OdbcResponse.STATUS_FAILED, "Failed to find query with ID: " + req.queryId()); + + List<Object> items = new ArrayList<>(); + + for (int i = 0; i < req.pageSize() && cur.hasNext(); ++i) + items.add(cur.next()); + + OdbcQueryFetchResult res = new OdbcQueryFetchResult(req.queryId(), items, !cur.hasNext()); + + return new OdbcResponse(res); + } + catch (Exception e) { + qryCurs.remove(req.queryId()); + + return new OdbcResponse(OdbcResponse.STATUS_FAILED, e.getMessage()); + } + } + + /** + * {@link OdbcQueryGetColumnsMetaRequest} command handler. + * + * @param req Get columns metadata request. + * @return Response. + */ + private OdbcResponse getColumnsMeta(OdbcQueryGetColumnsMetaRequest req) { + try { + List<OdbcColumnMeta> meta = new ArrayList<>(); + + String cacheName; + String tableName; + + if (req.tableName().contains(".")) { + // Parsing two-part table name. + String[] parts = req.tableName().split("\\."); + - cacheName = removeQuotationMarksIfNeeded(parts[0]); ++ cacheName = OdbcUtils.removeQuotationMarksIfNeeded(parts[0]); + + tableName = parts[1]; + } + else { - cacheName = removeQuotationMarksIfNeeded(req.cacheName()); ++ cacheName = OdbcUtils.removeQuotationMarksIfNeeded(req.cacheName()); + + tableName = req.tableName(); + } + + Collection<GridQueryTypeDescriptor> tablesMeta = ctx.query().types(cacheName); + + for (GridQueryTypeDescriptor table : tablesMeta) { + if (!matches(table.name(), tableName)) + continue; + + for (Map.Entry<String, Class<?>> field : table.fields().entrySet()) { + if (!matches(field.getKey(), req.columnName())) + continue; + - OdbcColumnMeta columnMeta = new OdbcColumnMeta(req.cacheName(), - table.name(), field.getKey(), field.getValue()); ++ OdbcColumnMeta columnMeta = new OdbcColumnMeta(req.cacheName(), table.name(), ++ field.getKey(), field.getValue()); + + if (!meta.contains(columnMeta)) + meta.add(columnMeta); + } + } ++ + OdbcQueryGetColumnsMetaResult res = new OdbcQueryGetColumnsMetaResult(meta); + + return new OdbcResponse(res); + } + catch (Exception e) { + return new OdbcResponse(OdbcResponse.STATUS_FAILED, e.getMessage()); + } + } + + /** + * {@link OdbcQueryGetTablesMetaRequest} command handler. + * + * @param req Get tables metadata request. + * @return Response. + */ + private OdbcResponse getTablesMeta(OdbcQueryGetTablesMetaRequest req) { + try { + List<OdbcTableMeta> meta = new ArrayList<>(); + - String realSchema = removeQuotationMarksIfNeeded(req.schema()); ++ String realSchema = OdbcUtils.removeQuotationMarksIfNeeded(req.schema()); + + for (String cacheName : ctx.cache().cacheNames()) + { + if (!matches(cacheName, realSchema)) + continue; + + Collection<GridQueryTypeDescriptor> tablesMeta = ctx.query().types(cacheName); + + for (GridQueryTypeDescriptor table : tablesMeta) { + if (!matches(table.name(), req.table())) + continue; + + if (!matches("TABLE", req.tableType())) + continue; + - OdbcTableMeta tableMeta = new OdbcTableMeta(req.catalog(), cacheName, - table.name(), "TABLE"); ++ OdbcTableMeta tableMeta = new OdbcTableMeta(req.catalog(), cacheName, table.name(), "TABLE"); + + if (!meta.contains(tableMeta)) + meta.add(tableMeta); + } + } + + OdbcQueryGetTablesMetaResult res = new OdbcQueryGetTablesMetaResult(meta); + + return new OdbcResponse(res); + } + catch (Exception e) { + return new OdbcResponse(OdbcResponse.STATUS_FAILED, e.getMessage()); + } + } + + /** + * Convert metadata in collection from {@link GridQueryFieldMetadata} to + * {@link OdbcColumnMeta}. + * + * @param meta Internal query field metadata. + * @return Odbc query field metadata. + */ + private static Collection<OdbcColumnMeta> convertMetadata(Collection<?> meta) { + List<OdbcColumnMeta> res = new ArrayList<>(); + + if (meta != null) { + for (Object info : meta) { + assert info instanceof GridQueryFieldMetadata; + + res.add(new OdbcColumnMeta((GridQueryFieldMetadata)info)); + } + } + + return res; + } + + /** + * Checks whether string matches SQL pattern. + * + * @param str String. + * @param ptrn Pattern. + * @return Whether string matches pattern. + */ + private static boolean matches(String str, String ptrn) { + return str != null && (F.isEmpty(ptrn) || - str.toUpperCase().matches(ptrn.toUpperCase().replace("%", ".*").replace("_", "."))); - } - - /** - * Remove quotation marks at the beginning and end of the string if present. - * - * @param str Input string. - * @return String without leading and trailing quotation marks. - */ - private static String removeQuotationMarksIfNeeded(String str) { - if (str.startsWith("\"") && str.endsWith("\"")) - return str.substring(1, str.length() - 1); - - return str; ++ str.toUpperCase().matches(ptrn.toUpperCase().replace("%", ".*").replace("_", "."))); + } +}
