PostgreSQL Source Code: src/backend/rewrite/rewriteDefine.c Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

16

38

39

41 bool isSelect, bool requireColumnNameMatch);

44

45

46

47

48

49

50

53 int evtype,

54 Oid eventrel_oid,

55 bool evinstead,

56 Node *event_qual,

58 bool replace)

59{

63 bool nulls[Natts_pg_rewrite] = {0};

67 oldtup;

68 Oid rewriteObjectId;

70 referenced;

71 bool is_update = false;

72

73

74

75

84

85

86

87

89

90

91

92

96

98 {

99 bool replaces[Natts_pg_rewrite] = {0};

100

101 if (!replace)

104 errmsg("rule \"%s\" for relation \"%s\" already exists",

106

107

108

109

110 replaces[Anum_pg_rewrite_ev_type - 1] = true;

111 replaces[Anum_pg_rewrite_is_instead - 1] = true;

112 replaces[Anum_pg_rewrite_ev_qual - 1] = true;

113 replaces[Anum_pg_rewrite_ev_action - 1] = true;

114

116 values, nulls, replaces);

117

119

121

123 is_update = true;

124 }

125 else

126 {

128 RewriteOidIndexId,

129 Anum_pg_rewrite_oid);

131

133

135 }

136

137

139

140

141 if (is_update)

143

144

145

146

147

148

149

150 myself.classId = RewriteRelationId;

151 myself.objectId = rewriteObjectId;

153

154 referenced.classId = RelationRelationId;

155 referenced.objectId = eventrel_oid;

157

160

161

162

163

166

167 if (event_qual != NULL)

168 {

169

171

175 }

176

177

179

181

182 return rewriteObjectId;

183}

184

185

186

187

188

191{

192 List *actions;

193 Node *whereClause;

194 Oid relId;

195

196

198

199

200

201

202

204

205

207 relId,

208 whereClause,

210 stmt->instead,

211 stmt->replace,

212 actions);

213}

214

215

216

217

218

219

220

221

222

225 Oid event_relid,

226 Node *event_qual,

228 bool is_instead,

229 bool replace,

231{

237

238

239

240

241

242

243

244

245

246

247

249

250

251

252

253

254

255 if (event_relation->rd_rel->relkind != RELKIND_RELATION &&

256 event_relation->rd_rel->relkind != RELKIND_MATVIEW &&

257 event_relation->rd_rel->relkind != RELKIND_VIEW &&

258 event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)

260 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

261 errmsg("relation \"%s\" cannot have rules",

264

267 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),

268 errmsg("permission denied: \"%s\" is a system catalog",

270

271

272

273

277

278

279

280

282 {

284 if (query->resultRelation == 0)

285 continue;

286

288 continue;

291 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

292 errmsg("rule actions on OLD are not implemented"),

293 errhint("Use views or triggers instead.")));

296 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

297 errmsg("rule actions on NEW are not implemented"),

298 errhint("Use triggers instead.")));

299 }

300

302 {

303

304

305

306

307

308 if (event_relation->rd_rel->relkind != RELKIND_VIEW &&

309 event_relation->rd_rel->relkind != RELKIND_MATVIEW)

311 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

312 errmsg("relation \"%s\" cannot have ON SELECT rules",

315

316

317

318

321 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

322 errmsg("INSTEAD NOTHING rules on SELECT are not implemented"),

323 errhint("Use views instead.")));

324

325

326

327

330 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

331 errmsg("multiple actions for rules on SELECT are not implemented")));

332

333

334

335

337 if (!is_instead ||

340 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

341 errmsg("rules on SELECT must have action INSTEAD SELECT")));

342

343

344

345

346 if (query->hasModifyingCTE)

348 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

349 errmsg("rules on SELECT must not contain data-modifying statements in WITH")));

350

351

352

353

354 if (event_qual != NULL)

356 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

357 errmsg("event qualifications are not implemented for rules on SELECT")));

358

359

360

361

362

365 true,

366 event_relation->rd_rel->relkind !=

367 RELKIND_MATVIEW);

368

369

370

371

372 if (!replace && event_relation->rd_rules != NULL)

373 {

374 int i;

375

377 {

379

383 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

384 errmsg("\"%s\" is already a view",

386 }

387 }

388

389

390

391

393 {

394

395

396

397

398

399

400

401

402

403 if (strncmp(rulename, "_RET", 4) != 0 ||

407 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

408 errmsg("view rule for \"%s\" must be named \"%s\"",

412 }

413 }

414 else

415 {

416

417

418

419

420

421

422

423

424 bool haveReturning = false;

425

427 {

429

431 continue;

432 if (haveReturning)

434 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

435 errmsg("cannot have multiple RETURNING lists in a rule")));

436 haveReturning = true;

437 if (event_qual != NULL)

439 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

440 errmsg("RETURNING lists are not supported in conditional rules")));

441 if (!is_instead)

443 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

444 errmsg("RETURNING lists are not supported in non-INSTEAD rules")));

447 false, false);

448 }

449

450

451

452

453

454

457 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

458 errmsg("non-view rule for \"%s\" must not be named \"%s\"",

461 }

462

463

464

465

466

467

469 {

471 event_type,

472 event_relid,

473 is_instead,

474 event_qual,

476 replace);

477

478

479

480

481

482

483

484

486 }

487

489

490

492

493 return address;

494}

495

496

497

498

499

500

501

502

503

504

505static void

507 bool requireColumnNameMatch)

508{

510 int i;

511

512

513 Assert(isSelect || !requireColumnNameMatch);

514

515 i = 0;

516 foreach(tllist, targetList)

517 {

519 Oid tletypid;

523

524

525 if (tle->resjunk)

526 continue;

527 i++;

528 if (i > resultDesc->natts)

530 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

531 isSelect ?

532 errmsg("SELECT rule's target list has too many entries") :

533 errmsg("RETURNING list has too many entries")));

534

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556 if (attr->attisdropped)

558 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

559 isSelect ?

560 errmsg("cannot convert relation containing dropped columns to view") :

561 errmsg("cannot create a RETURNING list for a relation containing dropped columns")));

562

563

564 if (requireColumnNameMatch && strcmp(tle->resname, attname) != 0)

566 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

567 errmsg("SELECT rule's target entry %d has different column name from column \"%s\"",

569 errdetail("SELECT target entry is named \"%s\".",

570 tle->resname)));

571

572

574 if (attr->atttypid != tletypid)

576 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

577 isSelect ?

578 errmsg("SELECT rule's target entry %d has different type from column \"%s\"",

580 errmsg("RETURNING list's entry %d has different type from column \"%s\"",

582 isSelect ?

583 errdetail("SELECT target entry has type %s, but column has type %s.",

586 errdetail("RETURNING list entry has type %s, but column has type %s.",

589

590

591

592

593

594

595

597 if (attr->atttypmod != tletypmod &&

598 attr->atttypmod != -1 && tletypmod != -1)

600 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

601 isSelect ?

602 errmsg("SELECT rule's target entry %d has different size from column \"%s\"",

604 errmsg("RETURNING list's entry %d has different size from column \"%s\"",

606 isSelect ?

607 errdetail("SELECT target entry has type %s, but column has type %s.",

610 attr->atttypmod)) :

611 errdetail("RETURNING list entry has type %s, but column has type %s.",

614 attr->atttypmod))));

615 }

616

617 if (i != resultDesc->natts)

619 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

620 isSelect ?

621 errmsg("SELECT rule's target list has too few entries") :

622 errmsg("RETURNING list has too few entries")));

623}

624

625

626

627

628

629

630void

632{

634}

635

636static bool

638{

639 if (node == NULL)

640 return false;

642 {

644 return false;

645 }

647 context);

648}

649

650static void

652{

654

655

656 foreach(l, qry->rteperminfos)

657 {

659

661 }

662

663

664 foreach(l, qry->rtable)

665 {

667

670 }

671

672

674 {

676

678 }

679

680

681 if (qry->hasSubLinks)

684}

685

686

687

688

689

690void

692 char fires_when)

693{

696 Oid eventRelationOid;

699 bool changed = false;

700

701

702

703

710 (errcode(ERRCODE_UNDEFINED_OBJECT),

711 errmsg("rule \"%s\" for relation \"%s\" does not exist",

713

715

716

717

718

719 eventRelationOid = ruleform->ev_class;

720 Assert(eventRelationOid == owningRel);

724

725

726

727

729 fires_when)

730 {

731 ruleform->ev_enabled = CharGetDatum(fires_when);

733

734 changed = true;

735 }

736

738

741

742

743

744

745

746

747 if (changed)

749}

750

751

752

753

754

755static void

757 void *arg)

758{

761

764 return;

766

767

768 if (form->relkind != RELKIND_RELATION &&

769 form->relkind != RELKIND_VIEW &&

770 form->relkind != RELKIND_PARTITIONED_TABLE)

772 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

773 errmsg("relation \"%s\" cannot have rules", rv->relname),

775

778 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),

779 errmsg("permission denied: \"%s\" is a system catalog",

781

782

785

787}

788

789

790

791

794 const char *newName)

795{

796 Oid relid;

801 Oid ruleOid;

803

804

805

806

807

809 0,

811 NULL);

812

813

815

816

818

819

825 (errcode(ERRCODE_UNDEFINED_OBJECT),

826 errmsg("rule \"%s\" for relation \"%s\" does not exist",

829 ruleOid = ruleform->oid;

830

831

835 errmsg("rule \"%s\" for relation \"%s\" already exists",

837

838

839

840

841

842 if (ruleform->ev_type == CMD_SELECT + '0')

844 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),

845 errmsg("renaming an ON SELECT rule is not allowed")));

846

847

848 namestrcpy(&(ruleform->rulename), newName);

849

851

853

856

857

858

859

860

861

863

865

866

867

868

870

871 return address;

872}

void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)

bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)

static Datum values[MAXATTR]

#define CStringGetTextDatum(s)

bool IsSystemRelation(Relation relation)

Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)

bool IsSystemClass(Oid relid, Form_pg_class reltuple)

void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)

int errdetail(const char *fmt,...)

int errhint(const char *fmt,...)

int errcode(int sqlerrcode)

int errmsg(const char *fmt,...)

#define ereport(elevel,...)

char * format_type_with_typemod(Oid type_oid, int32 typemod)

char * format_type_be(Oid type_oid)

bool allowSystemTableMods

Assert(PointerIsAligned(start, uint64))

HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)

HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)

void heap_freetuple(HeapTuple htup)

#define HeapTupleIsValid(tuple)

static void * GETSTRUCT(const HeapTupleData *tuple)

void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)

void CatalogTupleInsert(Relation heapRel, HeapTuple tup)

void CacheInvalidateRelcache(Relation relation)

#define AccessExclusiveLock

char * get_rel_name(Oid relid)

char get_rel_relkind(Oid relid)

char * pstrdup(const char *in)

void namestrcpy(Name name, const char *str)

Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)

#define RangeVarGetRelid(relation, lockmode, missing_ok)

Oid exprType(const Node *expr)

int32 exprTypmod(const Node *expr)

#define query_tree_walker(q, w, c, f)

#define expression_tree_walker(n, w, c)

#define QTW_IGNORE_RC_SUBQUERIES

#define IsA(nodeptr, _type_)

#define castNode(_type_, nodeptr)

#define InvokeObjectPostCreateHook(classId, objectId, subId)

#define InvokeObjectPostAlterHook(classId, objectId, subId)

ObjectType get_relkind_objtype(char relkind)

#define ObjectAddressSet(addr, class_id, object_id)

char * nodeToString(const void *obj)

void transformRuleStmt(RuleStmt *stmt, const char *queryString, List **actions, Node **whereClause)

FormData_pg_attribute * Form_pg_attribute

int errdetail_relkind_not_supported(char relkind)

FormData_pg_class * Form_pg_class

void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)

long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)

#define lfirst_node(type, lc)

static int list_length(const List *l)

#define linitial_node(type, l)

FormData_pg_rewrite * Form_pg_rewrite

static Datum PointerGetDatum(const void *X)

static Datum BoolGetDatum(bool X)

static Datum ObjectIdGetDatum(Oid X)

static Datum NameGetDatum(const NameData *X)

static char DatumGetChar(Datum X)

static Datum CharGetDatum(char X)

#define RelationGetRelid(relation)

#define RelationGetDescr(relation)

#define RelationGetRelationName(relation)

static Oid InsertRule(const char *rulname, int evtype, Oid eventrel_oid, bool evinstead, Node *event_qual, List *action, bool replace)

void setRuleCheckAsUser(Node *node, Oid userid)

static bool setRuleCheckAsUser_walker(Node *node, Oid *context)

ObjectAddress DefineRule(RuleStmt *stmt, const char *queryString)

static void RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)

static void checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect, bool requireColumnNameMatch)

static void setRuleCheckAsUser_Query(Query *qry, Oid userid)

ObjectAddress DefineQueryRewrite(const char *rulename, Oid event_relid, Node *event_qual, CmdType event_type, bool is_instead, bool replace, List *action)

void EnableDisableRule(Relation rel, const char *rulename, char fires_when)

ObjectAddress RenameRewriteRule(RangeVar *relation, const char *oldName, const char *newName)

#define RULE_FIRES_ON_ORIGIN

Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)

void SetRelationRuleStatus(Oid relationId, bool relHasRules)

bool IsDefinedRewriteRule(Oid owningRel, const char *ruleName)

#define ViewSelectRuleName

void relation_close(Relation relation, LOCKMODE lockmode)

Relation relation_open(Oid relationId, LOCKMODE lockmode)

#define ERRCODE_DUPLICATE_OBJECT

void ReleaseSysCache(HeapTuple tuple)

HeapTuple SearchSysCache1(int cacheId, Datum key1)

HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)

#define SearchSysCacheCopy2(cacheId, key1, key2)

void table_close(Relation relation, LOCKMODE lockmode)

Relation table_open(Oid relationId, LOCKMODE lockmode)

static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)