diff -u src/pl_comp.c src.mk/pl_comp.c --- src/pl_comp.c 2004-09-13 21:09:20.000000000 +0100 +++ src.mk/pl_comp.c 2004-11-18 12:59:25.825372489 +0000 @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.82 2004/09/13 20:09:20 tgl Exp $ + * $PostgreSQL: pgsql-server/src/pl/plpgsql/src/pl_comp.c,v 1.82 2004/09/13 20:09:20 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -783,6 +783,75 @@ return T_WORD; } +/* ---------- + * plpgsql_parse_wordexpr Same lookup for word followed by dot. + * Should only get here if it wasn't followed by + * an identifier. + * ---------- + */ +int +plpgsql_parse_wordexpr(char *word) +{ + PLpgSQL_nsitem *ns; + char *cp[1]; + int save_spacescanned = plpgsql_SpaceScanned; + + /* Do case conversion and word separation */ + /* add fake bit after dot to keep converter happy */ + word[strlen(word) - 1] = '\0'; + plpgsql_convert_ident(word, cp, 1); + + /* Make sure we've got an open parenthesis */ + + /* + * Do a lookup on the compilers namestack + */ + ns = plpgsql_ns_lookup(cp[0], NULL); + if (ns == NULL) + { + pfree(cp[0]); + return T_ERROR; + } + switch (ns->itemtype) + { + case PLPGSQL_NSTYPE_REC: + { + /* + * First word is a record name, so expression refers to + * field in this record. + */ + PLpgSQL_recfield *new; + + new = malloc(sizeof(PLpgSQL_recfield)); + memset(new, 0, sizeof(PLpgSQL_recfield)); + + if (plpgsql_yylex() != '(') + plpgsql_yyerror("expected identifier or \"(\""); + new->expr = plpgsql_read_expression(')', ")"); + new->recparentno = ns->itemno; + /* just to be sure - we'll test on this later */ + new->fieldname = '\0'; + new->dtype = PLPGSQL_DTYPE_RECFIELD; + + plpgsql_adddatum((PLpgSQL_datum *) new); + + plpgsql_yylval.scalar = (PLpgSQL_datum *) new; + + plpgsql_SpaceScanned = save_spacescanned; + + pfree(cp[0]); + return T_SCALAR; + } + + /* TODO: deal with rows, too */ + + default: + break; + + } + pfree(cp[0]); + return T_ERROR; +} /* ---------- * plpgsql_parse_dblword Same lookup for two words diff -u src/pl_exec.c src.mk/pl_exec.c --- src/pl_exec.c 2004-09-16 17:58:44.000000000 +0100 +++ src.mk/pl_exec.c 2004-11-18 12:59:25.825372489 +0000 @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.120 2004/09/16 16:58:44 tgl Exp $ + * $PostgreSQL: pgsql-server/src/pl/plpgsql/src/pl_exec.c,v 1.120 2004/09/16 16:58:44 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -2965,7 +2965,8 @@ PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target; PLpgSQL_rec *rec; int fno; - HeapTuple newtup; + char *fname; + HeapTuple newtup; int natts; int i; Datum *values; @@ -2988,20 +2989,48 @@ errmsg("record \"%s\" is not assigned yet", rec->refname), errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); - - /* + + /* Have we got an expr to deal with? */ + fno = 0; + if (recfield->fieldname == '\0') + { + Datum exprdatum; + Oid exprtype; + bool *isNull = false; + + /* Evaluate expression */ + exprdatum = exec_eval_expr(estate, recfield->expr, + isNull, &exprtype); + + /* Get C-String representation */ + fname = convert_value_to_string( + exprdatum, exprtype); + /* cols must be one-based... not ideal */ + fno = atoi(fname); + + /* do we need to free datum? */ + } + else { + fname = recfield->fieldname; + } + + /* * Get the number of the records field to change and the * number of attributes in the tuple. */ - fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); - if (fno == SPI_ERROR_NOATTRIBUTE) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("record \"%s\" has no field \"%s\"", - rec->refname, recfield->fieldname))); - fno--; - natts = rec->tupdesc->natts; - + if (fno < 1) + { + fno = SPI_fnumber(rec->tupdesc, fname); + if (fno == SPI_ERROR_NOATTRIBUTE) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("record \"%s\" has no field \"%s\"", + rec->refname, fname))); + } + fno--; + natts = rec->tupdesc->natts; + + /* * Set up values/datums arrays for heap_formtuple. For * all the attributes except the one we want to replace, @@ -3297,7 +3326,8 @@ PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum; PLpgSQL_rec *rec; int fno; - + char *fname; + rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]); if (!HeapTupleIsValid(rec->tup)) ereport(ERROR, @@ -3305,19 +3335,59 @@ errmsg("record \"%s\" is not assigned yet", rec->refname), errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); - fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); - if (fno == SPI_ERROR_NOATTRIBUTE) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("record \"%s\" has no field \"%s\"", - rec->refname, recfield->fieldname))); - *typeid = SPI_gettypeid(rec->tupdesc, fno); + + /* Have we got an expr to deal with? */ + fno = 0; + if (recfield->fieldname == '\0') + { + Datum exprdatum; + Oid exprtype; + + /* Evaluate expression */ + exprdatum = exec_eval_expr(estate, recfield->expr, + isnull, &exprtype); + + + /* Get C-String representation */ + fname = convert_value_to_string( + exprdatum, exprtype); + + /* How do we test to see if it's an integer for fno? + this isn't working... */ + fno = atoi(fname); + + } + else { + fname = recfield->fieldname; + } + + /* + * Get the number of the records field to change and the + * number of attributes in the tuple. + */ + if (fno < 1) + { + fno = SPI_fnumber(rec->tupdesc, fname); + if (fno == SPI_ERROR_NOATTRIBUTE) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("record \"%s\" has no field \"%s\"", + rec->refname, fname))); + } + + *typeid = SPI_gettypeid(rec->tupdesc, fno); *value = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull); - if (expectedtypeid != InvalidOid && expectedtypeid != *typeid) + if (*value == SPI_ERROR_NOATTRIBUTE) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("record \"%s\" has no field number \"%d\"", + rec->refname, &fno))); + + if (expectedtypeid != InvalidOid && expectedtypeid != *typeid) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("type of \"%s.%s\" does not match that when preparing the plan", - rec->refname, recfield->fieldname))); + rec->refname, fname))); break; } Only in src.mk: .plpgsql.h.swp diff -u src/scan.l src.mk/scan.l --- src/scan.l 2004-09-13 02:45:32.000000000 +0100 +++ src.mk/scan.l 2004-11-18 12:59:25.825372489 +0000 @@ -4,7 +4,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.37 2004/09/13 01:45:32 neilc Exp $ + * $PostgreSQL: pgsql-server/src/pl/plpgsql/src/scan.l,v 1.37 2004/09/13 01:45:32 neilc Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -195,6 +195,9 @@ {identifier} { plpgsql_error_lineno = plpgsql_scanner_lineno(); return plpgsql_parse_word(yytext); } +{identifier}{space}*\. { + plpgsql_error_lineno = plpgsql_scanner_lineno(); + return plpgsql_parse_wordexpr(yytext); } {identifier}{space}*\.{space}*{identifier} { plpgsql_error_lineno = plpgsql_scanner_lineno(); return plpgsql_parse_dblword(yytext); }