or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-cursors.mdbatch-operations.mdconnection-pooling.mdconnections-cursors.mderror-handling.mdindex.mdreplication.mdsql-composition.mdtimezone-support.mdtype-adaptation.md

advanced-cursors.mddocs/

0

# Advanced Cursor Types

1

2

Specialized cursor classes that enhance the standard cursor functionality by returning results as dictionaries, named tuples, or providing logging capabilities for development and debugging purposes.

3

4

## Capabilities

5

6

### Dictionary Cursors

7

8

Cursors that return rows as dictionary-like or real dictionary objects, providing attribute and key-based access to column values.

9

10

```python { .api }

11

class DictConnection(connection):

12

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

13

14

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

15

"""Create DictCursor."""

16

17

class DictCursor(cursor):

18

"""Cursor returning dict-like rows."""

19

20

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

21

"""Execute query and prepare dict-like results."""

22

23

def callproc(self, procname, vars=None):

24

"""Call stored procedure with dict-like results."""

25

26

def fetchone(self):

27

"""

28

Fetch next row as DictRow.

29

30

Returns:

31

DictRow or None: Dictionary-like row object

32

"""

33

34

def fetchmany(self, size=None):

35

"""

36

Fetch multiple rows as DictRow objects.

37

38

Returns:

39

list[DictRow]: List of dictionary-like row objects

40

"""

41

42

def fetchall(self):

43

"""

44

Fetch all rows as DictRow objects.

45

46

Returns:

47

list[DictRow]: List of dictionary-like row objects

48

"""

49

50

class DictRow(list):

51

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

52

53

def __getitem__(self, x):

54

"""Get item by index or column name."""

55

56

def __setitem__(self, x, v):

57

"""Set item by index or column name."""

58

59

def items(self):

60

"""Return (column_name, value) pairs."""

61

62

def keys(self):

63

"""Return column names."""

64

65

def values(self):

66

"""Return column values."""

67

68

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

69

"""Get column value with default."""

70

71

def copy(self):

72

"""Return OrderedDict copy."""

73

74

class RealDictConnection(connection):

75

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

76

77

class RealDictCursor(cursor):

78

"""Cursor with real dict rows."""

79

80

def fetchone(self):

81

"""

82

Fetch next row as real dictionary.

83

84

Returns:

85

dict or None: Real dictionary row

86

"""

87

88

def fetchmany(self, size=None):

89

"""

90

Fetch multiple rows as real dictionaries.

91

92

Returns:

93

list[dict]: List of dictionary rows

94

"""

95

96

def fetchall(self):

97

"""

98

Fetch all rows as real dictionaries.

99

100

Returns:

101

list[dict]: List of dictionary rows

102

"""

103

104

class RealDictRow(dict):

105

"""Real dictionary row object (OrderedDict)."""

106

```

107

108

**Usage Example:**

109

110

```python

111

import psycopg2

112

from psycopg2.extras import DictCursor, RealDictCursor, DictConnection

113

114

# Using DictCursor

115

conn = psycopg2.connect("host=localhost dbname=mydb user=myuser")

116

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

117

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

118

user = cur.fetchone()

119

120

# Access by column name or index

121

print(f"Name: {user['name']}")

122

print(f"Email: {user[2]}")

123

print(f"Keys: {list(user.keys())}")

124

125

# Using RealDictCursor for real dictionaries

126

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

127

cur.execute("SELECT * FROM users LIMIT 3")

128

users = cur.fetchall()

129

130

for user in users:

131

# Real dictionary access

132

print(f"User: {user}")

133

print(f"Name: {user.get('name', 'Unknown')}")

134

135

# Using DictConnection for default dict cursors

136

dict_conn = psycopg2.connect(

137

"host=localhost dbname=mydb user=myuser",

138

connection_factory=DictConnection

139

)

140

with dict_conn.cursor() as cur:

141

cur.execute("SELECT name, age FROM users")

142

for row in cur:

143

print(f"{row['name']} is {row['age']} years old")

144

145

conn.close()

146

dict_conn.close()

147

```

148

149

### Named Tuple Cursors

150

151

Cursors that return rows as named tuples, providing attribute access to column values with automatic type generation.

152

153

```python { .api }

154

class NamedTupleConnection(connection):

155

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

156

157

class NamedTupleCursor(cursor):

158

"""Cursor returning named tuples."""

159

160

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

161

"""Execute query and prepare named tuple results."""

162

163

def executemany(self, query, vars):

164

"""Execute multiple times with named tuple results."""

165

166

def callproc(self, procname, vars=None):

167

"""Call stored procedure with named tuple results."""

168

169

def fetchone(self):

170

"""

171

Fetch next row as named tuple.

172

173

Returns:

174

namedtuple or None: Named tuple row

175

"""

176

177

def fetchmany(self, size=None):

178

"""

179

Fetch multiple rows as named tuples.

180

181

Returns:

182

list[namedtuple]: List of named tuple rows

183

"""

184

185

def fetchall(self):

186

"""

187

Fetch all rows as named tuples.

188

189

Returns:

190

list[namedtuple]: List of named tuple rows

191

"""

192

193

# Class attributes

194

Record = None # Generated namedtuple class for current query

195

MAX_CACHE = 1024 # Maximum cached namedtuple classes

196

```

197

198

**Usage Example:**

199

200

```python

201

import psycopg2

202

from psycopg2.extras import NamedTupleCursor

203

204

conn = psycopg2.connect("host=localhost dbname=mydb user=myuser")

205

206

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

207

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

208

209

# Access by attribute name

210

for user in cur:

211

print(f"ID: {user.id}")

212

print(f"Name: {user.name}")

213

print(f"Email: {user.email}")

214

print(f"Age: {user.age}")

215

216

# The Record class is auto-generated

217

print(f"Record type: {cur.Record}")

218

print(f"Record fields: {cur.Record._fields}")

219

220

conn.close()

221

```

222

223

### Logging Cursors

224

225

Cursors that log executed queries and their execution time, useful for development, debugging, and performance monitoring.

226

227

```python { .api }

228

class LoggingConnection(connection):

229

"""Connection that logs queries."""

230

231

def initialize(self, logobj):

232

"""

233

Initialize logging with logger or file.

234

235

Parameters:

236

- logobj: Logger object or file-like object

237

"""

238

239

def filter(self, msg, curs):

240

"""

241

Filter log messages.

242

243

Parameters:

244

- msg (str): Log message

245

- curs: Cursor object

246

247

Returns:

248

str: Filtered message

249

"""

250

251

def log(self, msg, curs):

252

"""

253

Log method (set by initialize).

254

255

Parameters:

256

- msg (str): Message to log

257

- curs: Cursor object

258

"""

259

260

class LoggingCursor(cursor):

261

"""Cursor that logs executed queries."""

262

263

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

264

"""Execute and log query."""

265

266

def callproc(self, procname, vars=None):

267

"""Execute procedure and log."""

268

269

class MinTimeLoggingConnection(LoggingConnection):

270

"""Log queries over time threshold."""

271

272

def initialize(self, logobj, mintime=0):

273

"""

274

Initialize with time threshold.

275

276

Parameters:

277

- logobj: Logger object or file-like object

278

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

279

"""

280

281

def filter(self, msg, curs):

282

"""Filter by execution time."""

283

284

class MinTimeLoggingCursor(LoggingCursor):

285

"""Cursor for MinTimeLoggingConnection."""

286

287

@property

288

def timestamp(self):

289

"""Execution timestamp."""

290

```

291

292

**Usage Example:**

293

294

```python

295

import psycopg2

296

import logging

297

from psycopg2.extras import LoggingConnection, MinTimeLoggingConnection

298

299

# Set up logging

300

logging.basicConfig(level=logging.DEBUG)

301

logger = logging.getLogger('psycopg2')

302

303

# Basic query logging

304

conn = psycopg2.connect(

305

"host=localhost dbname=mydb user=myuser",

306

connection_factory=LoggingConnection

307

)

308

conn.initialize(logger)

309

310

with conn.cursor() as cur:

311

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

312

users = cur.fetchall()

313

# Logs: "SELECT * FROM users WHERE age > 25"

314

315

# Log only slow queries (> 0.1 seconds)

316

slow_conn = psycopg2.connect(

317

"host=localhost dbname=mydb user=myuser",

318

connection_factory=MinTimeLoggingConnection

319

)

320

slow_conn.initialize(logger, mintime=0.1)

321

322

with slow_conn.cursor() as cur:

323

cur.execute("SELECT COUNT(*) FROM large_table")

324

# Only logs if query takes > 0.1 seconds

325

326

# Log to file

327

with open('queries.log', 'a') as logfile:

328

file_conn = psycopg2.connect(

329

"host=localhost dbname=mydb user=myuser",

330

connection_factory=LoggingConnection

331

)

332

file_conn.initialize(logfile)

333

334

with file_conn.cursor() as cur:

335

cur.execute("INSERT INTO audit_log (action) VALUES (%s)", ("user_login",))

336

337

file_conn.commit()

338

file_conn.close()

339

340

conn.close()

341

slow_conn.close()

342

```

343

344

### Cursor Factories

345

346

Custom cursor creation and configuration for specialized use cases.

347

348

**Usage Example:**

349

350

```python

351

import psycopg2

352

from psycopg2.extras import DictCursor, LoggingCursor

353

354

# Custom cursor factory

355

def my_cursor_factory(conn):

356

"""Custom cursor combining dict and logging functionality."""

357

class MyCustomCursor(DictCursor, LoggingCursor):

358

pass

359

return MyCustomCursor(conn)

360

361

# Use custom cursor factory

362

conn = psycopg2.connect(

363

"host=localhost dbname=mydb user=myuser",

364

cursor_factory=my_cursor_factory

365

)

366

367

# Set up logging for custom cursor

368

if hasattr(conn, 'initialize'):

369

import logging

370

logger = logging.getLogger('custom')

371

conn.initialize(logger)

372

373

with conn.cursor() as cur:

374

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

375

for row in cur:

376

# Dictionary access + logging

377

print(f"User: {row['name']}")

378

379

conn.close()

380

```

381

382

## Types

383

384

### Dictionary Row Types

385

386

```python { .api }

387

class DictRow(list):

388

"""Dictionary-like row that extends list."""

389

390

def __getitem__(self, x) -> Any:

391

"""Get by index (int) or column name (str)."""

392

393

def __setitem__(self, x, v) -> None:

394

"""Set by index (int) or column name (str)."""

395

396

def items(self) -> list[tuple[str, Any]]:

397

"""Column name, value pairs."""

398

399

def keys(self) -> list[str]:

400

"""Column names."""

401

402

def values(self) -> list[Any]:

403

"""Column values."""

404

405

def get(self, x, default=None) -> Any:

406

"""Get column value with default."""

407

408

class RealDictRow(dict):

409

"""Real dictionary row (OrderedDict)."""

410

```

411

412

### Named Tuple Cursor Attributes

413

414

```python { .api }

415

class NamedTupleCursor:

416

Record: type # Auto-generated namedtuple class

417

MAX_CACHE: int # 1024 - Maximum cached namedtuple classes

418

```

419

420

### Logging Connection Methods

421

422

```python { .api }

423

class LoggingConnection:

424

def initialize(self, logobj) -> None:

425

"""Initialize with logger or file object."""

426

427

def filter(self, msg: str, curs) -> str:

428

"""Filter log messages."""

429

430

def log(self, msg: str, curs) -> None:

431

"""Log method (configured by initialize)."""

432

433

class MinTimeLoggingConnection(LoggingConnection):

434

def initialize(self, logobj, mintime: float = 0) -> None:

435

"""Initialize with time threshold."""

436

```