or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-operations.mdconnections.mdcursors.mderror-handling.mdindex.mdrow-factories.mdsql-composition.mdtype-system.md

cursors.mddocs/

0

# Query Execution and Cursors

1

2

Comprehensive cursor functionality for query execution, result fetching, and data manipulation with multiple cursor types optimized for different performance and memory requirements.

3

4

## Capabilities

5

6

### Standard Cursors

7

8

Basic cursor functionality for query execution and result retrieval with full DB-API 2.0 compliance.

9

10

```python { .api }

11

class Cursor:

12

def execute(

13

self,

14

query,

15

params=None,

16

*,

17

prepare: bool | None = None,

18

binary: bool | None = None

19

) -> Cursor:

20

"""

21

Execute a database query.

22

23

Args:

24

query: SQL query string or sql.Composable object

25

params: Query parameters (tuple, list, or dict)

26

prepare: Use prepared statements for better performance

27

binary: Request binary format for results

28

29

Returns:

30

Self for method chaining

31

"""

32

33

def executemany(

34

self,

35

query,

36

params_seq,

37

*,

38

returning: bool = False

39

) -> None:

40

"""

41

Execute query multiple times with different parameter sets.

42

43

Args:

44

query: SQL query string or sql.Composable object

45

params_seq: Sequence of parameter sets

46

returning: True if query returns results

47

"""

48

49

def executescript(self, script: str) -> None:

50

"""Execute multiple SQL statements from a script"""

51

52

def fetchone(self) -> Any:

53

"""

54

Fetch next row from query results.

55

56

Returns:

57

Next row or None if no more rows

58

"""

59

60

def fetchmany(self, size: int | None = None) -> list:

61

"""

62

Fetch multiple rows from query results.

63

64

Args:

65

size: Number of rows to fetch (uses arraysize if None)

66

67

Returns:

68

List of rows (may be empty)

69

"""

70

71

def fetchall(self) -> list:

72

"""

73

Fetch all remaining rows from query results.

74

75

Returns:

76

List of all remaining rows

77

"""

78

79

def close(self) -> None:

80

"""Close the cursor and free resources"""

81

82

def scroll(self, value: int, mode: str = "relative") -> None:

83

"""

84

Scroll cursor position in scrollable cursors.

85

86

Args:

87

value: Number of rows to scroll

88

mode: 'relative' or 'absolute' positioning

89

"""

90

91

class AsyncCursor:

92

async def execute(

93

self,

94

query,

95

params=None,

96

*,

97

prepare: bool | None = None,

98

binary: bool | None = None

99

) -> AsyncCursor:

100

"""Async version of Cursor.execute()"""

101

102

async def executemany(

103

self,

104

query,

105

params_seq,

106

*,

107

returning: bool = False

108

) -> None:

109

"""Async version of Cursor.executemany()"""

110

111

async def fetchone(self) -> Any:

112

"""Async version of Cursor.fetchone()"""

113

114

async def fetchmany(self, size: int | None = None) -> list:

115

"""Async version of Cursor.fetchmany()"""

116

117

async def fetchall(self) -> list:

118

"""Async version of Cursor.fetchall()"""

119

```

120

121

### Server-Side Cursors

122

123

Server-side cursors for memory-efficient processing of large result sets by keeping data on the PostgreSQL server.

124

125

```python { .api }

126

class ServerCursor:

127

def __init__(

128

self,

129

connection,

130

name: str,

131

*,

132

scrollable: bool | None = None,

133

withhold: bool = False

134

):

135

"""

136

Create a server-side cursor.

137

138

Args:

139

connection: Database connection

140

name: Cursor name (must be unique)

141

scrollable: Enable bidirectional scrolling

142

withhold: Keep cursor after transaction commit

143

"""

144

145

@property

146

def name(self) -> str:

147

"""Server-side cursor name"""

148

149

@property

150

def scrollable(self) -> bool | None:

151

"""True if cursor supports scrolling"""

152

153

@property

154

def withhold(self) -> bool:

155

"""True if cursor survives transaction commit"""

156

157

def execute(self, query, params=None, *, binary: bool | None = None) -> ServerCursor:

158

"""Execute query using server-side cursor"""

159

160

def executemany(self, query, params_seq) -> None:

161

"""Execute query multiple times using server cursor"""

162

163

def fetchone(self) -> Any:

164

"""Fetch one row from server cursor"""

165

166

def fetchmany(self, size: int | None = None) -> list:

167

"""Fetch multiple rows from server cursor"""

168

169

def fetchall(self) -> list:

170

"""Fetch all remaining rows from server cursor"""

171

172

class AsyncServerCursor:

173

# Async version of ServerCursor with same interface but async methods

174

async def execute(self, query, params=None, *, binary: bool | None = None) -> AsyncServerCursor: ...

175

async def fetchone(self) -> Any: ...

176

async def fetchmany(self, size: int | None = None) -> list: ...

177

async def fetchall(self) -> list: ...

178

```

179

180

### Client-Side Cursors

181

182

Client-side cursors that fetch and buffer results locally for applications that need random access to result sets.

183

184

```python { .api }

185

class ClientCursor:

186

def execute(self, query, params=None, *, binary: bool | None = None) -> ClientCursor:

187

"""Execute query with client-side result buffering"""

188

189

def fetchone(self) -> Any:

190

"""Fetch one row from client buffer"""

191

192

def fetchmany(self, size: int | None = None) -> list:

193

"""Fetch multiple rows from client buffer"""

194

195

def fetchall(self) -> list:

196

"""Return all buffered rows"""

197

198

def scroll(self, value: int, mode: str = "relative") -> None:

199

"""Scroll within buffered results"""

200

201

class AsyncClientCursor:

202

# Async version of ClientCursor

203

async def execute(self, query, params=None, *, binary: bool | None = None) -> AsyncClientCursor: ...

204

async def fetchone(self) -> Any: ...

205

async def fetchmany(self, size: int | None = None) -> list: ...

206

async def fetchall(self) -> list: ...

207

```

208

209

### Raw Cursors

210

211

Low-level cursors that return raw bytes without type adaptation for maximum performance in specialized applications.

212

213

```python { .api }

214

class RawCursor:

215

"""Cursor returning raw bytes without type conversion"""

216

217

def execute(self, query, params=None, *, binary: bool | None = None) -> RawCursor:

218

"""Execute query returning raw bytes"""

219

220

def fetchone(self) -> tuple[bytes, ...] | None:

221

"""Fetch one row as tuple of bytes"""

222

223

def fetchmany(self, size: int | None = None) -> list[tuple[bytes, ...]]:

224

"""Fetch multiple rows as tuples of bytes"""

225

226

def fetchall(self) -> list[tuple[bytes, ...]]:

227

"""Fetch all rows as tuples of bytes"""

228

229

class RawServerCursor:

230

"""Server-side cursor returning raw bytes"""

231

# Same interface as RawCursor but server-side

232

233

class AsyncRawCursor:

234

"""Async cursor returning raw bytes"""

235

async def execute(self, query, params=None, *, binary: bool | None = None) -> AsyncRawCursor: ...

236

async def fetchone(self) -> tuple[bytes, ...] | None: ...

237

async def fetchmany(self, size: int | None = None) -> list[tuple[bytes, ...]]: ...

238

async def fetchall(self) -> list[tuple[bytes, ...]]: ...

239

240

class AsyncRawServerCursor:

241

"""Async server-side cursor returning raw bytes"""

242

# Same interface as AsyncRawCursor but server-side

243

```

244

245

### Cursor Properties and Metadata

246

247

Access cursor state, query information, and result metadata.

248

249

```python { .api }

250

class Cursor:

251

@property

252

def description(self) -> list[Column] | None:

253

"""Column information for last query results"""

254

255

@property

256

def rowcount(self) -> int:

257

"""Number of rows affected by last query"""

258

259

@property

260

def arraysize(self) -> int:

261

"""Default number of rows for fetchmany()"""

262

263

@arraysize.setter

264

def arraysize(self, size: int) -> None:

265

"""Set default fetchmany() size"""

266

267

@property

268

def itersize(self) -> int:

269

"""Number of rows fetched per network round-trip"""

270

271

@itersize.setter

272

def itersize(self, size: int) -> None:

273

"""Set network fetch batch size"""

274

275

@property

276

def query(self) -> bytes | None:

277

"""Last executed query as bytes"""

278

279

@property

280

def params(self) -> Sequence | None:

281

"""Parameters used in last query"""

282

283

@property

284

def pgresult(self) -> PGresult | None:

285

"""Low-level PostgreSQL result object"""

286

287

@property

288

def connection(self) -> Connection:

289

"""Connection associated with this cursor"""

290

291

@property

292

def row_factory(self) -> RowFactory | None:

293

"""Current row factory for result formatting"""

294

295

@row_factory.setter

296

def row_factory(self, factory: RowFactory | None) -> None:

297

"""Set row factory for result formatting"""

298

```

299

300

### Iterator Interface

301

302

Cursors support Python iterator protocol for convenient row-by-row processing.

303

304

```python { .api }

305

class Cursor:

306

def __iter__(self) -> Iterator:

307

"""Return iterator over query results"""

308

309

def __next__(self) -> Any:

310

"""Get next row (used by iterator protocol)"""

311

312

# Usage example

313

for row in cursor:

314

print(row)

315

```

316

317

### Context Manager Support

318

319

All cursor types support context manager protocol for automatic resource cleanup.

320

321

```python { .api }

322

class Cursor:

323

def __enter__(self) -> Cursor:

324

"""Enter context manager"""

325

326

def __exit__(self, exc_type, exc_val, exc_tb) -> None:

327

"""Exit context manager and close cursor"""

328

329

class AsyncCursor:

330

async def __aenter__(self) -> AsyncCursor:

331

"""Enter async context manager"""

332

333

async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:

334

"""Exit async context manager and close cursor"""

335

```

336

337

### COPY Operations

338

339

Specialized cursor methods for high-performance bulk data operations using PostgreSQL's COPY protocol.

340

341

```python { .api }

342

class Cursor:

343

def copy(

344

self,

345

statement: str,

346

params=None,

347

*,

348

writer: Callable | None = None

349

) -> Copy:

350

"""

351

Start COPY operation for bulk data transfer.

352

353

Args:

354

statement: COPY SQL statement

355

params: Query parameters

356

writer: Custom data writer function

357

358

Returns:

359

Copy context manager

360

"""

361

362

class AsyncCursor:

363

def copy(

364

self,

365

statement: str,

366

params=None,

367

*,

368

writer: Callable | None = None

369

) -> AsyncCopy:

370

"""Async version of copy operation"""

371

```

372

373

### Prepared Statements

374

375

Automatic prepared statement support for improved performance with repeated queries.

376

377

```python { .api }

378

class Connection:

379

def prepare(self, query: str) -> str:

380

"""

381

Prepare a statement for repeated execution.

382

383

Args:

384

query: SQL query to prepare

385

386

Returns:

387

Prepared statement name

388

"""

389

390

def prepared(self) -> dict[str, str]:

391

"""Get mapping of prepared statement names to queries"""

392

393

# Prepared statements are used automatically when prepare=True

394

cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,), prepare=True)

395

```

396

397

## Column Metadata

398

399

```python { .api }

400

class Column:

401

@property

402

def name(self) -> str:

403

"""Column name"""

404

405

@property

406

def type_code(self) -> int:

407

"""PostgreSQL type OID"""

408

409

@property

410

def display_size(self) -> int | None:

411

"""Display size for column"""

412

413

@property

414

def internal_size(self) -> int | None:

415

"""Internal storage size"""

416

417

@property

418

def precision(self) -> int | None:

419

"""Numeric precision"""

420

421

@property

422

def scale(self) -> int | None:

423

"""Numeric scale"""

424

425

@property

426

def null_ok(self) -> bool | None:

427

"""True if column allows NULL values"""

428

```

429

430

## Usage Examples

431

432

### Basic Query Execution

433

434

```python

435

# Simple query

436

with conn.cursor() as cur:

437

cur.execute("SELECT version()")

438

result = cur.fetchone()

439

print(result)

440

441

# Parameterized query

442

with conn.cursor() as cur:

443

cur.execute("SELECT * FROM users WHERE age > %s", (25,))

444

users = cur.fetchall()

445

for user in users:

446

print(user)

447

```

448

449

### Large Result Set Processing

450

451

```python

452

# Server-side cursor for large results

453

with conn.cursor(name="large_query") as cur:

454

cur.execute("SELECT * FROM huge_table")

455

while True:

456

rows = cur.fetchmany(1000) # Fetch in batches

457

if not rows:

458

break

459

process_batch(rows)

460

```

461

462

### Bulk Operations

463

464

```python

465

# Bulk insert

466

data = [("Alice", 30), ("Bob", 25), ("Charlie", 35)]

467

with conn.cursor() as cur:

468

cur.executemany(

469

"INSERT INTO users (name, age) VALUES (%s, %s)",

470

data

471

)

472

```

473

474

### Async Operations

475

476

```python

477

# Async query execution

478

async with conn.cursor() as cur:

479

await cur.execute("SELECT * FROM users")

480

async for row in cur:

481

print(row)

482

```