or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdconnection-pooling.mdconnections-cursors.mdcursors-rows.mderror-handling.mdindex.mdsql-composition.mdtypes-adaptation.md

cursors-rows.mddocs/

0

# Enhanced Cursors and Row Access

1

2

Specialized cursor implementations providing dictionary-like row access, named tuple rows, real dictionary rows, and logging capabilities. These cursors extend the basic cursor functionality with convenient row access patterns for improved development experience.

3

4

## Capabilities

5

6

### Dictionary Cursors

7

8

Cursors that return rows as dictionary-like objects allowing access to columns by name instead of index position.

9

10

```python { .api }

11

class DictCursorBase(cursor):

12

"""Base class for dictionary-like cursors."""

13

14

def __init__(self, *args, **kwargs):

15

"""Initialize dict cursor base."""

16

17

class DictCursor(DictCursorBase):

18

"""Cursor returning DictRow objects."""

19

20

def __init__(self, *args, **kwargs):

21

"""Initialize dictionary cursor."""

22

23

def fetchone(self):

24

"""

25

Fetch next row as DictRow.

26

27

Returns:

28

DictRow/None: Dictionary-like row object

29

"""

30

31

def fetchmany(self, size=None):

32

"""

33

Fetch multiple rows as DictRow objects.

34

35

Returns:

36

list: List of DictRow objects

37

"""

38

39

def fetchall(self):

40

"""

41

Fetch all rows as DictRow objects.

42

43

Returns:

44

list: List of DictRow objects

45

"""

46

47

class DictConnection(connection):

48

"""Connection using DictCursor by default."""

49

50

def cursor(self, *args, **kwargs):

51

"""Create DictCursor by default."""

52

53

class DictRow(list):

54

"""Dictionary-like row object."""

55

56

def __init__(self, cursor):

57

"""Initialize from cursor description."""

58

59

def __getitem__(self, x):

60

"""

61

Get item by index or column name.

62

63

Parameters:

64

- x (int/str): Column index or name

65

66

Returns:

67

Value at column

68

"""

69

70

def __setitem__(self, x, v):

71

"""

72

Set item by index or column name.

73

74

Parameters:

75

- x (int/str): Column index or name

76

- v: Value to set

77

"""

78

79

def keys(self):

80

"""

81

Get column names.

82

83

Returns:

84

iterator: Column names

85

"""

86

87

def values(self):

88

"""

89

Get column values.

90

91

Returns:

92

iterator: Column values

93

"""

94

95

def items(self):

96

"""

97

Get (name, value) pairs.

98

99

Returns:

100

iterator: (column_name, value) tuples

101

"""

102

103

def get(self, x, default=None):

104

"""

105

Get value with default.

106

107

Parameters:

108

- x (str): Column name

109

- default: Default value if column not found

110

111

Returns:

112

Column value or default

113

"""

114

115

def copy(self):

116

"""

117

Create OrderedDict copy of row.

118

119

Returns:

120

OrderedDict: Copy of row data

121

"""

122

123

def __contains__(self, x):

124

"""

125

Check if column exists.

126

127

Parameters:

128

- x (str): Column name

129

130

Returns:

131

bool: True if column exists

132

"""

133

```

134

135

Usage examples:

136

137

```python

138

from psycopg2.extras import DictCursor, DictConnection

139

140

# Using DictCursor with existing connection

141

cur = conn.cursor(cursor_factory=DictCursor)

142

cur.execute("SELECT id, name, email FROM users WHERE id = %s", (1,))

143

user = cur.fetchone()

144

145

print(user['name']) # Access by column name

146

print(user[1]) # Access by index still works

147

print(user.get('age', 'Unknown')) # Safe access with default

148

149

# Iterate over columns

150

for key, value in user.items():

151

print(f"{key}: {value}")

152

153

# Using DictConnection (DictCursor by default)

154

dict_conn = psycopg2.connect(..., connection_factory=DictConnection)

155

cur = dict_conn.cursor() # Automatically a DictCursor

156

cur.execute("SELECT * FROM products")

157

for row in cur:

158

print(f"Product: {row['name']}, Price: {row['price']}")

159

```

160

161

### Real Dictionary Cursors

162

163

Cursors that return actual Python dictionary objects instead of DictRow objects.

164

165

```python { .api }

166

class RealDictCursor(DictCursorBase):

167

"""Cursor returning real dict objects."""

168

169

def __init__(self, *args, **kwargs):

170

"""Initialize real dictionary cursor."""

171

172

class RealDictConnection(connection):

173

"""Connection using RealDictCursor by default."""

174

175

def cursor(self, *args, **kwargs):

176

"""Create RealDictCursor by default."""

177

178

class RealDictRow(dict):

179

"""Real dictionary row object."""

180

181

def __init__(self, cursor):

182

"""Initialize from cursor description."""

183

```

184

185

Usage examples:

186

187

```python

188

from psycopg2.extras import RealDictCursor

189

190

cur = conn.cursor(cursor_factory=RealDictCursor)

191

cur.execute("SELECT id, name, email FROM users")

192

users = cur.fetchall()

193

194

# Each row is a real Python dict

195

for user in users:

196

print(user) # {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'}

197

user['processed'] = True # Can modify like normal dict

198

199

# Useful for JSON serialization

200

import json

201

json_users = json.dumps(users) # Direct serialization

202

```

203

204

### Named Tuple Cursors

205

206

Cursors that return rows as named tuples with column names as attributes.

207

208

```python { .api }

209

class NamedTupleCursor(cursor):

210

"""Cursor returning named tuple objects."""

211

212

def __init__(self, *args, **kwargs):

213

"""Initialize named tuple cursor."""

214

215

class NamedTupleConnection(connection):

216

"""Connection using NamedTupleCursor by default."""

217

218

def cursor(self, *args, **kwargs):

219

"""Create NamedTupleCursor by default."""

220

```

221

222

Usage examples:

223

224

```python

225

from psycopg2.extras import NamedTupleCursor

226

227

cur = conn.cursor(cursor_factory=NamedTupleCursor)

228

cur.execute("SELECT id, name, email FROM users WHERE id = %s", (1,))

229

user = cur.fetchone()

230

231

# Access as attributes

232

print(user.name) # Access by attribute name

233

print(user.email) # Clean, readable access

234

print(user[0]) # Index access still works

235

236

# Named tuples are immutable and hashable

237

user_set = {user} # Can be added to sets

238

# user.name = 'Bob' # Would raise AttributeError

239

240

# Good for type hints and IDE support

241

def process_user(user_row):

242

return f"Processing {user_row.name} ({user_row.email})"

243

```

244

245

### Logging Cursors

246

247

Cursors that log SQL statements and execution times for debugging and monitoring.

248

249

```python { .api }

250

class LoggingConnection(connection):

251

"""Connection with logging capabilities."""

252

253

def __init__(self, *args, **kwargs):

254

"""Initialize logging connection."""

255

256

def cursor(self, *args, **kwargs):

257

"""Create LoggingCursor."""

258

259

class LoggingCursor(cursor):

260

"""Cursor that logs SQL statements."""

261

262

def __init__(self, *args, **kwargs):

263

"""Initialize logging cursor."""

264

265

def execute(self, query, vars=None):

266

"""Execute with logging."""

267

268

def executemany(self, query, vars_list):

269

"""Execute many with logging."""

270

271

class MinTimeLoggingConnection(LoggingConnection):

272

"""Connection with minimum time logging."""

273

274

def __init__(self, *args, **kwargs):

275

"""

276

Initialize with minimum logging time.

277

278

Parameters:

279

- mintime (float): Minimum execution time to log (seconds)

280

"""

281

282

class MinTimeLoggingCursor(LoggingCursor):

283

"""Cursor logging only slow queries."""

284

285

def __init__(self, *args, **kwargs):

286

"""Initialize minimum time logging cursor."""

287

```

288

289

Usage examples:

290

291

```python

292

import logging

293

from psycopg2.extras import LoggingConnection, MinTimeLoggingConnection

294

295

# Setup logging

296

logging.basicConfig(level=logging.DEBUG)

297

298

# Log all queries

299

log_conn = psycopg2.connect(..., connection_factory=LoggingConnection)

300

cur = log_conn.cursor()

301

cur.execute("SELECT * FROM users") # Will be logged

302

303

# Log only slow queries (>0.5 seconds)

304

slow_conn = psycopg2.connect(...,

305

connection_factory=MinTimeLoggingConnection,

306

mintime=0.5

307

)

308

cur = slow_conn.cursor()

309

cur.execute("SELECT * FROM large_table") # Only logged if slow

310

```

311

312

### Cursor Context Managers

313

314

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

315

316

```python

317

# Automatic cursor cleanup

318

with conn.cursor(cursor_factory=DictCursor) as cur:

319

cur.execute("SELECT * FROM users")

320

users = cur.fetchall()

321

# Cursor automatically closed

322

323

# Named cursor with context manager

324

with conn.cursor('server_cursor') as cur:

325

cur.execute("SELECT * FROM large_table")

326

for row in cur:

327

process_row(row)

328

# Server cursor automatically closed

329

```

330

331

### Bulk Operations with Enhanced Cursors

332

333

Enhanced cursors work seamlessly with bulk operations for improved performance.

334

335

```python

336

from psycopg2.extras import execute_batch, execute_values, RealDictCursor

337

338

# Bulk insert with real dict cursor (for result processing)

339

cur = conn.cursor(cursor_factory=RealDictCursor)

340

data = [

341

{'name': 'Alice', 'email': 'alice@example.com'},

342

{'name': 'Bob', 'email': 'bob@example.com'}

343

]

344

345

# Convert dicts to tuples for bulk insert

346

tuples = [(d['name'], d['email']) for d in data]

347

execute_batch(cur,

348

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

349

tuples

350

)

351

352

# Bulk select with dict cursor

353

cur.execute("SELECT * FROM users WHERE created_date = CURRENT_DATE")

354

new_users = cur.fetchall() # List of dicts

355

356

# Process results easily

357

for user in new_users:

358

send_welcome_email(user['email'])

359

```

360

361

### Bulk Operations

362

363

Efficient bulk execution functions for improved performance with large data sets.

364

365

```python { .api }

366

def execute_batch(cur, sql, argslist, page_size=100):

367

"""

368

Execute statement in batches.

369

370

Parameters:

371

- cur (cursor): Database cursor

372

- sql (str): SQL statement with placeholders

373

- argslist (sequence): Sequence of parameter tuples

374

- page_size (int): Number of statements per batch

375

"""

376

377

def execute_values(cur, sql, argslist, template=None, page_size=100, fetch=False):

378

"""

379

Execute statement using VALUES syntax.

380

381

Parameters:

382

- cur (cursor): Database cursor

383

- sql (str): SQL statement with VALUES placeholder

384

- argslist (sequence): Sequence of parameter tuples

385

- template (str, optional): VALUES template

386

- page_size (int): Number of tuples per page

387

- fetch (bool): Return results if True

388

389

Returns:

390

list/None: Query results if fetch=True

391

"""

392

```

393

394

## Types

395

396

### Row Factory Functions

397

398

```python { .api }

399

def DictRowFactory(cursor):

400

"""Factory function for DictRow objects."""

401

402

def RealDictRowFactory(cursor):

403

"""Factory function for real dict objects."""

404

405

def NamedTupleRowFactory(cursor):

406

"""Factory function for named tuple objects."""

407

```

408

409

### Cursor Factory Types

410

411

```python { .api }

412

CursorFactory = callable[[connection], cursor]

413

RowFactory = callable[[cursor], Any]

414

```

415

416

### Connection Factory Examples

417

418

```python

419

# Custom connection with default cursor factory

420

class MyConnection(psycopg2.extensions.connection):

421

def cursor(self, *args, **kwargs):

422

kwargs.setdefault('cursor_factory', DictCursor)

423

return super().cursor(*args, **kwargs)

424

425

# Use custom connection

426

conn = psycopg2.connect(..., connection_factory=MyConnection)

427

cur = conn.cursor() # Automatically a DictCursor

428

```