or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

batch-operations.mdcore-operations.mddataset.mdindex.mdparameters.mdresult-processing.mdstored-procedures.mdtransactions.md

stored-procedures.mddocs/

0

# Stored Procedures

1

2

Complete stored procedure support with input/output parameters, result set processing, and CallableStatement wrapper functionality.

3

4

## Capabilities

5

6

### Basic Stored Procedure Calls

7

8

Execute stored procedures with input parameters and retrieve output values.

9

10

```java { .api }

11

// Basic procedure calls

12

public List call(String sql) throws SQLException;

13

public List call(String sql, List<?> params) throws SQLException;

14

public List call(String sql, List<?> params, Closure closure) throws SQLException;

15

public List call(GString gstring) throws SQLException;

16

17

// Map-based parameter calls

18

public List call(String sql, Map params) throws SQLException;

19

public List call(Map params, String sql) throws SQLException;

20

public List call(String sql, Map params, Closure closure) throws SQLException;

21

public List call(Map params, String sql, Closure closure) throws SQLException;

22

```

23

24

**Example**:

25

```groovy

26

import static groovy.sql.Sql.*

27

28

// Simple procedure call with no parameters

29

def result = sql.call('CALL get_server_time()')

30

println "Server time: ${result[0]}"

31

32

// Procedure with input parameters

33

def userId = 123

34

def results = sql.call('CALL get_user_details(?)', [userId])

35

results.each { row ->

36

println "User data: $row"

37

}

38

39

// Using output parameters

40

def params = [

41

INTEGER(userId), // input parameter

42

out(VARCHAR), // output parameter for user name

43

out(INTEGER) // output parameter for user count

44

]

45

def outputs = sql.call('CALL get_user_info(?, ?, ?)', params)

46

println "User name: ${outputs[0][1]}" // First row, second column (first output param)

47

println "User count: ${outputs[0][2]}" // First row, third column (second output param)

48

```

49

50

### Result Set Processing

51

52

Process result sets returned by stored procedures with various processing options.

53

54

```java { .api }

55

// Process first result set only

56

public void callWithRows(String sql, Closure closure) throws SQLException;

57

public void callWithRows(String sql, List<?> params, Closure closure) throws SQLException;

58

public void callWithRows(String sql, List<?> params, Closure metaClosure, Closure rowClosure) throws SQLException;

59

60

// Process all result sets

61

public void callWithAllRows(String sql, Closure closure) throws SQLException;

62

public void callWithAllRows(String sql, List<?> params, Closure closure) throws SQLException;

63

public void callWithAllRows(String sql, List<?> params, Closure metaClosure, Closure rowClosure) throws SQLException;

64

65

// Result set processing constants

66

public static final int NO_RESULT_SETS = 0;

67

public static final int FIRST_RESULT_SET = 1;

68

public static final int ALL_RESULT_SETS = 2;

69

```

70

71

**Example**:

72

```groovy

73

// Process first result set from procedure

74

sql.callWithRows('CALL get_active_users()') { row ->

75

println "Active user: ${row.name} (${row.email})"

76

}

77

78

// Process first result set with parameters

79

sql.callWithRows('CALL get_users_by_department(?)', ['Engineering']) { row ->

80

println "${row.name} - ${row.title}"

81

}

82

83

// Process all result sets (procedure returns multiple result sets)

84

sql.callWithAllRows('CALL get_user_summary(?)') { resultSet ->

85

println "Processing result set..."

86

while (resultSet.next()) {

87

println "Row: ${resultSet.getString(1)}"

88

}

89

}

90

91

// With metadata processing

92

sql.callWithRows('CALL get_report_data(?)', [reportId],

93

{ meta ->

94

println "Report has ${meta.columnCount} columns"

95

(1..meta.columnCount).each { i ->

96

println "Column $i: ${meta.getColumnName(i)}"

97

}

98

},

99

{ row ->

100

println "Data row: $row"

101

}

102

)

103

```

104

105

### Input/Output Parameters

106

107

Handle complex parameter combinations including input, output, and bidirectional parameters.

108

109

```java { .api }

110

// Parameter type interfaces (defined in parameters.md)

111

public interface InParameter {

112

int getType();

113

Object getValue();

114

}

115

116

public interface OutParameter {

117

int getType();

118

}

119

120

public interface InOutParameter extends InParameter, OutParameter {}

121

122

public interface ResultSetOutParameter extends OutParameter {}

123

```

124

125

**Example**:

126

```groovy

127

import static groovy.sql.Sql.*

128

import java.sql.Types

129

130

// Complex parameter scenario

131

def params = [

132

VARCHAR('john.doe'), // input: username

133

out(INTEGER), // output: user ID

134

out(VARCHAR), // output: full name

135

out(TIMESTAMP), // output: last login

136

inout(VARCHAR('active')) // input/output: status (input 'active', may be changed by procedure)

137

]

138

139

def results = sql.call('CALL authenticate_user(?, ?, ?, ?, ?)', params)

140

141

// Extract output values from first result row

142

def outputRow = results[0]

143

def userId = outputRow[1] // First output parameter (user ID)

144

def fullName = outputRow[2] // Second output parameter (full name)

145

def lastLogin = outputRow[3] // Third output parameter (last login)

146

def finalStatus = outputRow[4] // InOut parameter final value

147

148

println "Authentication result:"

149

println "User ID: $userId"

150

println "Name: $fullName"

151

println "Last login: $lastLogin"

152

println "Status: $finalStatus"

153

154

// Handle null outputs

155

if (userId == null) {

156

println "Authentication failed"

157

} else {

158

println "User authenticated successfully"

159

}

160

```

161

162

### ResultSet Output Parameters

163

164

Handle stored procedures that return result sets as output parameters.

165

166

```java { .api }

167

public static ResultSetOutParameter resultSet(int type);

168

```

169

170

**Example**:

171

```groovy

172

import static groovy.sql.Sql.*

173

174

// Procedure with ResultSet output parameter

175

def params = [

176

INTEGER(departmentId), // input: department ID

177

resultSet(Types.OTHER) // output: result set of employees

178

]

179

180

def results = sql.call('CALL get_department_employees(?, ?)', params)

181

182

// The ResultSet is returned as part of the output

183

def employeeResultSet = results[0][1] // Second column contains the ResultSet

184

185

// Process the returned ResultSet

186

if (employeeResultSet instanceof ResultSet) {

187

while (employeeResultSet.next()) {

188

println "Employee: ${employeeResultSet.getString('name')} - ${employeeResultSet.getString('title')}"

189

}

190

employeeResultSet.close()

191

}

192

```

193

194

### Complex Stored Procedure Scenarios

195

196

Handle advanced stored procedure patterns including multiple result sets, cursors, and error handling.

197

198

**Example**:

199

```groovy

200

// Procedure returning multiple result sets

201

sql.call('CALL get_comprehensive_report(?)', [reportId]) { allResults ->

202

allResults.eachWithIndex { resultSet, index ->

203

println "Processing result set $index:"

204

205

// Get metadata for this result set

206

def meta = resultSet.metaData

207

def columnNames = (1..meta.columnCount).collect { meta.getColumnName(it) }

208

println "Columns: ${columnNames.join(', ')}"

209

210

// Process rows

211

while (resultSet.next()) {

212

def row = columnNames.collectEntries { col ->

213

[col, resultSet.getObject(col)]

214

}

215

println "Row: $row"

216

}

217

println "---"

218

}

219

}

220

221

// Error handling with stored procedures

222

try {

223

def params = [

224

INTEGER(accountId),

225

DECIMAL(amount),

226

out(VARCHAR), // output: error message

227

out(INTEGER) // output: error code

228

]

229

230

def results = sql.call('CALL transfer_funds(?, ?, ?, ?)', params)

231

232

def errorMessage = results[0][2]

233

def errorCode = results[0][3]

234

235

if (errorCode != 0) {

236

println "Transfer failed: $errorMessage (code: $errorCode)"

237

} else {

238

println "Transfer successful"

239

}

240

241

} catch (SQLException e) {

242

println "Database error during transfer: ${e.message}"

243

}

244

245

// Working with cursor-based procedures

246

def cursorParams = [

247

INTEGER(pageSize),

248

INTEGER(offset),

249

out(Types.OTHER) // cursor output

250

]

251

252

sql.call('CALL get_paged_results(?, ?, ?)', cursorParams) { results ->

253

// Handle cursor-based result processing

254

// Implementation depends on database-specific cursor handling

255

}

256

```

257

258

### Batch Stored Procedure Calls

259

260

Execute stored procedures in batch mode for improved performance.

261

262

**Example**:

263

```groovy

264

// Batch procedure calls with same parameters structure

265

def userUpdates = [

266

[userId: 1, status: 'active', lastLogin: new Date()],

267

[userId: 2, status: 'inactive', lastLogin: new Date() - 30],

268

[userId: 3, status: 'pending', lastLogin: null]

269

]

270

271

sql.withBatch('CALL update_user_status(?, ?, ?)') { stmt ->

272

userUpdates.each { update ->

273

stmt.addBatch([

274

INTEGER(update.userId),

275

VARCHAR(update.status),

276

update.lastLogin ? TIMESTAMP(update.lastLogin) : null

277

])

278

}

279

}

280

281

// Batch with different procedure calls

282

sql.withBatch { stmt ->

283

// Different procedures in same batch

284

stmt.addBatch('CALL log_user_action(?, ?)', [INTEGER(userId), VARCHAR('login')])

285

stmt.addBatch('CALL update_last_seen(?)', [INTEGER(userId)])

286

stmt.addBatch('CALL increment_login_count(?)', [INTEGER(userId)])

287

}

288

```

289

290

### Database-Specific Stored Procedure Examples

291

292

Handle database-specific stored procedure patterns and syntax variations.

293

294

**Example**:

295

```groovy

296

// MySQL stored procedure with multiple outputs

297

def mysqlParams = [

298

INTEGER(customerId),

299

out(DECIMAL), // total_orders

300

out(DECIMAL), // total_amount

301

out(INTEGER) // order_count

302

]

303

def mysqlResults = sql.call('CALL get_customer_stats(?, ?, ?, ?)', mysqlParams)

304

305

// Oracle procedure with cursor

306

def oracleParams = [

307

INTEGER(departmentId),

308

out(Types.OTHER) // REF CURSOR

309

]

310

// Oracle-specific cursor handling would go here

311

312

// SQL Server procedure with table-valued parameter

313

def sqlServerData = [

314

[id: 1, name: 'Item 1', price: 10.99],

315

[id: 2, name: 'Item 2', price: 15.99]

316

]

317

// SQL Server table-valued parameters require special handling

318

319

// PostgreSQL function call (functions vs procedures)

320

def pgResult = sql.firstRow('SELECT * FROM calculate_interest(?, ?)', [principal, rate])

321

println "Interest: ${pgResult.interest_amount}"

322

```