/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.ais.protobuf;
import com.foundationdb.ais.CAOIBuilderFiller;
import com.foundationdb.ais.model.AISBuilder;
import com.foundationdb.ais.model.AkibanInformationSchema;
import com.foundationdb.ais.model.Column;
import com.foundationdb.ais.model.Index;
import com.foundationdb.ais.model.IndexColumn;
import com.foundationdb.ais.model.Join;
import com.foundationdb.ais.model.JoinColumn;
import com.foundationdb.ais.model.Parameter;
import com.foundationdb.ais.model.Routine;
import com.foundationdb.ais.model.Sequence;
import com.foundationdb.ais.model.SQLJJar;
import com.foundationdb.ais.model.TableIndex;
import com.foundationdb.ais.model.Table;
import com.foundationdb.ais.model.TableName;
import com.foundationdb.ais.model.aisb2.AISBBasedBuilder;
import com.foundationdb.ais.model.aisb2.NewAISBuilder;
import com.foundationdb.server.collation.AkCollatorFactory;
import com.foundationdb.server.error.ProtobufReadException;
import com.foundationdb.server.error.ProtobufWriteException;
import com.foundationdb.server.store.format.DummyStorageFormatRegistry;
import com.foundationdb.server.store.format.StorageFormatRegistry;
import com.foundationdb.server.store.format.TestStorageDescription;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.common.types.StringAttribute;
import com.foundationdb.server.types.common.types.StringFactory;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.server.types.mcompat.mtypes.MTypesTranslator;
import com.foundationdb.server.types.service.TestTypesRegistry;
import com.foundationdb.server.types.service.TypesRegistry;
import org.junit.Test;
import java.nio.ByteBuffer;
import static com.foundationdb.ais.AISComparator.compareAndAssert;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class ProtobufReaderWriterTest {
private final String SCHEMA = "test";
private final String identifier = "test";
@Test
public void empty() {
final AkibanInformationSchema inAIS = new AkibanInformationSchema();
inAIS.freeze();
final AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, false);
}
@Test
public void caoi() {
final AkibanInformationSchema inAIS = CAOIBuilderFiller.createAndFillBuilder(SCHEMA).ais();
final AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, false);
}
@Test
public void caoiWithGroupIndex() {
NewAISBuilder builder = CAOIBuilderFiller.createAndFillBuilder(SCHEMA);
builder.groupIndex("iprice_odate", Index.JoinType.RIGHT).
on(CAOIBuilderFiller.ITEM_TABLE, "unit_price").
and(CAOIBuilderFiller.ORDER_TABLE, "order_date");
final AkibanInformationSchema inAIS = builder.ais();
final AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, false);
}
@Test
public void caoiWithView() {
NewAISBuilder builder = CAOIBuilderFiller.createAndFillBuilder(SCHEMA);
builder.view("recent_orders").
definition("CREATE VIEW recent_order AS SELECT * FROM order WHERE order_date > CURRENT_DATE - INTERVAL '30' DAY").
references(CAOIBuilderFiller.ORDER_TABLE).
colBigInt("order_id", false).
colBigInt("customer_id", false).
colInt("order_date", false);
final AkibanInformationSchema inAIS = builder.ais();
final AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, false);
}
@Test
public void nonDefaultCharsetAndCollations() {
// AIS char/col not serialized (will be on Schema when that exists)
final AkibanInformationSchema inAIS = CAOIBuilderFiller.createAndFillBuilder(SCHEMA).ais(false);
inAIS.getTable(SCHEMA, CAOIBuilderFiller.ORDER_TABLE).
setCharsetAndCollation("utf16", "sv_se_ci");
Column column = inAIS.getTable(SCHEMA, CAOIBuilderFiller.CUSTOMER_TABLE).getColumn("customer_name");
TInstance type = column.getType();
type = type.typeClass().instance(
type.attribute(StringAttribute.MAX_LENGTH),
StringFactory.Charset.LATIN1.ordinal(),
AkCollatorFactory.getAkCollator("en_us").getCollationId(),
type.nullability());
column.setType(type);
inAIS.freeze();
final AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, false);
}
/*
* Stubbed out parent, similar to how table creation from the adapter works
*/
@Test
public void partialParentWithFullChild() {
final AkibanInformationSchema inAIS = new AkibanInformationSchema();
Table stubCustomer = Table.create(inAIS, SCHEMA, "c", 1);
TInstance bigint = typesRegistry().getTypeClass("MCOMPAT", "BIGINT").instance(false);
Column cId = Column.create(stubCustomer, "id", 2, bigint);
Table realOrder = Table.create(inAIS, SCHEMA, "o", 2);
Column oId = Column.create(realOrder, "oid", 0, bigint);
Column oCid = Column.create(realOrder, "cid", 1, bigint);
TInstance date = typesRegistry().getTypeClass("MCOMPAT", "DATE").instance(true);
Column.create(realOrder, "odate", 2, date);
Index orderPK = TableIndex.create(inAIS, realOrder, Index.PRIMARY, 0, true, true, new TableName(SCHEMA, "pkey"));
IndexColumn.create(orderPK, oId, 0, true, null);
Index akFk = TableIndex.create(inAIS, realOrder, "_fk1", 1, false, false);
IndexColumn.create(akFk, oCid, 0, true, null);
Join coJoin = Join.create(inAIS, "co", stubCustomer, realOrder);
JoinColumn.create(coJoin, cId, oCid);
final AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, false);
}
/*
* Stubbed out table, similar to how index creation from the adapter works
*/
@Test
public void partialTableWithIndexes() {
final AkibanInformationSchema inAIS = new AkibanInformationSchema();
Table stubCustomer = Table.create(inAIS, SCHEMA, "c", 1);
TInstance varchar32 = typesRegistry().getTypeClass("MCOMPAT", "VARCHAR").instance(32, true);
Column cFirstName = Column.create(stubCustomer, "first_name", 3, varchar32);
Column cLastName = Column.create(stubCustomer, "last_name", 4, varchar32);
TInstance int_null = typesRegistry().getTypeClass("MCOMPAT", "INT").instance(true);
Column cPayment = Column.create(stubCustomer, "payment", 6, int_null);
Index iName = TableIndex.create(inAIS, stubCustomer, "name", 2, false, false);
IndexColumn.create(iName, cLastName, 0, true, null);
IndexColumn.create(iName, cFirstName, 1, true, null);
Index iPayment = TableIndex.create(inAIS, stubCustomer, "payment", 3, false, false);
IndexColumn.create(iPayment, cPayment, 0, true, null);
final AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, false);
}
@Test
public void caoiWithFullComparison() {
final AkibanInformationSchema inAIS = CAOIBuilderFiller.createAndFillBuilder(SCHEMA).ais();
final AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, true);
}
@Test(expected=ProtobufReadException.class)
public void missingRootTable() {
final AkibanInformationSchema inAIS = CAOIBuilderFiller.createAndFillBuilder(SCHEMA).ais(false);
inAIS.getTables().remove(TableName.create(SCHEMA, CAOIBuilderFiller.CUSTOMER_TABLE));
inAIS.getSchema(SCHEMA).getTables().remove(CAOIBuilderFiller.CUSTOMER_TABLE);
writeAndRead(inAIS);
}
@Test(expected=ProtobufReadException.class)
public void readBufferTooSmall() {
ByteBuffer bb = ByteBuffer.allocate(4096);
final AkibanInformationSchema inAIS = CAOIBuilderFiller.createAndFillBuilder(SCHEMA).ais();
ProtobufWriter writer = new ProtobufWriter();
writer.save(inAIS);
writer.serialize(bb);
bb.flip();
bb.limit(bb.limit() / 2);
new ProtobufReader(typesRegistry(), storageFormatRegistry()).loadBuffer(bb);
}
@Test(expected=ProtobufWriteException.class)
public void writeBufferTooSmall() {
ByteBuffer bb = ByteBuffer.allocate(10);
final AkibanInformationSchema inAIS = CAOIBuilderFiller.createAndFillBuilder(SCHEMA).ais();
ProtobufWriter writer = new ProtobufWriter();
writer.save(inAIS);
writer.serialize(bb);
}
// bug971833
@Test
public void tableWithNoDeclaredPK() {
// CREATE TABLE t1(valid BOOLEAN, state CHAR(2))
final String TABLE = "t1";
AISBuilder builder = new AISBuilder();
builder.table(SCHEMA, TABLE);
builder.column(SCHEMA, TABLE, "valid", 0, typesRegistry().getTypeClass("MCOMPAT", "TINYINT").instance(true), false, null, null);
builder.column(SCHEMA, TABLE, "state", 1, typesRegistry().getTypeClass("MCOMPAT", "CHAR").instance(2, true), false, null, null);
builder.createGroup(TABLE, SCHEMA);
builder.addTableToGroup(TABLE, SCHEMA, TABLE);
builder.basicSchemaIsComplete();
builder.groupingIsComplete();
// AIS does not have to be validate-able to be serialized (this is how it comes from adapter)
final AkibanInformationSchema inAIS = builder.akibanInformationSchema();
final Table t1_1 = inAIS.getTable(SCHEMA, TABLE);
assertNull("Source table should not have declared PK", t1_1.getPrimaryKey());
assertNotNull("Source table should have internal PK", t1_1.getPrimaryKeyIncludingInternal());
// Serialized AIS did not create an internal column, PK
AkibanInformationSchema outAIS = writeAndRead(inAIS);
Table t1_2 = outAIS.getTable(SCHEMA, TABLE);
assertNull("Deserialized should not have declared PK", t1_2.getPrimaryKey());
assertNotNull("Deserialized should have internal PK", t1_2.getPrimaryKeyIncludingInternal());
compareAndAssert(inAIS, outAIS, false);
// Now add an internal PK and run through again
t1_1.endTable(builder.getNameGenerator());
assertNull("Source table should not have declared PK", t1_1.getPrimaryKey());
assertNotNull("Source table should have internal PK", t1_1.getPrimaryKeyIncludingInternal());
outAIS = writeAndRead(inAIS);
t1_2 = outAIS.getTable(SCHEMA, TABLE);
assertNull("Deserialized should not have declared PK", t1_2.getPrimaryKey());
assertNotNull("Deserialized should have internal PK", t1_2.getPrimaryKeyIncludingInternal());
compareAndAssert(inAIS, outAIS, false);
}
@Test
public void writeWithRestrictedSchema() {
final String SCHEMA1 = "test1";
final String TABLE1 = "t1";
final String SCHEMA2 = "test2";
final String TABLE2 = "t2";
NewAISBuilder builder = AISBBasedBuilder.create(typesTranslator());
builder.table(SCHEMA1, TABLE1).colInt("id", false).colString("v", 250).pk("id");
builder.table(SCHEMA2, TABLE2).colInt("tid", false).pk("tid");
AkibanInformationSchema inAIS = builder.ais();
AkibanInformationSchema outAIS1 = writeAndRead(inAIS, SCHEMA1);
assertEquals("Serialized AIS has just schema 1", "[" + SCHEMA1 + "]", outAIS1.getSchemas().keySet().toString());
AkibanInformationSchema outAIS2 = writeAndRead(inAIS, SCHEMA2);
assertEquals("Serialized AIS has just schema 2", "[" + SCHEMA2 + "]", outAIS2.getSchemas().keySet().toString());
}
@Test
public void writeWithRestrictedSchemaNoMatch() {
AkibanInformationSchema inAIS = CAOIBuilderFiller.createAndFillBuilder(SCHEMA).ais();
AkibanInformationSchema outAIS = writeAndRead(inAIS, SCHEMA + "foobar");
assertEquals("Serialized AIS has no schemas", "[]", outAIS.getSchemas().keySet().toString());
}
@Test
public void loadMultipleBuffers() {
final int COUNT = 3;
NewAISBuilder builder = AISBBasedBuilder.create(typesTranslator());
builder.table(SCHEMA+0, "t0").colInt("id", false).pk("id");
builder.table(SCHEMA+1, "t1").colBigInt("bid", false).colString("v", 32).pk("bid");
builder.table(SCHEMA+2, "t2").colDouble("d").colInt("l").key("d_idx", "d");
AkibanInformationSchema inAIS = builder.ais();
ByteBuffer bbs[] = new ByteBuffer[COUNT];
for(int i = 0; i < COUNT; ++i) {
bbs[i] = createByteBuffer();
ProtobufWriter writer = new ProtobufWriter(new ProtobufWriter.SingleSchemaSelector(SCHEMA+i));
writer.save(inAIS);
writer.serialize(bbs[i]);
}
AkibanInformationSchema outAIS = new AkibanInformationSchema();
ProtobufReader reader = new ProtobufReader(typesRegistry(), storageFormatRegistry(), outAIS);
for(int i = 0; i < COUNT; ++i) {
bbs[i].flip();
reader.loadBuffer(bbs[i]);
}
reader.loadAIS();
compareAndAssert(inAIS, outAIS, true);
}
@Test
public void groupAndIndexTreeNames() {
final String GROUP_TREENAME = "foo";
final String PARENT_PK_TREENAME = "bar";
final String GROUP_INDEX_TREENAME = "zap";
NewAISBuilder builder = AISBBasedBuilder.create(SCHEMA, typesTranslator());
builder.table("parent").colInt("pid", false).colString("v", 32).pk("pid").key("v", "v");
builder.table("child").colInt("cid", false).colInt("pid").pk("pid").joinTo("parent").on("pid", "pid");
builder.groupIndex("v_cid", Index.JoinType.LEFT).on("parent", "v").and("child", "cid");
AkibanInformationSchema inAIS = builder.ais();
Table inParent = inAIS.getTable(SCHEMA, "parent");
inParent.getGroup().setStorageDescription(new TestStorageDescription(inParent.getGroup(), GROUP_TREENAME, identifier));
inParent.getGroup().getIndex("v_cid").setStorageDescription(new TestStorageDescription(inParent.getGroup().getIndex("v_cid"), GROUP_INDEX_TREENAME, identifier));
inParent.getIndex("PRIMARY").setStorageDescription(new TestStorageDescription(inParent.getIndex("PRIMARY"), PARENT_PK_TREENAME, identifier));
AkibanInformationSchema outAIS = writeAndRead(inAIS);
compareAndAssert(inAIS, outAIS, true);
Table outParent = outAIS.getTable(SCHEMA, "parent");
assertEquals("group treename", GROUP_TREENAME, outParent.getGroup().getStorageUniqueKey());
assertEquals("parent pk treename", PARENT_PK_TREENAME, inParent.getIndex("PRIMARY").getStorageUniqueKey());
assertEquals("group index treename", GROUP_INDEX_TREENAME, inParent.getGroup().getIndex("v_cid").getStorageUniqueKey());
}
@Test
public void tableVersionNumber() {
final String TABLE = "t1";
NewAISBuilder builder = AISBBasedBuilder.create(SCHEMA, typesTranslator());
builder.table(TABLE).colInt("pid", false).pk("pid");
AkibanInformationSchema inAIS = builder.ais();
AkibanInformationSchema outAIS = writeAndRead(inAIS);
assertSame("Table without version", null, outAIS.getTable(SCHEMA, TABLE).getVersion());
final Integer VERSION = 5;
inAIS.getTable(SCHEMA, TABLE).setVersion(VERSION);
outAIS = writeAndRead(inAIS);
assertEquals("Table with version", VERSION, outAIS.getTable(SCHEMA, TABLE).getVersion());
}
@Test
public void sameRootTableNameTwoSchemas() {
NewAISBuilder builder = AISBBasedBuilder.create(typesTranslator());
builder.table(SCHEMA+"1", "t").colInt("id", false).pk("id");
builder.table(SCHEMA+"2", "t").colInt("id", false).pk("id");
AkibanInformationSchema inAIS = builder.ais();
writeAndRead(inAIS);
}
@Test
public void sequenceSimple () {
TableName seqName = new TableName (SCHEMA, "Sequence-1");
NewAISBuilder builder = AISBBasedBuilder.create(typesTranslator());
builder.defaultSchema(SCHEMA);
builder.sequence(seqName.getTableName());
AkibanInformationSchema inAIS = builder.ais();
AkibanInformationSchema outAIS = writeAndRead(inAIS);
assertNotNull(outAIS.getSequence(new TableName(SCHEMA, "Sequence-1")));
Sequence sequence = outAIS.getSequence(new TableName(SCHEMA, "Sequence-1"));
assertEquals(1, sequence.getStartsWith());
assertEquals(1, sequence.getIncrement());
assertEquals(Long.MIN_VALUE, sequence.getMinValue());
assertEquals(Long.MAX_VALUE, sequence.getMaxValue());
assertTrue(!sequence.isCycle());
}
@Test
public void sequenceComplex() {
NewAISBuilder builder = AISBBasedBuilder.create(typesTranslator());
builder.defaultSchema(SCHEMA);
builder.sequence("sequence-2", 42, -2, true);
AkibanInformationSchema inAIS = builder.ais();
AkibanInformationSchema outAIS = writeAndRead(inAIS);
assertNotNull(outAIS.getSequence(new TableName(SCHEMA, "sequence-2")));
Sequence sequence = outAIS.getSequence(new TableName(SCHEMA, "sequence-2"));
assertEquals(42, sequence.getStartsWith());
assertEquals(-2, sequence.getIncrement());
assertTrue(sequence.isCycle());
}
@Test
public void sequenceTree() {
NewAISBuilder builder = AISBBasedBuilder.create(typesTranslator());
TableName seqName = new TableName (SCHEMA, "sequence-3");
builder.defaultSchema(SCHEMA);
builder.sequence("sequence-3", 42, -2, true);
AkibanInformationSchema inAIS = builder.ais();
Sequence inSeq = inAIS.getSequence(seqName);
inSeq.setStorageDescription(new TestStorageDescription(inSeq, "sequence-3.tree", identifier));
AkibanInformationSchema outAIS = writeAndRead(inAIS);
assertNotNull(outAIS.getSequence(seqName));
Sequence sequence = outAIS.getSequence(seqName);
assertEquals ("sequence-3.tree", sequence.getStorageUniqueKey());
}
@Test
public void columnSequence() {
NewAISBuilder builder = AISBBasedBuilder.create(SCHEMA, typesTranslator());
TableName sequenceName = new TableName (SCHEMA, "sequence-4");
builder.sequence(sequenceName.getTableName());
builder.table("customers").
colBigInt("customer_id", false).
colString("customer_name", 100, false).
pk("customer_id");
AkibanInformationSchema inAIS = builder.unvalidatedAIS();
Column idColumn = inAIS.getTable(new TableName (SCHEMA, "customers")).getColumn(0);
idColumn.setDefaultIdentity(true);
idColumn.setIdentityGenerator(inAIS.getSequence(sequenceName));
AkibanInformationSchema outAIS = writeAndRead(builder.ais());
assertNotNull(outAIS.getSequence(sequenceName));
Column outColumn = outAIS.getTable(new TableName(SCHEMA, "customers")).getColumn(0);
assertNotNull (outColumn.getDefaultIdentity());
assertTrue (outColumn.getDefaultIdentity());
assertNotNull (outColumn.getIdentityGenerator());
assertSame (outColumn.getIdentityGenerator(), outAIS.getSequence(sequenceName));
}
@Test
public void indexColumnIndexedLength() {
final String TABLE = "t";
final Integer INDEXED_LENGTH = 16;
AISBuilder builder = new AISBuilder();
builder.table(SCHEMA, TABLE);
builder.column(SCHEMA, TABLE, "v", 0, typesRegistry().getTypeClass("MCOMPAT", "VARCHAR").instance(32, false), false, null, null);
builder.index(SCHEMA, TABLE, "v");
builder.indexColumn(SCHEMA, TABLE, "v", "v", 0, true, INDEXED_LENGTH);
builder.createGroup(TABLE, SCHEMA);
builder.addTableToGroup(TABLE, SCHEMA, TABLE);
builder.basicSchemaIsComplete();
builder.groupingIsComplete();
AkibanInformationSchema outAIS = writeAndRead(builder.akibanInformationSchema());
Table table = outAIS.getTable(SCHEMA, TABLE);
assertNotNull("found table", table);
assertNotNull("has v index", table.getIndex("v"));
assertEquals("v indexed length", INDEXED_LENGTH, table.getIndex("v").getKeyColumns().get(0).getIndexedLength());
}
@Test
public void maxStorageSizeAndPrefixSize() {
final String TABLE = "t";
NewAISBuilder builder = AISBBasedBuilder.create(SCHEMA, typesTranslator());
builder.table(TABLE).colBigInt("id");
AkibanInformationSchema inAIS = builder.unvalidatedAIS();
// Note: If storage* methods go away, or are non-null by default, that is *good* and these can go away
Column inCol = inAIS.getTable(SCHEMA, TABLE).getColumn(0);
assertNull("storedMaxStorageSize null by default", inCol.getMaxStorageSizeWithoutComputing());
assertNull("storedPrefixSize null by default", inCol.getPrefixSizeWithoutComputing());
AkibanInformationSchema outAIS = writeAndRead(inAIS);
Column outCol = outAIS.getTable(SCHEMA, TABLE).getColumn(0);
assertNull("storedMaxStorageSize null preserved", outCol.getMaxStorageSizeWithoutComputing());
assertNull("storedPrefixSize null preserved", outCol.getPrefixSizeWithoutComputing());
inCol.getMaxStorageSize();
inCol.getPrefixSize();
outAIS = writeAndRead(inAIS);
outCol = outAIS.getTable(SCHEMA, TABLE).getColumn(0);
assertEquals("storedMaxStorageSize", Long.valueOf(8L), outCol.getMaxStorageSizeWithoutComputing());
assertEquals("storedPrefixSize", Integer.valueOf(0), outCol.getPrefixSizeWithoutComputing());
}
@Test
public void columnDefaultValue() {
final String TABLE = "t";
NewAISBuilder builder = AISBBasedBuilder.create(SCHEMA, typesTranslator());
builder.table(TABLE).colBigInt("id");
AkibanInformationSchema inAIS = builder.unvalidatedAIS();
Column inCol = inAIS.getTable(SCHEMA, TABLE).getColumn("id");
AkibanInformationSchema outAIS = writeAndRead(inAIS);
Column outCol = outAIS.getTable(SCHEMA, TABLE).getColumn("id");
assertEquals("default defaultValue null", inCol.getDefaultValue(), outCol.getDefaultValue());
inCol.setDefaultValue("100");
outAIS = writeAndRead(inAIS);
outCol = outAIS.getTable(SCHEMA, TABLE).getColumn("id");
assertEquals("defaultValue", inCol.getDefaultValue(), outCol.getDefaultValue());
}
@Test
public void procedureJava() {
NewAISBuilder builder = AISBBasedBuilder.create(SCHEMA, typesTranslator());
builder.sqljJar("myjar")
// A file URL would vary by testing system. But don't check exists.
.url("http://example.com/procs.jar", false);
builder.procedure("PROC1")
.language("java", Routine.CallingConvention.JAVA)
.paramLongIn("x1")
.paramLongIn("x2")
.paramDoubleOut("d")
.externalName("myjar", "com.acme.Procs", "proc1")
.sqlAllowed(Routine.SQLAllowed.READS_SQL_DATA)
.dynamicResultSets(2);
AkibanInformationSchema inAIS = builder.ais();
AkibanInformationSchema outAIS = writeAndRead(inAIS);
Routine proc = outAIS.getRoutine(SCHEMA, "PROC1");
assertNotNull(proc);
SQLJJar jar = proc.getSQLJJar();
assertNotNull(jar);
assertEquals("myjar", jar.getName().getTableName());
assertEquals("http://example.com/procs.jar", jar.getURL().toString());
assertEquals("java", proc.getLanguage());
assertEquals(Routine.CallingConvention.JAVA, proc.getCallingConvention());
assertEquals(3, proc.getParameters().size());
assertEquals("x1", proc.getParameters().get(0).getName());
assertEquals(Parameter.Direction.IN, proc.getParameters().get(0).getDirection());
assertEquals("BIGINT", proc.getParameters().get(0).getTypeName());
assertEquals("x2", proc.getParameters().get(1).getName());
assertEquals("BIGINT", proc.getParameters().get(1).getTypeName());
assertEquals(Parameter.Direction.IN, proc.getParameters().get(1).getDirection());
assertEquals("d", proc.getParameters().get(2).getName());
assertEquals("DOUBLE", proc.getParameters().get(2).getTypeName());
assertEquals(Parameter.Direction.OUT, proc.getParameters().get(2).getDirection());
assertEquals("com.acme.Procs", proc.getClassName());
assertEquals("proc1", proc.getMethodName());
assertEquals(Routine.SQLAllowed.READS_SQL_DATA, proc.getSQLAllowed());
assertEquals(2, proc.getDynamicResultSets());
}
@Test
public void procedureLoadablePlan() {
NewAISBuilder builder = AISBBasedBuilder.create(SCHEMA, typesTranslator());
builder.procedure("PROC2")
.language("java", Routine.CallingConvention.LOADABLE_PLAN)
.externalName("com.acme.Procs", "proc1");
AkibanInformationSchema inAIS = builder.ais();
AkibanInformationSchema outAIS = writeAndRead(inAIS);
Routine proc = outAIS.getRoutine(SCHEMA, "PROC2");
assertEquals("java", proc.getLanguage());
assertEquals(Routine.CallingConvention.LOADABLE_PLAN, proc.getCallingConvention());
assertEquals(0, proc.getParameters().size());
}
private AkibanInformationSchema writeAndRead(AkibanInformationSchema inAIS) {
return writeAndRead(inAIS, null);
}
private AkibanInformationSchema writeAndRead(AkibanInformationSchema inAIS, String restrictSchema) {
ByteBuffer bb = createByteBuffer();
final ProtobufWriter writer;
if(restrictSchema == null) {
writer = new ProtobufWriter();
} else {
writer = new ProtobufWriter(new ProtobufWriter.SingleSchemaSelector(restrictSchema));
}
writer.save(inAIS);
writer.serialize(bb);
bb.flip();
ProtobufReader reader = new ProtobufReader(typesRegistry(), storageFormatRegistry()).loadBuffer(bb);
return reader.loadAIS().getAIS();
}
private ByteBuffer createByteBuffer() {
return ByteBuffer.allocate(4096);
}
private static TypesRegistry typesRegistry() {
return TestTypesRegistry.MCOMPAT;
}
private static TypesTranslator typesTranslator() {
return MTypesTranslator.INSTANCE;
}
private static StorageFormatRegistry storageFormatRegistry() {
return DummyStorageFormatRegistry.create();
}
}