Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IGNITE-5327 PARTITIONED and REPLICATED cache templates #2056

Closed
wants to merge 9 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.apache.ignite.internal.util.lang.GridClosureException;
import org.apache.ignite.internal.util.lang.IgniteOutClosureX;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.T3;
Expand Down Expand Up @@ -1278,7 +1279,8 @@ else if (op instanceof SchemaIndexDropOperation) {
*
* @param schemaName Schema name to create table in.
* @param entity Entity to create table from.
* @param templateName Template name.
* @param templateName Cache name to take settings from, if {@code null},
* a new {@code PARTITIONED} cache will be created.
* @param atomicityMode Atomicity mode.
* @param backups Backups.
* @param ifNotExists Quietly ignore this command if table already exists.
Expand All @@ -1287,19 +1289,28 @@ else if (op instanceof SchemaIndexDropOperation) {
@SuppressWarnings("unchecked")
public void dynamicTableCreate(String schemaName, QueryEntity entity, String templateName,
@Nullable CacheAtomicityMode atomicityMode, int backups, boolean ifNotExists) throws IgniteCheckedException {
assert !F.isEmpty(templateName);
assert backups >= 0;

CacheConfiguration<?, ?> templateCfg = ctx.cache().getConfigFromTemplate(templateName);
// Use PARTITIONED as template cache name if no actual name is given.
templateName = U.firstNotNull(templateName, CacheMode.PARTITIONED.name());

if (templateCfg == null)
throw new SchemaOperationException(SchemaOperationException.CODE_CACHE_NOT_FOUND, templateName);
CacheConfiguration<?, ?> newCfg;

if (!F.isEmpty(templateCfg.getQueryEntities()))
throw new SchemaOperationException("Template cannot contain query entities [template=" +
templateName + ']');
CacheConfiguration<?, ?> templateCfg = ctx.cache().getConfigFromTemplate(templateName);

CacheConfiguration<?, ?> newCfg = new CacheConfiguration<>(templateCfg);
if (templateCfg == null) {
if (CacheMode.PARTITIONED.name().equalsIgnoreCase(templateName))
newCfg = new CacheConfiguration<>().setCacheMode(CacheMode.PARTITIONED);
else if (CacheMode.REPLICATED.name().equalsIgnoreCase(templateName))
newCfg = new CacheConfiguration<>().setCacheMode(CacheMode.REPLICATED);
else
throw new SchemaOperationException(SchemaOperationException.CODE_CACHE_NOT_FOUND, templateName);
}
else if (!F.isEmpty(templateCfg.getQueryEntities())) {
throw new SchemaOperationException("Template cache already contains query entities which it should not: " +
templateName);
}
else
newCfg = new CacheConfiguration<>(templateCfg);

if (atomicityMode != null)
newCfg.setAtomicityMode(atomicityMode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.Map;
import javax.cache.CacheException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.CacheAtomicityMode;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.QueryIndex;
Expand Down Expand Up @@ -405,11 +406,6 @@ public class GridSqlQueryParser {
/** */
private static final String PARAM_ATOMICITY = "ATOMICITY";

/** Names of the params that need to be present in WITH clause of CREATE TABLE. */
private static final String[] MANDATORY_CREATE_TABLE_PARAMS = {
PARAM_TEMPLATE
};

/** */
private final IdentityHashMap<Object, Object> h2ObjToGridObj = new IdentityHashMap<>();

Expand Down Expand Up @@ -960,33 +956,28 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) {

res.params(extraParams);

Map<String, String> params = new HashMap<>();

if (!F.isEmpty(extraParams)) {
for (String p : extraParams) {
String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR);
if (F.isEmpty(extraParams))
return res;

if (parts.length > 2)
throw new IgniteSQLException("Invalid parameter (key[=value] expected): " + p,
IgniteQueryErrorCode.PARSING);
Map<String, String> params = new HashMap<>();

String name = parts[0].trim().toUpperCase();
for (String p : extraParams) {
String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR);

String val = parts.length > 1 ? parts[1].trim() : null;
if (parts.length > 2)
throw new IgniteSQLException("Invalid parameter (key[=value] expected): " + p,
IgniteQueryErrorCode.PARSING);

if (F.isEmpty(name))
throw new IgniteSQLException("Invalid parameter (key[=value] expected): " + p,
IgniteQueryErrorCode.PARSING);
String name = parts[0].trim().toUpperCase();

if (params.put(name, val) != null)
throw new IgniteSQLException("Duplicate parameter: " + p, IgniteQueryErrorCode.PARSING);
}
}
String val = parts.length > 1 ? parts[1].trim() : null;

for (String paramName : MANDATORY_CREATE_TABLE_PARAMS) {
if (!params.containsKey(paramName))
throw new IgniteSQLException("Mandatory parameter is missing: " + paramName,
if (F.isEmpty(name))
throw new IgniteSQLException("Invalid parameter (key[=value] expected): " + p,
IgniteQueryErrorCode.PARSING);

if (params.put(name, val) != null)
throw new IgniteSQLException("Duplicate parameter: " + p, IgniteQueryErrorCode.PARSING);
}

for (Map.Entry<String, String> e : params.entrySet())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,64 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest {
* @throws Exception if failed.
*/
public void testCreateTable() throws Exception {
doTestCreateTable(CACHE_NAME, null);
}

/**
* Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code REPLICATED} cache,
* H2 table and type descriptor on all nodes.
* @throws Exception if failed.
*/
public void testCreateTableReplicated() throws Exception {
doTestCreateTable("REPLICATED", CacheMode.REPLICATED);
}

/**
* Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code PARTITIONED} cache,
* H2 table and type descriptor on all nodes.
* @throws Exception if failed.
*/
public void testCreateTablePartitioned() throws Exception {
doTestCreateTable("PARTITIONED", CacheMode.PARTITIONED);
}

/**
* Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code REPLICATED} cache,
* H2 table and type descriptor on all nodes.
* @throws Exception if failed.
*/
public void testCreateTableReplicatedCaseInsensitive() throws Exception {
doTestCreateTable("replicated", CacheMode.REPLICATED);
}

/**
* Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code PARTITIONED} cache,
* H2 table and type descriptor on all nodes.
* @throws Exception if failed.
*/
public void testCreateTablePartitionedCaseInsensitive() throws Exception {
doTestCreateTable("partitioned", CacheMode.PARTITIONED);
}

/**
* Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code PARTITIONED} cache,
* H2 table and type descriptor on all nodes, when no cache template name is given.
* @throws Exception if failed.
*/
public void testCreateTableNoTemplate() throws Exception {
doTestCreateTable(null, CacheMode.PARTITIONED);
}

/**
* Test that {@code CREATE TABLE} with given template cache name actually creates new cache,
* H2 table and type descriptor on all nodes, optionally with cache type check.
* @param tplCacheName Template cache name.
* @param mode Expected cache mode, or {@code null} if no check is needed.
*/
private void doTestCreateTable(String tplCacheName, CacheMode mode) {
executeDdl("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," +
" \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " +
"\"template=cache,backups=10\",\"atomicity=atomic\"");
(F.isEmpty(tplCacheName) ? "" : "\"template=" + tplCacheName + "\",") + "\"backups=10,atomicity=atomic\"");

for (int i = 0; i < 4; i++) {
IgniteEx node = grid(i);
Expand All @@ -110,12 +165,18 @@ public void testCreateTable() throws Exception {

assertNotNull(cacheDesc);

assertEquals(10, cacheDesc.cacheConfiguration().getBackups());
if (mode == CacheMode.REPLICATED)
assertEquals(Integer.MAX_VALUE, cacheDesc.cacheConfiguration().getBackups());
else
assertEquals(10, cacheDesc.cacheConfiguration().getBackups());

assertEquals(CacheAtomicityMode.ATOMIC, cacheDesc.cacheConfiguration().getAtomicityMode());

assertTrue(cacheDesc.sql());

if (mode != null)
assertEquals(mode, cacheDesc.cacheConfiguration().getCacheMode());

QueryTypeDescriptorImpl desc = typeExisting(node, "Person", "Person");

assertEquals(Object.class, desc.keyClass());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -598,10 +598,7 @@ false, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING),
assertParseThrows("create table Person (id int primary key)",
IgniteSQLException.class, "No cache value related columns found");

assertParseThrows("create table Person (id int primary key, age int null)",
IgniteSQLException.class, "Mandatory parameter is missing: TEMPLATE");

assertParseThrows("create table Person (id int primary key, age int not null) WITH \"template=cache\"",
assertParseThrows("create table Person (id int primary key, age int not null) WITH \"cacheTemplate=cache\"",
IgniteSQLException.class, "Non nullable columns are forbidden");

assertParseThrows("create table Person (id int primary key, age int unique) WITH \"template=cache\"",
Expand Down