or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdexceptions.mdexecution.mdexpressions.mdindex.mdjdbc.mdmapreduce.mdmonitoring.mdquery-compilation.mdschema-metadata.mdserver.mdtransactions.mdtypes.md

expressions.mddocs/

0

# Expression Framework

1

2

Phoenix's expression framework provides a powerful system for evaluating SQL expressions, functions, and operators. The framework supports literal values, column references, function calls, and complex expressions with proper type handling and optimization.

3

4

## Core Imports

5

6

```java

7

import org.apache.phoenix.expression.*;

8

import org.apache.phoenix.expression.function.*;

9

import org.apache.phoenix.expression.aggregator.*;

10

import org.apache.phoenix.schema.tuple.Tuple;

11

import org.apache.hadoop.hbase.io.ImmutableBytesWritable;

12

```

13

14

## Core Expression Types

15

16

### Expression

17

18

Base interface for all Phoenix expressions providing evaluation and metadata methods.

19

20

```java{ .api }

21

public interface Expression extends Writable {

22

// Expression evaluation

23

boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

24

PDataType getDataType()

25

Integer getMaxLength()

26

Integer getScale()

27

boolean isNullable()

28

29

// Expression properties

30

SortOrder getSortOrder()

31

boolean isDeterministic()

32

boolean isStateless()

33

34

// Child expressions

35

List<Expression> getChildren()

36

void reset()

37

boolean requiresFinalEvaluation()

38

39

// Serialization

40

void write(DataOutput output) throws IOException

41

void readFields(DataInput input) throws IOException

42

}

43

```

44

45

### LiteralExpression

46

47

Expression representing constant literal values with type-safe value handling.

48

49

```java{ .api }

50

public class LiteralExpression implements Expression {

51

// Factory methods for creating literals

52

public static LiteralExpression newConstant(Object value)

53

public static LiteralExpression newConstant(Object value, PDataType dataType)

54

public static LiteralExpression newConstant(Object value, PDataType dataType,

55

Integer maxLength, Integer scale)

56

public static LiteralExpression newConstant(Object value, PDataType dataType,

57

SortOrder sortOrder)

58

59

// Expression implementation

60

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

61

public PDataType getDataType()

62

public Object getValue()

63

public byte[] getBytes()

64

65

// Literal-specific methods

66

public boolean isNull()

67

public String toString()

68

}

69

```

70

71

**Usage:**

72

```java

73

// Create literal expressions

74

LiteralExpression stringLiteral = LiteralExpression.newConstant("Hello World");

75

LiteralExpression intLiteral = LiteralExpression.newConstant(42);

76

LiteralExpression decimalLiteral = LiteralExpression.newConstant(

77

new BigDecimal("123.45"), PDecimal.INSTANCE, 5, 2

78

);

79

80

// Evaluate literals

81

ImmutableBytesWritable result = new ImmutableBytesWritable();

82

boolean success = stringLiteral.evaluate(null, result); // Literals don't need tuple

83

if (success) {

84

String value = (String) stringLiteral.getDataType().toObject(result);

85

System.out.println("String value: " + value);

86

}

87

88

// Create null literal

89

LiteralExpression nullLiteral = LiteralExpression.newConstant(null, PVarchar.INSTANCE);

90

boolean isNull = nullLiteral.isNull(); // Returns true

91

```

92

93

### ColumnExpression

94

95

Expression representing column references from tables.

96

97

```java{ .api }

98

public class ColumnExpression extends BaseTerminalExpression {

99

public ColumnExpression(PColumn column, byte[] table)

100

101

// Column information

102

public PColumn getColumn()

103

public byte[] getTableName()

104

public String getDisplayName()

105

106

// Expression implementation

107

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

108

public PDataType getDataType()

109

public boolean isNullable()

110

}

111

```

112

113

**Usage:**

114

```java

115

// Create column expression

116

PTable table = connection.getTable(PNameFactory.newName("users"));

117

PColumn nameColumn = table.getColumn("name");

118

ColumnExpression nameExpr = new ColumnExpression(nameColumn, table.getName().getBytes());

119

120

// Evaluate column expression (requires tuple with row data)

121

Tuple rowTuple = getCurrentRowTuple(); // From query execution

122

ImmutableBytesWritable result = new ImmutableBytesWritable();

123

boolean success = nameExpr.evaluate(rowTuple, result);

124

if (success) {

125

String name = (String) nameExpr.getDataType().toObject(result);

126

System.out.println("Name: " + name);

127

}

128

129

// Column properties

130

PDataType dataType = nameExpr.getDataType();

131

String displayName = nameExpr.getDisplayName();

132

boolean nullable = nameExpr.isNullable();

133

```

134

135

## Function Framework

136

137

### FunctionExpression

138

139

Base class for all Phoenix function expressions providing common function behavior.

140

141

```java{ .api }

142

public abstract class FunctionExpression implements Expression {

143

public FunctionExpression(List<Expression> children)

144

public FunctionExpression(String name, List<Expression> children)

145

146

// Function properties

147

public String getName()

148

public List<Expression> getChildren()

149

public abstract PDataType getDataType()

150

151

// Function evaluation

152

public abstract boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

153

public abstract String toString()

154

155

// Helper methods for child evaluation

156

protected boolean evaluateExpression(Expression expression, Tuple tuple,

157

ImmutableBytesWritable ptr)

158

protected Object evaluateExpression(Expression expression, Tuple tuple)

159

}

160

```

161

162

### ScalarFunction

163

164

Base class for scalar functions that return a single value.

165

166

```java{ .api }

167

public abstract class ScalarFunction extends FunctionExpression {

168

public ScalarFunction(List<Expression> children)

169

public ScalarFunction(String name, List<Expression> children)

170

171

// Scalar function implementation

172

public abstract boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

173

public abstract PDataType getDataType()

174

175

// Common scalar function utilities

176

protected static boolean checkNulls(Tuple tuple, Expression... expressions)

177

protected static Object getObject(Expression expression, Tuple tuple)

178

}

179

```

180

181

### AggregateFunction

182

183

Base class for aggregate functions that accumulate values across multiple rows.

184

185

```java{ .api }

186

public abstract class AggregateFunction extends FunctionExpression {

187

public AggregateFunction(List<Expression> children, String name)

188

189

// Aggregate function implementation

190

public abstract Aggregator newAggregator()

191

public abstract boolean isAggregator(Expression expression)

192

193

// Aggregate properties

194

public boolean requiresFinalEvaluation() // Returns true

195

public abstract PDataType getDataType()

196

}

197

```

198

199

**Usage:**

200

```java

201

// Create scalar function (example: UPPER function)

202

Expression nameColumn = new ColumnExpression(nameColumn, tableBytes);

203

List<Expression> upperArgs = Arrays.asList(nameColumn);

204

ScalarFunction upperFunc = new UpperFunction(upperArgs);

205

206

// Evaluate scalar function

207

Tuple rowTuple = getCurrentRowTuple();

208

ImmutableBytesWritable result = new ImmutableBytesWritable();

209

boolean success = upperFunc.evaluate(rowTuple, result);

210

if (success) {

211

String upperName = (String) upperFunc.getDataType().toObject(result);

212

System.out.println("Upper name: " + upperName);

213

}

214

215

// Create aggregate function (example: COUNT function)

216

List<Expression> countArgs = Arrays.asList(LiteralExpression.newConstant(1));

217

AggregateFunction countFunc = new CountAggregateFunction(countArgs);

218

Aggregator aggregator = countFunc.newAggregator();

219

```

220

221

## Aggregation Framework

222

223

### Aggregator

224

225

Interface for aggregation operations that accumulate values across multiple rows.

226

227

```java{ .api }

228

public interface Aggregator {

229

// Aggregation operations

230

void aggregate(Tuple tuple, ImmutableBytesWritable ptr)

231

boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

232

233

// Aggregator state

234

void reset()

235

Aggregator newAggregator()

236

237

// Size estimation

238

int getSize()

239

}

240

```

241

242

### ServerAggregators

243

244

Container for server-side aggregators used in distributed query execution.

245

246

```java{ .api }

247

public class ServerAggregators {

248

public ServerAggregators(List<SingleAggregateFunction> functions,

249

int minNullableIndex)

250

251

// Aggregator access

252

public SingleAggregateFunction[] getFunctions()

253

public Aggregator[] getAggregators()

254

public KeyValueSchema getSchema()

255

256

// Aggregation operations

257

public void aggregate(Aggregator[] aggregators, Tuple result)

258

public void reset(Aggregator[] aggregators)

259

public int getEstimatedByteSize()

260

}

261

```

262

263

**Usage:**

264

```java

265

// Create aggregators for distributed execution

266

List<SingleAggregateFunction> aggFunctions = Arrays.asList(

267

new CountAggregateFunction(),

268

new SumAggregateFunction(salaryColumn),

269

new MaxAggregateFunction(salaryColumn)

270

);

271

272

ServerAggregators serverAggs = new ServerAggregators(aggFunctions, 0);

273

Aggregator[] aggregators = serverAggs.getAggregators();

274

275

// Process each row in server-side scan

276

while (scanner.hasNext()) {

277

Tuple row = scanner.next();

278

serverAggs.aggregate(aggregators, row);

279

}

280

281

// Get final aggregated results

282

ImmutableBytesWritable result = new ImmutableBytesWritable();

283

for (int i = 0; i < aggregators.length; i++) {

284

boolean success = aggregators[i].evaluate(null, result);

285

if (success) {

286

Object value = aggFunctions.get(i).getDataType().toObject(result);

287

System.out.println("Aggregate " + i + ": " + value);

288

}

289

}

290

```

291

292

## Common Function Types

293

294

### String Functions

295

296

```java

297

// String manipulation functions

298

public class UpperFunction extends ScalarFunction {

299

public UpperFunction(List<Expression> children)

300

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

301

public PDataType getDataType() // Returns PVarchar.INSTANCE

302

}

303

304

public class LowerFunction extends ScalarFunction {

305

public LowerFunction(List<Expression> children)

306

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

307

public PDataType getDataType() // Returns PVarchar.INSTANCE

308

}

309

310

public class SubstrFunction extends ScalarFunction {

311

public SubstrFunction(List<Expression> children) // string, start, [length]

312

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

313

public PDataType getDataType() // Returns PVarchar.INSTANCE

314

}

315

316

public class LengthFunction extends ScalarFunction {

317

public LengthFunction(List<Expression> children)

318

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

319

public PDataType getDataType() // Returns PInteger.INSTANCE

320

}

321

```

322

323

**Usage:**

324

```java

325

// String function examples

326

Expression nameColumn = new ColumnExpression(nameColumn, tableBytes);

327

328

// UPPER(name)

329

UpperFunction upper = new UpperFunction(Arrays.asList(nameColumn));

330

331

// LENGTH(name)

332

LengthFunction length = new LengthFunction(Arrays.asList(nameColumn));

333

334

// SUBSTR(name, 1, 5)

335

SubstrFunction substr = new SubstrFunction(Arrays.asList(

336

nameColumn,

337

LiteralExpression.newConstant(1),

338

LiteralExpression.newConstant(5)

339

));

340

341

// Evaluate functions

342

Tuple row = getCurrentRowTuple();

343

ImmutableBytesWritable result = new ImmutableBytesWritable();

344

345

if (upper.evaluate(row, result)) {

346

String upperName = (String) upper.getDataType().toObject(result);

347

System.out.println("Upper: " + upperName);

348

}

349

350

if (length.evaluate(row, result)) {

351

Integer nameLength = (Integer) length.getDataType().toObject(result);

352

System.out.println("Length: " + nameLength);

353

}

354

```

355

356

### Numeric Functions

357

358

```java

359

// Mathematical functions

360

public class RoundFunction extends ScalarFunction {

361

public RoundFunction(List<Expression> children) // number, [scale]

362

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

363

public PDataType getDataType() // Returns number type

364

}

365

366

public class AbsFunction extends ScalarFunction {

367

public AbsFunction(List<Expression> children)

368

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

369

public PDataType getDataType() // Returns same as input

370

}

371

372

public class PowerFunction extends ScalarFunction {

373

public PowerFunction(List<Expression> children) // base, exponent

374

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

375

public PDataType getDataType() // Returns PDouble.INSTANCE

376

}

377

```

378

379

### Date/Time Functions

380

381

```java

382

// Date/time manipulation functions

383

public class NowFunction extends ScalarFunction {

384

public NowFunction() // No arguments

385

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

386

public PDataType getDataType() // Returns PTimestamp.INSTANCE

387

}

388

389

public class ToDateFunction extends ScalarFunction {

390

public ToDateFunction(List<Expression> children) // string, [format]

391

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

392

public PDataType getDataType() // Returns PDate.INSTANCE

393

}

394

395

public class YearFunction extends ScalarFunction {

396

public YearFunction(List<Expression> children) // date

397

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

398

public PDataType getDataType() // Returns PInteger.INSTANCE

399

}

400

```

401

402

### Aggregate Functions

403

404

```java

405

// Standard aggregate functions

406

public class CountAggregateFunction extends SingleAggregateFunction {

407

public CountAggregateFunction(List<Expression> children)

408

public Aggregator newAggregator()

409

public PDataType getDataType() // Returns PLong.INSTANCE

410

}

411

412

public class SumAggregateFunction extends SingleAggregateFunction {

413

public SumAggregateFunction(List<Expression> children)

414

public Aggregator newAggregator()

415

public PDataType getDataType() // Returns numeric type

416

}

417

418

public class AvgAggregateFunction extends SingleAggregateFunction {

419

public AvgAggregateFunction(List<Expression> children)

420

public Aggregator newAggregator()

421

public PDataType getDataType() // Returns PDecimal.INSTANCE

422

}

423

424

public class MinAggregateFunction extends SingleAggregateFunction {

425

public MinAggregateFunction(List<Expression> children)

426

public Aggregator newAggregator()

427

public PDataType getDataType() // Returns same as input

428

}

429

430

public class MaxAggregateFunction extends SingleAggregateFunction {

431

public MaxAggregateFunction(List<Expression> children)

432

public Aggregator newAggregator()

433

public PDataType getDataType() // Returns same as input

434

}

435

```

436

437

**Usage:**

438

```java

439

// Aggregate function examples

440

Expression salaryColumn = new ColumnExpression(salaryColumn, tableBytes);

441

442

// COUNT(*)

443

CountAggregateFunction count = new CountAggregateFunction(

444

Arrays.asList(LiteralExpression.newConstant(1))

445

);

446

447

// SUM(salary)

448

SumAggregateFunction sum = new SumAggregateFunction(Arrays.asList(salaryColumn));

449

450

// AVG(salary)

451

AvgAggregateFunction avg = new AvgAggregateFunction(Arrays.asList(salaryColumn));

452

453

// MIN(salary)

454

MinAggregateFunction min = new MinAggregateFunction(Arrays.asList(salaryColumn));

455

456

// MAX(salary)

457

MaxAggregateFunction max = new MaxAggregateFunction(Arrays.asList(salaryColumn));

458

459

// Create aggregators

460

Aggregator countAgg = count.newAggregator();

461

Aggregator sumAgg = sum.newAggregator();

462

Aggregator avgAgg = avg.newAggregator();

463

464

// Process rows

465

while (hasMoreRows()) {

466

Tuple row = getNextRow();

467

468

// Aggregate each row

469

countAgg.aggregate(row, null);

470

ImmutableBytesWritable ptr = new ImmutableBytesWritable();

471

if (salaryColumn.evaluate(row, ptr)) {

472

sumAgg.aggregate(row, ptr);

473

avgAgg.aggregate(row, ptr);

474

}

475

}

476

477

// Get final results

478

ImmutableBytesWritable result = new ImmutableBytesWritable();

479

480

if (countAgg.evaluate(null, result)) {

481

Long countValue = (Long) count.getDataType().toObject(result);

482

System.out.println("Count: " + countValue);

483

}

484

485

if (sumAgg.evaluate(null, result)) {

486

Object sumValue = sum.getDataType().toObject(result);

487

System.out.println("Sum: " + sumValue);

488

}

489

```

490

491

## Complex Expression Examples

492

493

### Conditional Expressions

494

495

```java

496

// CASE WHEN expressions

497

public class CaseExpression extends ScalarFunction {

498

public CaseExpression(List<Expression> children)

499

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

500

public PDataType getDataType()

501

}

502

503

// Usage: CASE WHEN age < 18 THEN 'Minor' ELSE 'Adult' END

504

Expression ageColumn = new ColumnExpression(ageColumn, tableBytes);

505

Expression condition = new ComparisonExpression(

506

CompareOp.LESS,

507

Arrays.asList(ageColumn, LiteralExpression.newConstant(18))

508

);

509

Expression caseExpr = new CaseExpression(Arrays.asList(

510

condition,

511

LiteralExpression.newConstant("Minor"),

512

LiteralExpression.newConstant("Adult")

513

));

514

```

515

516

### Arithmetic Expressions

517

518

```java

519

// Arithmetic operations

520

public class ArithmeticExpression extends ScalarFunction {

521

public ArithmeticExpression(ArithmeticOp op, List<Expression> children)

522

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

523

public PDataType getDataType()

524

}

525

526

// Usage: salary * 1.1 (10% raise)

527

Expression salaryColumn = new ColumnExpression(salaryColumn, tableBytes);

528

Expression raiseMultiplier = LiteralExpression.newConstant(new BigDecimal("1.1"));

529

Expression raisedSalary = new ArithmeticExpression(

530

ArithmeticOp.MULT,

531

Arrays.asList(salaryColumn, raiseMultiplier)

532

);

533

```

534

535

### Comparison Expressions

536

537

```java

538

// Comparison operations

539

public class ComparisonExpression extends ScalarFunction {

540

public ComparisonExpression(CompareOp op, List<Expression> children)

541

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr)

542

public PDataType getDataType() // Returns PBoolean.INSTANCE

543

}

544

545

// Usage: age >= 21

546

Expression ageColumn = new ColumnExpression(ageColumn, tableBytes);

547

Expression legalAge = LiteralExpression.newConstant(21);

548

Expression isLegalAge = new ComparisonExpression(

549

CompareOp.GREATER_OR_EQUAL,

550

Arrays.asList(ageColumn, legalAge)

551

);

552

```

553

554

## Practical Examples

555

556

### Building Complex Expressions

557

558

```java

559

public class ExpressionBuilder {

560

private final PTable table;

561

private final byte[] tableBytes;

562

563

public ExpressionBuilder(PTable table) {

564

this.table = table;

565

this.tableBytes = table.getName().getBytes();

566

}

567

568

public Expression buildFullNameExpression() {

569

// CONCAT(first_name, ' ', last_name)

570

Expression firstName = new ColumnExpression(table.getColumn("first_name"), tableBytes);

571

Expression lastName = new ColumnExpression(table.getColumn("last_name"), tableBytes);

572

Expression space = LiteralExpression.newConstant(" ");

573

574

return new ConcatFunction(Arrays.asList(firstName, space, lastName));

575

}

576

577

public Expression buildAgeGroupExpression() {

578

// CASE

579

// WHEN age < 18 THEN 'Minor'

580

// WHEN age < 65 THEN 'Adult'

581

// ELSE 'Senior'

582

// END

583

Expression ageColumn = new ColumnExpression(table.getColumn("age"), tableBytes);

584

585

Expression isMinor = new ComparisonExpression(

586

CompareOp.LESS,

587

Arrays.asList(ageColumn, LiteralExpression.newConstant(18))

588

);

589

590

Expression isAdult = new ComparisonExpression(

591

CompareOp.LESS,

592

Arrays.asList(ageColumn, LiteralExpression.newConstant(65))

593

);

594

595

return new CaseExpression(Arrays.asList(

596

isMinor, LiteralExpression.newConstant("Minor"),

597

isAdult, LiteralExpression.newConstant("Adult"),

598

LiteralExpression.newConstant("Senior")

599

));

600

}

601

602

public Expression buildSalaryBonusExpression() {

603

// salary + (salary * bonus_percentage / 100)

604

Expression salary = new ColumnExpression(table.getColumn("salary"), tableBytes);

605

Expression bonusPercent = new ColumnExpression(table.getColumn("bonus_percentage"), tableBytes);

606

Expression hundred = LiteralExpression.newConstant(100);

607

608

Expression bonusAmount = new ArithmeticExpression(

609

ArithmeticOp.MULT,

610

Arrays.asList(salary, bonusPercent)

611

);

612

613

Expression bonusDivided = new ArithmeticExpression(

614

ArithmeticOp.DIV,

615

Arrays.asList(bonusAmount, hundred)

616

);

617

618

return new ArithmeticExpression(

619

ArithmeticOp.ADD,

620

Arrays.asList(salary, bonusDivided)

621

);

622

}

623

}

624

625

// Usage

626

PTable employeeTable = connection.getTable(PNameFactory.newName("employees"));

627

ExpressionBuilder builder = new ExpressionBuilder(employeeTable);

628

629

Expression fullName = builder.buildFullNameExpression();

630

Expression ageGroup = builder.buildAgeGroupExpression();

631

Expression totalSalary = builder.buildSalaryBonusExpression();

632

633

// Evaluate expressions for a row

634

Tuple employeeRow = getCurrentEmployeeRow();

635

ImmutableBytesWritable result = new ImmutableBytesWritable();

636

637

if (fullName.evaluate(employeeRow, result)) {

638

String name = (String) fullName.getDataType().toObject(result);

639

System.out.println("Full Name: " + name);

640

}

641

642

if (ageGroup.evaluate(employeeRow, result)) {

643

String group = (String) ageGroup.getDataType().toObject(result);

644

System.out.println("Age Group: " + group);

645

}

646

647

if (totalSalary.evaluate(employeeRow, result)) {

648

BigDecimal total = (BigDecimal) totalSalary.getDataType().toObject(result);

649

System.out.println("Total Salary: $" + total);

650

}

651

```

652

653

### Custom Function Implementation

654

655

```java

656

// Custom scalar function example

657

public class AgeFromBirthdateFunction extends ScalarFunction {

658

public AgeFromBirthdateFunction(List<Expression> children) {

659

super("AGE_FROM_BIRTHDATE", children);

660

if (children.size() != 1) {

661

throw new IllegalArgumentException("AGE_FROM_BIRTHDATE expects 1 argument");

662

}

663

}

664

665

@Override

666

public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {

667

Expression birthdateExpr = getChildren().get(0);

668

669

if (!birthdateExpr.evaluate(tuple, ptr)) {

670

return false;

671

}

672

673

if (ptr.getLength() == 0) {

674

return true; // NULL input -> NULL output

675

}

676

677

// Get birthdate value

678

Date birthdate = (Date) birthdateExpr.getDataType().toObject(ptr);

679

680

// Calculate age

681

Calendar birth = Calendar.getInstance();

682

birth.setTime(birthdate);

683

684

Calendar now = Calendar.getInstance();

685

686

int age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR);

687

if (now.get(Calendar.DAY_OF_YEAR) < birth.get(Calendar.DAY_OF_YEAR)) {

688

age--;

689

}

690

691

// Convert result to bytes

692

return PInteger.INSTANCE.toBytes(age, ptr.get(), ptr.getOffset());

693

}

694

695

@Override

696

public PDataType getDataType() {

697

return PInteger.INSTANCE;

698

}

699

}

700

701

// Usage

702

Expression birthdateColumn = new ColumnExpression(table.getColumn("birthdate"), tableBytes);

703

AgeFromBirthdateFunction ageFunc = new AgeFromBirthdateFunction(Arrays.asList(birthdateColumn));

704

705

// Evaluate custom function

706

Tuple row = getCurrentRow();

707

ImmutableBytesWritable result = new ImmutableBytesWritable();

708

if (ageFunc.evaluate(row, result)) {

709

Integer age = (Integer) ageFunc.getDataType().toObject(result);

710

System.out.println("Calculated age: " + age);

711

}

712

```