Browse Source

Merge pull request #1070 from ViktorBasanets/master

Merge
pull/1078/merge
VoBa 8 years ago
committed by GitHub
parent
commit
e781dd0718
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      application/src/main/data/upgrade/2.1.1/schema_update.cql
  2. 4
      application/src/main/data/upgrade/2.1.1/schema_update.sql
  3. 16
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java
  4. 8
      application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java
  5. 2
      application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java
  6. 2
      common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java
  7. 4
      common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java
  8. 11
      dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
  9. 6
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  10. 16
      dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java
  11. 16
      dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java
  12. 15
      dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java
  13. 12
      dao/src/main/resources/cassandra/schema.cql
  14. 4
      dao/src/main/resources/sql/schema.sql

20
application/src/main/data/upgrade/2.1.1/schema_update.cql

@ -29,8 +29,8 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
customer_id timeuuid,
name text,
keys text,
ts_begin bigint,
ts_end bigint,
start_ts bigint,
end_ts bigint,
search_text text,
additional_info text,
PRIMARY KEY (id, entity_id, tenant_id, customer_id)
@ -43,8 +43,8 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_na
AND tenant_id IS NOT NULL
AND customer_id IS NOT NULL
AND keys IS NOT NULL
AND ts_begin IS NOT NULL
AND ts_end IS NOT NULL
AND start_ts IS NOT NULL
AND end_ts IS NOT NULL
AND name IS NOT NULL
AND id IS NOT NULL
PRIMARY KEY (tenant_id, name, id, entity_id, customer_id)
@ -57,8 +57,8 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_en
AND tenant_id IS NOT NULL
AND customer_id IS NOT NULL
AND keys IS NOT NULL
AND ts_begin IS NOT NULL
AND ts_end IS NOT NULL
AND start_ts IS NOT NULL
AND end_ts IS NOT NULL
AND name IS NOT NULL
AND id IS NOT NULL
PRIMARY KEY (tenant_id, entity_id, id, customer_id, name)
@ -71,8 +71,8 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_cu
AND tenant_id IS NOT NULL
AND customer_id IS NOT NULL
AND keys IS NOT NULL
AND ts_begin IS NOT NULL
AND ts_end IS NOT NULL
AND start_ts IS NOT NULL
AND end_ts IS NOT NULL
AND name IS NOT NULL
AND id IS NOT NULL
PRIMARY KEY (tenant_id, customer_id, id, entity_id, name)
@ -85,8 +85,8 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_cu
AND tenant_id IS NOT NULL
AND customer_id IS NOT NULL
AND keys IS NOT NULL
AND ts_begin IS NOT NULL
AND ts_end IS NOT NULL
AND start_ts IS NOT NULL
AND end_ts IS NOT NULL
AND name IS NOT NULL
AND id IS NOT NULL
PRIMARY KEY (tenant_id, customer_id, entity_id, id, name)

4
application/src/main/data/upgrade/2.1.1/schema_update.sql

@ -24,8 +24,8 @@ CREATE TABLE IF NOT EXISTS entity_views (
customer_id varchar(31),
name varchar(255),
keys varchar(255),
ts_begin varchar(255),
ts_end varchar(255),
start_ts bigint,
end_ts bigint,
search_text varchar(255),
additional_info varchar
);

16
application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java

@ -29,10 +29,15 @@ import org.thingsboard.rule.engine.api.util.DonAsynchron;
import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
//<<<<<<< HEAD
import org.thingsboard.server.common.data.id.EntityViewId;
//=======
import org.thingsboard.server.common.data.id.TenantId;
//>>>>>>> d909192071880b7af2137333142bc62ece369ec1
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
@ -48,6 +53,8 @@ import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
@ -101,6 +108,9 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
@Autowired
private ClusterRpcService rpcService;
/*@Autowired
private EntityViewService entityViewService;*/
@Autowired
@Lazy
private DeviceStateService stateService;
@ -133,15 +143,17 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
@Override
public void addLocalWsSubscription(String sessionId, EntityId entityId, SubscriptionState sub) {
String familyName = entityId.getEntityType().equals(EntityType.ENTITY_VIEW)
? ModelConstants.ENTITY_VIEW_FAMILY_NAME : ModelConstants.DEVICE_FAMILY_NAME;
Optional<ServerAddress> server = routingService.resolveById(entityId);
Subscription subscription;
if (server.isPresent()) {
ServerAddress address = server.get();
log.trace("[{}] Forwarding subscription [{}] for device [{}] to [{}]", sessionId, sub.getSubscriptionId(), entityId, address);
log.trace("[{}] Forwarding subscription [{}] for " + familyName + " [{}] to [{}]", sessionId, sub.getSubscriptionId(), entityId, address);
subscription = new Subscription(sub, true, address);
tellNewSubscription(address, sessionId, subscription);
} else {
log.trace("[{}] Registering local subscription [{}] for device [{}]", sessionId, sub.getSubscriptionId(), entityId);
log.trace("[{}] Registering local subscription [{}] for " + familyName + " [{}]", sessionId, sub.getSubscriptionId(), entityId);
subscription = new Subscription(sub, true);
}
registerSubscription(sessionId, entityId, subscription);

8
application/src/main/java/org/thingsboard/server/service/telemetry/sub/Subscription.java

@ -30,9 +30,15 @@ public class Subscription {
private final SubscriptionState sub;
private final boolean local;
private ServerAddress server;
private long startTime;
private long endTime;
public Subscription(SubscriptionState sub, boolean local) {
this(sub, local, null);
this(sub, local, null, 0L, 0L);
}
public Subscription(SubscriptionState sub, boolean local, ServerAddress server) {
this(sub, local, server, 0L, 0L);
}
public String getWsSessionId() {

2
application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java

@ -24,7 +24,7 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({
"org.thingsboard.server.controller.sql.*Test",
"org.thingsboard.server.controller.sql.EntityViewControllerSqlTest",
})
public class ControllerSqlTestSuite {

2
common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java

@ -1,4 +1,4 @@
/**
/**
* Copyright © 2016-2018 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");

4
common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseReadTsKvQuery.java

@ -42,4 +42,8 @@ public class BaseReadTsKvQuery extends BaseTsKvQuery implements ReadTsKvQuery {
this(key, startTs, endTs, endTs - startTs, 1, Aggregation.AVG, "DESC");
}
public BaseReadTsKvQuery(String key, long startTs, long endTs, int limit, String orderBy) {
this(key, startTs, endTs, endTs - startTs, limit, Aggregation.AVG, orderBy);
}
}

11
dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java

@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer;
@ -88,7 +89,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
@Autowired
private CacheManager cacheManager;
// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}")
@Cacheable(cacheNames = ENTITY_VIEW_CACHE)
@Override
public EntityView findEntityViewById(EntityViewId entityViewId) {
log.trace("Executing findEntityViewById [{}]", entityViewId);
@ -104,7 +105,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
.orElse(null);
}
// @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id}")
@CachePut(cacheNames = ENTITY_VIEW_CACHE)
@Override
public EntityView saveEntityView(EntityView entityView) {
log.trace("Executing save entity view [{}]", entityView);
@ -136,7 +137,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
List<Object> list = new ArrayList<>();
list.add(entityView.getTenantId());
list.add(entityView.getName());
// cache.evict(list);
cache.evict(list);
entityViewDao.removeById(entityViewId.getId());
}
@ -149,7 +150,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
return new TextPageData<>(entityViews, pageLink);
}
// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId, #pageLink}")
@Cacheable(cacheNames = ENTITY_VIEW_CACHE)
@Override
public TextPageData<EntityView> findEntityViewByTenantIdAndEntityId(TenantId tenantId, EntityId entityId,
TextPageLink pageLink) {
@ -189,7 +190,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
return new TextPageData<>(entityViews, pageLink);
}
// @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}")
@Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #customerId, #entityId, #pageLink}")
@Override
public TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(TenantId tenantId,
CustomerId customerId,

6
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -131,6 +131,7 @@ public class ModelConstants {
* Cassandra device constants.
*/
public static final String DEVICE_COLUMN_FAMILY_NAME = "device";
public static final String DEVICE_FAMILY_NAME = "device";
public static final String DEVICE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String DEVICE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
public static final String DEVICE_NAME_PROPERTY = "name";
@ -147,6 +148,7 @@ public class ModelConstants {
* Cassandra entityView constants.
*/
public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_views";
public static final String ENTITY_VIEW_FAMILY_NAME = "entity-view";
public static final String ENTITY_VIEW_ENTITY_ID_PROPERTY = ENTITY_ID_COLUMN;
public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
@ -154,8 +156,8 @@ public class ModelConstants {
public static final String ENTITY_VIEW_TYPE_PROPERTY = DEVICE_TYPE_PROPERTY;
public static final String ENTITY_VIEW_TENANT_AND_NAME_VIEW_NAME = "entity_view_by_tenant_and_name";
public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys";
public static final String ENTITY_VIEW_TS_BEGIN_PROPERTY = "ts_begin";
public static final String ENTITY_VIEW_TS_END_PROPERTY = "ts_end";
public static final String ENTITY_VIEW_START_TS_PROPERTY = "start_ts";
public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts";
public static final String ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
public static final String ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "entity_view_by_tenant_and_search_text";

16
dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java

@ -75,11 +75,11 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
@Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY)
private String keys;
@Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY)
private String tsBegin;
@Column(name = ModelConstants.ENTITY_VIEW_START_TS_PROPERTY)
private long startTs;
@Column(name = ModelConstants.ENTITY_VIEW_TS_END_PROPERTY)
private String tsEnd;
@Column(name = ModelConstants.ENTITY_VIEW_END_TS_PROPERTY)
private long endTs;
@Column(name = ModelConstants.SEARCH_TEXT_PROPERTY)
private String searchText;
@ -114,8 +114,8 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
} catch (IOException e) {
e.printStackTrace();
}
this.tsBegin = entityView.getStartTs() != 0L ? String.valueOf(entityView.getStartTs()) : "0";
this.tsEnd = entityView.getEndTs() != 0L ? String.valueOf(entityView.getEndTs()) : "0";
this.startTs = entityView.getStartTs() != 0L ? entityView.getStartTs() : 0L;
this.endTs = entityView.getEndTs() != 0L ? entityView.getEndTs() : 0L;
this.searchText = entityView.getSearchText();
this.additionalInfo = entityView.getAdditionalInfo();
}
@ -144,8 +144,8 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
} catch (IOException e) {
e.printStackTrace();
}
entityView.setStartTs(Long.parseLong(tsBegin));
entityView.setEndTs(Long.parseLong(tsEnd));
entityView.setStartTs(startTs);
entityView.setEndTs(endTs);
entityView.setAdditionalInfo(additionalInfo);
return entityView;
}

16
dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java

@ -66,11 +66,11 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
@Column(name = ModelConstants.ENTITY_VIEW_KEYS_PROPERTY)
private String keys;
@Column(name = ModelConstants.ENTITY_VIEW_TS_BEGIN_PROPERTY)
private String tsBegin;
@Column(name = ModelConstants.ENTITY_VIEW_START_TS_PROPERTY)
private long startTs;
@Column(name = ModelConstants.ENTITY_VIEW_TS_END_PROPERTY)
private String tsEnd;
@Column(name = ModelConstants.ENTITY_VIEW_END_TS_PROPERTY)
private long endTs;
@Column(name = ModelConstants.SEARCH_TEXT_PROPERTY)
private String searchText;
@ -105,8 +105,8 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
} catch (IOException e) {
e.printStackTrace();
}
this.tsBegin = entityView.getStartTs() != 0L ? String.valueOf(entityView.getStartTs()) : "0";
this.tsEnd = entityView.getEndTs() != 0L ? String.valueOf(entityView.getEndTs()) : "0";
this.startTs = entityView.getStartTs() != 0L ? entityView.getStartTs() : 0L;
this.endTs = entityView.getEndTs() != 0L ? entityView.getEndTs() : 0L;
this.searchText = entityView.getSearchText();
this.additionalInfo = entityView.getAdditionalInfo();
}
@ -141,8 +141,8 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
} catch (IOException e) {
e.printStackTrace();
}
entityView.setStartTs(Long.parseLong(tsBegin));
entityView.setEndTs(Long.parseLong(tsEnd));
entityView.setStartTs(startTs);
entityView.setEndTs(endTs);
entityView.setAdditionalInfo(additionalInfo);
return entityView;
}

15
dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java

@ -71,13 +71,17 @@ public class BaseTimeseriesService implements TimeseriesService {
validate(entityId);
List<ListenableFuture<TsKvEntry>> futures = Lists.newArrayListWithExpectedSize(keys.size());
keys.forEach(key -> Validator.validateString(key, "Incorrect key " + key));
if (false/*entityId.getEntityType().equals(EntityType.ENTITY_VIEW)*/) {
if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) {
EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId);
Collection<String> newKeys = chooseKeysForEntityView(entityView, keys);
newKeys.forEach(newKey -> futures.add(timeseriesDao.findLatest(entityView.getEntityId(), newKey)));
} else {
keys.forEach(key -> futures.add(timeseriesDao.findLatest(entityId, key)));
Collection<String> matchingKeys = chooseKeysForEntityView(entityView, keys);
List<ReadTsKvQuery> queries = new ArrayList<>();
matchingKeys.forEach(key -> queries.add(
new BaseReadTsKvQuery(key, entityView.getStartTs(), entityView.getEndTs(), 1, "ASC")));
return timeseriesDao.findAllAsync(entityView.getEntityId(), updateQueriesForEntityView(entityView, queries));
}
keys.forEach(key -> futures.add(timeseriesDao.findLatest(entityId, key)));
return Futures.allAsList(futures);
}
@ -150,7 +154,6 @@ public class BaseTimeseriesService implements TimeseriesService {
return newQueries;
}
@Deprecated /*Will be a modified*/
private Collection<String> chooseKeysForEntityView(EntityView entityView, Collection<String> keys) {
Collection<String> newKeys = new ArrayList<>();
entityView.getKeys().getTimeseries()

12
dao/src/main/resources/cassandra/schema.cql

@ -647,8 +647,8 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
customer_id timeuuid,
name text,
keys text,
ts_begin bigint,
ts_end bigint,
start_ts bigint,
end_ts bigint,
search_text text,
additional_info text,
PRIMARY KEY (id, tenant_id, customer_id)
@ -657,27 +657,27 @@ CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_name AS
SELECT *
from thingsboard.entity_views
WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
PRIMARY KEY (tenant_id, name, id, entity_id, customer_id)
WITH CLUSTERING ORDER BY (name ASC, id DESC, entity_id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_entity AS
SELECT *
from thingsboard.entity_views
WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
PRIMARY KEY (tenant_id, entity_id, id, customer_id, name)
WITH CLUSTERING ORDER BY (entity_id ASC, customer_id ASC, id DESC, name DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer AS
SELECT *
from thingsboard.entity_views
WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
PRIMARY KEY (tenant_id, customer_id, id, entity_id, name)
WITH CLUSTERING ORDER BY (customer_id ASC, id DESC, entity_id DESC, name DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_views_by_tenant_and_customer_and_entity AS
SELECT *
from thingsboard.entity_views
WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND ts_begin IS NOT NULL AND ts_end IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
WHERE entity_id IS NOT NULL AND tenant_id IS NOT NULL AND customer_id IS NOT NULL AND keys IS NOT NULL AND start_ts IS NOT NULL AND end_ts IS NOT NULL AND name IS NOT NULL AND id IS NOT NULL
PRIMARY KEY (tenant_id, customer_id, entity_id, id, name)
WITH CLUSTERING ORDER BY (customer_id ASC, entity_id DESC, id DESC, name DESC);

4
dao/src/main/resources/sql/schema.sql

@ -260,8 +260,8 @@ CREATE TABLE IF NOT EXISTS entity_views (
customer_id varchar(31),
name varchar(255),
keys varchar(255),
ts_begin varchar(255),
ts_end varchar(255),
start_ts bigint,
end_ts bigint,
search_text varchar(255),
additional_info varchar
);

Loading…
Cancel
Save