or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cluster-management.mdconfiguration.mdcore-api.mddata-structures.mdindex.mdsql-service.mdstream-processing.md

sql-service.mddocs/

0

# SQL Service

1

2

Hazelcast provides a distributed SQL engine that allows you to query data across the cluster using standard SQL syntax. The SQL service supports querying maps, accessing streaming data, and performing distributed joins and aggregations.

3

4

## SqlService Interface

5

6

The main interface for executing SQL operations in Hazelcast.

7

8

```java { .api }

9

import com.hazelcast.sql.SqlService;

10

import com.hazelcast.sql.SqlResult;

11

import com.hazelcast.sql.SqlStatement;

12

13

public interface SqlService {

14

// Execute SQL with inline parameters

15

SqlResult execute(String sql, Object... arguments);

16

17

// Execute SQL statement object

18

SqlResult execute(SqlStatement statement);

19

20

// Execute DML statements (INSERT, UPDATE, DELETE)

21

long executeUpdate(String sql, Object... arguments);

22

}

23

```

24

25

### Getting SqlService

26

27

```java { .api }

28

HazelcastInstance hz = Hazelcast.newHazelcastInstance();

29

SqlService sql = hz.getSql();

30

```

31

32

## SQL Statements

33

34

### SqlStatement Class

35

36

Represents a prepared SQL statement with parameters and execution options.

37

38

```java { .api }

39

import com.hazelcast.sql.SqlStatement;

40

import com.hazelcast.sql.SqlExpectedResultType;

41

import java.util.concurrent.TimeUnit;

42

43

public class SqlStatement {

44

// Statement creation

45

public static SqlStatement of(String sql);

46

public static SqlStatement of(String sql, Object... parameters);

47

48

// Configuration methods

49

public SqlStatement setSql(String sql);

50

public String getSql();

51

52

public SqlStatement setParameters(List<?> parameters);

53

public SqlStatement addParameter(Object parameter);

54

public List<Object> getParameters();

55

56

public SqlStatement setTimeoutMillis(long timeoutMillis);

57

public long getTimeoutMillis();

58

59

public SqlStatement setCursorBufferSize(int cursorBufferSize);

60

public int getCursorBufferSize();

61

62

public SqlStatement setExpectedResultType(SqlExpectedResultType expectedResultType);

63

public SqlExpectedResultType getExpectedResultType();

64

65

public SqlStatement setSchema(String schema);

66

public String getSchema();

67

}

68

```

69

70

### Expected Result Types

71

72

```java { .api }

73

import com.hazelcast.sql.SqlExpectedResultType;

74

75

public enum SqlExpectedResultType {

76

ANY, // Any result type is acceptable

77

ROWS, // Expect query results (SELECT)

78

UPDATE_COUNT // Expect update count (INSERT, UPDATE, DELETE)

79

}

80

```

81

82

### Basic SQL Execution

83

84

```java { .api }

85

// Simple query execution

86

SqlResult result = sql.execute("SELECT name, age FROM employees WHERE age > ?", 25);

87

88

// Using SqlStatement

89

SqlStatement statement = SqlStatement.of("SELECT * FROM products WHERE category = ? AND price > ?")

90

.addParameter("electronics")

91

.addParameter(100.0)

92

.setTimeoutMillis(30000);

93

94

SqlResult result = sql.execute(statement);

95

96

// DML operations

97

long updateCount = sql.executeUpdate("UPDATE employees SET salary = salary * 1.1 WHERE department = ?", "Engineering");

98

System.out.println("Updated " + updateCount + " employees");

99

```

100

101

## SQL Results

102

103

### SqlResult Interface

104

105

Represents the result of a SQL query execution.

106

107

```java { .api }

108

import com.hazelcast.sql.SqlResult;

109

import com.hazelcast.sql.SqlRow;

110

import com.hazelcast.sql.SqlRowMetadata;

111

import java.util.Iterator;

112

113

public interface SqlResult extends Iterable<SqlRow>, AutoCloseable {

114

// Metadata

115

SqlRowMetadata getRowMetadata();

116

117

// Row iteration

118

Iterator<SqlRow> iterator();

119

120

// Update count for DML operations

121

long updateCount();

122

boolean isUpdateCountValid();

123

124

// Resource management

125

void close();

126

}

127

```

128

129

### SqlRow Interface

130

131

Represents a single row in the result set.

132

133

```java { .api }

134

import com.hazelcast.sql.SqlRow;

135

136

public interface SqlRow {

137

// Get by column index

138

<T> T getObject(int columnIndex);

139

140

// Get by column name

141

<T> T getObject(String columnName);

142

143

// Metadata

144

SqlRowMetadata getMetadata();

145

}

146

```

147

148

### SqlRowMetadata Interface

149

150

Provides metadata about the result set structure.

151

152

```java { .api }

153

import com.hazelcast.sql.SqlRowMetadata;

154

import com.hazelcast.sql.SqlColumnMetadata;

155

import java.util.List;

156

157

public interface SqlRowMetadata {

158

// Column information

159

int getColumnCount();

160

List<SqlColumnMetadata> getColumns();

161

SqlColumnMetadata getColumn(int index);

162

163

// Column lookup

164

int findColumn(String columnName);

165

}

166

```

167

168

### SqlColumnMetadata Interface

169

170

Provides metadata about individual columns.

171

172

```java { .api }

173

import com.hazelcast.sql.SqlColumnMetadata;

174

import com.hazelcast.sql.SqlColumnType;

175

176

public interface SqlColumnMetadata {

177

String getName();

178

SqlColumnType getType();

179

boolean isNullableUnknown();

180

}

181

```

182

183

### SQL Column Types

184

185

```java { .api }

186

import com.hazelcast.sql.SqlColumnType;

187

188

public enum SqlColumnType {

189

VARCHAR,

190

BOOLEAN,

191

TINYINT,

192

SMALLINT,

193

INTEGER,

194

BIGINT,

195

DECIMAL,

196

REAL,

197

DOUBLE,

198

DATE,

199

TIME,

200

TIMESTAMP,

201

TIMESTAMP_WITH_TIME_ZONE,

202

OBJECT,

203

NULL,

204

JSON

205

}

206

```

207

208

## Query Examples

209

210

### Basic Queries

211

212

```java { .api }

213

// SELECT queries

214

SqlResult result = sql.execute("SELECT * FROM employees");

215

216

// Process results

217

for (SqlRow row : result) {

218

String name = row.getObject("name");

219

Integer age = row.getObject("age");

220

String department = row.getObject("department");

221

222

System.out.println(name + ", " + age + ", " + department);

223

}

224

225

// Always close results

226

result.close();

227

228

// Using try-with-resources

229

try (SqlResult result = sql.execute("SELECT COUNT(*) as employee_count FROM employees")) {

230

for (SqlRow row : result) {

231

Long count = row.getObject("employee_count");

232

System.out.println("Total employees: " + count);

233

}

234

}

235

```

236

237

### Parameterized Queries

238

239

```java { .api }

240

// Parameterized queries prevent SQL injection

241

String department = "Engineering";

242

int minAge = 25;

243

244

try (SqlResult result = sql.execute(

245

"SELECT name, age, salary FROM employees WHERE department = ? AND age >= ?",

246

department, minAge)) {

247

248

for (SqlRow row : result) {

249

System.out.println(String.format("%s (%d): $%.2f",

250

row.getObject("name"),

251

row.<Integer>getObject("age"),

252

row.<Double>getObject("salary")));

253

}

254

}

255

```

256

257

### Aggregation Queries

258

259

```java { .api }

260

// Aggregation with grouping

261

try (SqlResult result = sql.execute(

262

"SELECT department, COUNT(*) as emp_count, AVG(salary) as avg_salary " +

263

"FROM employees " +

264

"GROUP BY department " +

265

"HAVING COUNT(*) > ?"

266

, 5)) {

267

268

System.out.println("Department Statistics:");

269

for (SqlRow row : result) {

270

String dept = row.getObject("department");

271

Long count = row.getObject("emp_count");

272

Double avgSalary = row.getObject("avg_salary");

273

274

System.out.println(String.format("%s: %d employees, avg salary: $%.2f",

275

dept, count, avgSalary));

276

}

277

}

278

```

279

280

### Window Functions

281

282

```java { .api }

283

// Window functions for ranking

284

try (SqlResult result = sql.execute(

285

"SELECT name, department, salary, " +

286

" RANK() OVER (PARTITION BY department ORDER BY salary DESC) as dept_rank, " +

287

" ROW_NUMBER() OVER (ORDER BY salary DESC) as overall_rank " +

288

"FROM employees")) {

289

290

for (SqlRow row : result) {

291

System.out.println(String.format("%s (%s): Salary $%.2f, Dept Rank: %d, Overall Rank: %d",

292

row.<String>getObject("name"),

293

row.<String>getObject("department"),

294

row.<Double>getObject("salary"),

295

row.<Long>getObject("dept_rank"),

296

row.<Long>getObject("overall_rank")));

297

}

298

}

299

```

300

301

## Data Manipulation

302

303

### INSERT Operations

304

305

```java { .api }

306

// Insert single record

307

long insertCount = sql.executeUpdate(

308

"INSERT INTO employees (id, name, age, department, salary) VALUES (?, ?, ?, ?, ?)",

309

1001, "Alice Johnson", 28, "Engineering", 75000.0);

310

311

System.out.println("Inserted " + insertCount + " record(s)");

312

313

// Insert multiple records with batch

314

SqlStatement insertStatement = SqlStatement.of(

315

"INSERT INTO employees (id, name, age, department, salary) VALUES (?, ?, ?, ?, ?)");

316

317

// Note: Batch operations would typically be done in a loop or with bulk insert

318

long count1 = sql.executeUpdate(insertStatement.getSql(), 1002, "Bob Smith", 32, "Marketing", 68000.0);

319

long count2 = sql.executeUpdate(insertStatement.getSql(), 1003, "Carol Davis", 29, "Engineering", 72000.0);

320

```

321

322

### UPDATE Operations

323

324

```java { .api }

325

// Update with conditions

326

long updateCount = sql.executeUpdate(

327

"UPDATE employees SET salary = salary * ? WHERE department = ? AND age < ?",

328

1.15, "Engineering", 30);

329

330

System.out.println("Updated " + updateCount + " employees");

331

332

// Conditional update with CASE

333

sql.executeUpdate(

334

"UPDATE employees SET bonus = " +

335

"CASE " +

336

" WHEN salary > 80000 THEN salary * 0.15 " +

337

" WHEN salary > 60000 THEN salary * 0.10 " +

338

" ELSE salary * 0.05 " +

339

"END " +

340

"WHERE department = ?", "Sales");

341

```

342

343

### DELETE Operations

344

345

```java { .api }

346

// Delete with conditions

347

long deleteCount = sql.executeUpdate(

348

"DELETE FROM employees WHERE age > ? AND department = ?",

349

65, "Retired");

350

351

System.out.println("Deleted " + deleteCount + " employees");

352

353

// Delete with subquery

354

sql.executeUpdate(

355

"DELETE FROM employees WHERE id IN " +

356

"(SELECT id FROM employees WHERE salary < (SELECT AVG(salary) * 0.5 FROM employees))");

357

```

358

359

## Advanced SQL Features

360

361

### Joins Across Maps

362

363

```java { .api }

364

// Setup: Assume we have employees and departments maps

365

// employees: {id, name, dept_id, salary}

366

// departments: {id, name, budget}

367

368

// Inner join

369

try (SqlResult result = sql.execute(

370

"SELECT e.name as employee_name, d.name as department_name, e.salary " +

371

"FROM employees e " +

372

"INNER JOIN departments d ON e.dept_id = d.id " +

373

"WHERE e.salary > ?", 70000)) {

374

375

for (SqlRow row : result) {

376

System.out.println(String.format("%s works in %s, earns $%.2f",

377

row.<String>getObject("employee_name"),

378

row.<String>getObject("department_name"),

379

row.<Double>getObject("salary")));

380

}

381

}

382

383

// Left join with aggregation

384

try (SqlResult result = sql.execute(

385

"SELECT d.name as department, COUNT(e.id) as employee_count, " +

386

" COALESCE(AVG(e.salary), 0) as avg_salary " +

387

"FROM departments d " +

388

"LEFT JOIN employees e ON d.id = e.dept_id " +

389

"GROUP BY d.name " +

390

"ORDER BY employee_count DESC")) {

391

392

for (SqlRow row : result) {

393

System.out.println(String.format("%s: %d employees, avg salary: $%.2f",

394

row.<String>getObject("department"),

395

row.<Long>getObject("employee_count"),

396

row.<Double>getObject("avg_salary")));

397

}

398

}

399

```

400

401

### Streaming SQL

402

403

```java { .api }

404

// Query streaming data from map journals or topics

405

// Note: This requires appropriate configuration for streaming

406

407

try (SqlResult result = sql.execute(

408

"SELECT * FROM TABLE(IMPOSE_ORDER(" +

409

" TABLE(stream_from_map_journal('events', 'event_timestamp')), " +

410

" DESCRIPTOR(event_timestamp), " +

411

" INTERVAL '1' SECOND" +

412

"))")) {

413

414

for (SqlRow row : result) {

415

// Process streaming data

416

System.out.println("Event: " + row.getObject("event_data"));

417

}

418

}

419

```

420

421

### JSON Support

422

423

```java { .api }

424

// Working with JSON data

425

try (SqlResult result = sql.execute(

426

"SELECT " +

427

" JSON_EXTRACT(user_data, '$.name') as name, " +

428

" JSON_EXTRACT(user_data, '$.preferences.theme') as theme " +

429

"FROM user_profiles " +

430

"WHERE JSON_EXTRACT(user_data, '$.active') = true")) {

431

432

for (SqlRow row : result) {

433

String name = row.getObject("name");

434

String theme = row.getObject("theme");

435

System.out.println("User " + name + " prefers " + theme + " theme");

436

}

437

}

438

```

439

440

## Exception Handling

441

442

### HazelcastSqlException

443

444

```java { .api }

445

import com.hazelcast.sql.HazelcastSqlException;

446

447

public class HazelcastSqlException extends HazelcastException {

448

public int getCode();

449

public String getMessage();

450

public String getSuggestion();

451

public Member getOriginatingMember();

452

}

453

```

454

455

### Error Handling Examples

456

457

```java { .api }

458

try {

459

SqlResult result = sql.execute("SELECT * FROM non_existent_table");

460

// Process results...

461

462

} catch (HazelcastSqlException e) {

463

System.err.println("SQL Error " + e.getCode() + ": " + e.getMessage());

464

if (e.getSuggestion() != null) {

465

System.err.println("Suggestion: " + e.getSuggestion());

466

}

467

468

// Handle specific error codes

469

switch (e.getCode()) {

470

case 1000: // Generic error

471

// Handle generic error

472

break;

473

case 2000: // Parsing error

474

System.err.println("SQL syntax error");

475

break;

476

case 3000: // Data conversion error

477

System.err.println("Data type conversion failed");

478

break;

479

default:

480

System.err.println("Unhandled SQL error");

481

}

482

483

} catch (Exception e) {

484

System.err.println("Unexpected error: " + e.getMessage());

485

}

486

```

487

488

## Performance and Best Practices

489

490

### Query Optimization

491

492

```java { .api }

493

// Use indexes for better performance

494

// This should be done during map configuration, not via SQL

495

// But you can check index usage in execution plans

496

497

// Parameterized queries for prepared statement benefits

498

SqlStatement statement = SqlStatement.of("SELECT * FROM employees WHERE department = ?")

499

.setCursorBufferSize(1000) // Optimize for large result sets

500

.setTimeoutMillis(30000); // Set appropriate timeout

501

502

// Process in batches for large results

503

try (SqlResult result = sql.execute(statement.addParameter("Engineering"))) {

504

int batchSize = 0;

505

for (SqlRow row : result) {

506

// Process row

507

batchSize++;

508

509

// Process in batches

510

if (batchSize % 1000 == 0) {

511

System.out.println("Processed " + batchSize + " rows");

512

}

513

}

514

}

515

```

516

517

### Resource Management

518

519

```java { .api }

520

// Always close SqlResult to free resources

521

public List<Employee> getEmployees(String department) {

522

List<Employee> employees = new ArrayList<>();

523

524

try (SqlResult result = sql.execute(

525

"SELECT id, name, salary FROM employees WHERE department = ?", department)) {

526

527

for (SqlRow row : result) {

528

employees.add(new Employee(

529

row.<Integer>getObject("id"),

530

row.<String>getObject("name"),

531

row.<Double>getObject("salary")

532

));

533

}

534

}

535

536

return employees;

537

}

538

539

// For streaming queries, handle properly

540

public void processStreamingData() {

541

SqlStatement streamingQuery = SqlStatement.of(

542

"SELECT * FROM events_stream WHERE event_type = ?")

543

.addParameter("user_action")

544

.setCursorBufferSize(100); // Smaller buffer for streaming

545

546

try (SqlResult result = sql.execute(streamingQuery)) {

547

for (SqlRow row : result) {

548

// Process streaming event

549

processEvent(row);

550

551

// Add break condition for long-running streams

552

if (shouldStop()) {

553

break;

554

}

555

}

556

}

557

}

558

```

559

560

### Mapping Configuration for SQL

561

562

```java { .api }

563

// Configure maps for optimal SQL performance

564

Config config = new Config();

565

566

MapConfig mapConfig = new MapConfig("employees");

567

// Add indexes for commonly queried fields

568

mapConfig.addIndexConfig(new IndexConfig(IndexType.SORTED, "age"));

569

mapConfig.addIndexConfig(new IndexConfig(IndexType.HASH, "department"));

570

mapConfig.addIndexConfig(new IndexConfig(IndexType.BITMAP, "active"));

571

572

config.addMapConfig(mapConfig);

573

574

HazelcastInstance hz = Hazelcast.newHazelcastInstance(config);

575

```

576

577

## Common SQL Patterns

578

579

### Pagination

580

581

```java { .api }

582

public List<Employee> getEmployeesPage(int offset, int limit) {

583

List<Employee> employees = new ArrayList<>();

584

585

try (SqlResult result = sql.execute(

586

"SELECT * FROM employees ORDER BY name LIMIT ? OFFSET ?",

587

limit, offset)) {

588

589

for (SqlRow row : result) {

590

employees.add(mapRowToEmployee(row));

591

}

592

}

593

594

return employees;

595

}

596

```

597

598

### Existence Check

599

600

```java { .api }

601

public boolean employeeExists(int employeeId) {

602

try (SqlResult result = sql.execute(

603

"SELECT 1 FROM employees WHERE id = ? LIMIT 1", employeeId)) {

604

605

return result.iterator().hasNext();

606

}

607

}

608

```

609

610

### Conditional Aggregation

611

612

```java { .api }

613

public DepartmentStats getDepartmentStats(String department) {

614

try (SqlResult result = sql.execute(

615

"SELECT " +

616

" COUNT(*) as total_count, " +

617

" COUNT(CASE WHEN age < 30 THEN 1 END) as young_count, " +

618

" COUNT(CASE WHEN salary > 80000 THEN 1 END) as high_earners, " +

619

" AVG(salary) as avg_salary, " +

620

" MIN(salary) as min_salary, " +

621

" MAX(salary) as max_salary " +

622

"FROM employees WHERE department = ?", department)) {

623

624

if (result.iterator().hasNext()) {

625

SqlRow row = result.iterator().next();

626

return new DepartmentStats(

627

row.<Long>getObject("total_count"),

628

row.<Long>getObject("young_count"),

629

row.<Long>getObject("high_earners"),

630

row.<Double>getObject("avg_salary"),

631

row.<Double>getObject("min_salary"),

632

row.<Double>getObject("max_salary")

633

);

634

}

635

}

636

637

return null;

638

}

639

```