Does pl/python even have a DECLARE section that can mimick the data type
of an existing table column?

---------------------------------------------------------------------------

Greg Copeland wrote:
-- Start of PGP signed section.
> Does anyone know if such effort is also required to pl/python to become
> "schema aware"?
> 
> Regards,
> 
>       Greg Copeland
> 
> 
> On Wed, 2002-09-11 at 19:24, Bruce Momjian wrote:
> > 
> > Patch applied.  Thanks.
> > 
> > ---------------------------------------------------------------------------
> > 
> > 
> > Joe Conway wrote:
> > > Tom Lane wrote:
> > > > Sean Chittenden <[EMAIL PROTECTED]> writes:
> > > > 
> > > >>::sigh:: Is it me or does it look like all
> > > >>of pl/pgsql is schema un-aware (ie, all of the declarations).  -sc
> > > > 
> > > > 
> > > > Yeah.  The group of routines parse_word, parse_dblword, etc that are
> > > > called by the lexer certainly all need work.  There are some
> > > > definitional issues to think about, too --- plpgsql presently relies on
> > > > the number of names to give it some idea of what to look for, and those
> > > > rules are probably all toast now.  Please come up with a sketch of what
> > > > you think the behavior should be before you start hacking code.
> > > 
> > > Attached is a diff -c format proposal to fix this. I've also attached a short 
> > > test script. Seems to work OK and passes all regression tests.
> > > 
> > > Here's a breakdown of how I understand plpgsql's "Special word rules" -- I 
> > > think it illustrates the behavior reasonably well. New functions added by this 
> > > patch are plpgsql_parse_tripwordtype and plpgsql_parse_dblwordrowtype:
> > > 
> > > ============================================================================
> > > Identifiers             (represents)                        parsing function
> > > ----------------------------------------------------------------------------
> > > identifier                                                plpgsql_parse_word
> > >      tg_argv
> > >      T_LABEL             (label)
> > >      T_VARIABLE          (variable)
> > >      T_RECORD            (record)
> > >      T_ROW               (row)
> > > ----------------------------------------------------------------------------
> > > identifier.identifier                                  plpgsql_parse_dblword
> > >      T_LABEL
> > >          T_VARIABLE      (label.variable)
> > >          T_RECORD        (label.record)
> > >          T_ROW           (label.row)
> > >      T_RECORD
> > >          T_VARIABLE      (record.variable)
> > >      T_ROW
> > >          T_VARIABLE      (row.variable)
> > > ----------------------------------------------------------------------------
> > > identifier.identifier.identifier                      plpgsql_parse_tripword
> > >      T_LABEL
> > >          T_RECORD
> > >              T_VARIABLE  (label.record.variable)
> > >          T_ROW
> > >              T_VARIABLE  (label.row.variable)
> > > ----------------------------------------------------------------------------
> > > identifier%TYPE                                       plpgsql_parse_wordtype
> > >      T_VARIABLE
> > >          T_DTYPE         (variable%TYPE)
> > >      T_DTYPE             (typname%TYPE)
> > > ----------------------------------------------------------------------------
> > > identifier.identifier%TYPE                         plpgsql_parse_dblwordtype
> > >      T_LABEL
> > >          T_VARIABLE
> > >              T_DTYPE     (label.variable%TYPE)
> > >      T_DTYPE             (relname.attname%TYPE)
> > > ----------------------------------------------------------------------------
> > > <new>
> > > identifier.identifier.identifier%TYPE             plpgsql_parse_tripwordtype
> > >      T_DTYPE             (nspname.relname.attname%TYPE)
> > > ----------------------------------------------------------------------------
> > > identifier%ROWTYPE                                 plpgsql_parse_wordrowtype
> > >      T_DTYPE             (relname%ROWTYPE)
> > > ----------------------------------------------------------------------------
> > > <new>
> > > identifier.identifier%ROWTYPE                   plpgsql_parse_dblwordrowtype
> > >      T_DTYPE             (nspname.relname%ROWTYPE)
> > > 
> > > ============================================================================
> > > Parameters - parallels the above
> > > ----------------------------------------------------------------------------
> > > $#                                                        plpgsql_parse_word
> > > $#.identifier                                          plpgsql_parse_dblword
> > > $#.identifier.identifier                              plpgsql_parse_tripword
> > > $#%TYPE                                               plpgsql_parse_wordtype
> > > $#.identifier%TYPE                                 plpgsql_parse_dblwordtype
> > > $#.identifier.identifier%TYPE                     plpgsql_parse_tripwordtype
> > > $#%ROWTYPE                                         plpgsql_parse_wordrowtype
> > > $#.identifier%ROWTYPE                           plpgsql_parse_dblwordrowtype
> > > 
> > > Comments?
> > > 
> > > Thanks,
> > > 
> > > Joe
> > 
> > > Index: src/pl/plpgsql/src/pl_comp.c
> > > ===================================================================
> > > RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v
> > > retrieving revision 1.51
> > > diff -c -r1.51 pl_comp.c
> > > *** src/pl/plpgsql/src/pl_comp.c  4 Sep 2002 20:31:47 -0000       1.51
> > > --- src/pl/plpgsql/src/pl_comp.c  9 Sep 2002 04:22:24 -0000
> > > ***************
> > > *** 1092,1097 ****
> > > --- 1092,1217 ----
> > >           return T_DTYPE;
> > >   }
> > >   
> > > + /* ----------
> > > +  * plpgsql_parse_tripwordtype           Same lookup for word.word.word%TYPE
> > > +  * ----------
> > > +  */
> > > + #define TYPE_JUNK_LEN   5
> > > + 
> > > + int
> > > + plpgsql_parse_tripwordtype(char *word)
> > > + {
> > > +         Oid                     classOid;
> > > +         HeapTuple       classtup;
> > > +         Form_pg_class classStruct;
> > > +         HeapTuple       attrtup;
> > > +         Form_pg_attribute attrStruct;
> > > +         HeapTuple       typetup;
> > > +         Form_pg_type typeStruct;
> > > +         PLpgSQL_type *typ;
> > > +         char       *cp[2];
> > > +         int                     qualified_att_len;
> > > +         int                     numdots = 0;
> > > +         int                     i;
> > > +         RangeVar   *relvar;
> > > + 
> > > +         /* Do case conversion and word separation */
> > > +         qualified_att_len = strlen(word) - TYPE_JUNK_LEN;
> > > +         Assert(word[qualified_att_len] == '%');
> > > + 
> > > +         for (i = 0; i < qualified_att_len; i++)
> > > +         {
> > > +                 if (word[i] == '.' && ++numdots == 2)
> > > +                 {
> > > +                         cp[0] = (char *) palloc((i + 1) * sizeof(char));
> > > +                         memset(cp[0], 0, (i + 1) * sizeof(char));
> > > +                         memcpy(cp[0], word, i * sizeof(char));
> > > + 
> > > +                         /* qualified_att_len - one based position + 1 (null 
>terminator) */
> > > +                         cp[1] = (char *) palloc((qualified_att_len - i) * 
>sizeof(char));
> > > +                         memset(cp[1], 0, (qualified_att_len - i) * 
>sizeof(char));
> > > +                         memcpy(cp[1], &word[i + 1], (qualified_att_len - i - 
>1) * sizeof(char));
> > > + 
> > > +                         break;
> > > +                 }
> > > +         }
> > > + 
> > > +         relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp[0], 
>"plpgsql_parse_dblwordtype"));
> > > +         classOid = RangeVarGetRelid(relvar, true);
> > > +         if (!OidIsValid(classOid))
> > > +         {
> > > +                 pfree(cp[0]);
> > > +                 pfree(cp[1]);
> > > +                 return T_ERROR;
> > > +         }
> > > +         classtup = SearchSysCache(RELOID,
> > > +                                                           
>ObjectIdGetDatum(classOid),
> > > +                                                           0, 0, 0);
> > > +         if (!HeapTupleIsValid(classtup))
> > > +         {
> > > +                 pfree(cp[0]);
> > > +                 pfree(cp[1]);
> > > +                 return T_ERROR;
> > > +         }
> > > + 
> > > +         /*
> > > +          * It must be a relation, sequence, view, or type
> > > +          */
> > > +         classStruct = (Form_pg_class) GETSTRUCT(classtup);
> > > +         if (classStruct->relkind != RELKIND_RELATION &&
> > > +                 classStruct->relkind != RELKIND_SEQUENCE &&
> > > +                 classStruct->relkind != RELKIND_VIEW &&
> > > +                 classStruct->relkind != RELKIND_COMPOSITE_TYPE)
> > > +         {
> > > +                 ReleaseSysCache(classtup);
> > > +                 pfree(cp[0]);
> > > +                 pfree(cp[1]);
> > > +                 return T_ERROR;
> > > +         }
> > > + 
> > > +         /*
> > > +          * Fetch the named table field and it's type
> > > +          */
> > > +         attrtup = SearchSysCacheAttName(classOid, cp[1]);
> > > +         if (!HeapTupleIsValid(attrtup))
> > > +         {
> > > +                 ReleaseSysCache(classtup);
> > > +                 pfree(cp[0]);
> > > +                 pfree(cp[1]);
> > > +                 return T_ERROR;
> > > +         }
> > > +         attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
> > > + 
> > > +         typetup = SearchSysCache(TYPEOID,
> > > +                                                          
>ObjectIdGetDatum(attrStruct->atttypid),
> > > +                                                          0, 0, 0);
> > > +         if (!HeapTupleIsValid(typetup))
> > > +                 elog(ERROR, "cache lookup for type %u of %s.%s failed",
> > > +                          attrStruct->atttypid, cp[0], cp[1]);
> > > +         typeStruct = (Form_pg_type) GETSTRUCT(typetup);
> > > + 
> > > +         /*
> > > +          * Found that - build a compiler type struct and return it
> > > +          */
> > > +         typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
> > > + 
> > > +         typ->typname = strdup(NameStr(typeStruct->typname));
> > > +         typ->typoid = attrStruct->atttypid;
> > > +         perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
> > > +         typ->typelem = typeStruct->typelem;
> > > +         typ->typbyval = typeStruct->typbyval;
> > > +         typ->typlen = typeStruct->typlen;
> > > +         typ->atttypmod = attrStruct->atttypmod;
> > > + 
> > > +         plpgsql_yylval.dtype = typ;
> > > + 
> > > +         ReleaseSysCache(classtup);
> > > +         ReleaseSysCache(attrtup);
> > > +         ReleaseSysCache(typetup);
> > > +         pfree(cp[0]);
> > > +         pfree(cp[1]);
> > > +         return T_DTYPE;
> > > + }
> > >   
> > >   /* ----------
> > >    * plpgsql_parse_wordrowtype            Scanner found word%ROWTYPE.
> > > ***************
> > > *** 1125,1130 ****
> > > --- 1245,1290 ----
> > >   
> > >           pfree(cp[0]);
> > >           pfree(cp[1]);
> > > + 
> > > +         return T_ROW;
> > > + }
> > > + 
> > > + /* ----------
> > > +  * plpgsql_parse_dblwordrowtype         Scanner found word.word%ROWTYPE.
> > > +  *                      So word must be namespace qualified a table name.
> > > +  * ----------
> > > +  */
> > > + #define ROWTYPE_JUNK_LEN        8
> > > + 
> > > + int
> > > + plpgsql_parse_dblwordrowtype(char *word)
> > > + {
> > > +         Oid                     classOid;
> > > +         char       *cp;
> > > +         int                     i;
> > > +         RangeVar   *relvar;
> > > + 
> > > +         /* Do case conversion and word separation */
> > > +         /* We convert %rowtype to .rowtype momentarily to keep converter happy 
>*/
> > > +         i = strlen(word) - ROWTYPE_JUNK_LEN;
> > > +         Assert(word[i] == '%');
> > > + 
> > > +         cp = (char *) palloc((i + 1) * sizeof(char));
> > > +         memset(cp, 0, (i + 1) * sizeof(char));
> > > +         memcpy(cp, word, i * sizeof(char));
> > > + 
> > > +         /* Lookup the relation */
> > > +         relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp, 
>"plpgsql_parse_dblwordtype"));
> > > +         classOid = RangeVarGetRelid(relvar, true);
> > > +         if (!OidIsValid(classOid))
> > > +                 elog(ERROR, "%s: no such class", cp);
> > > + 
> > > +         /*
> > > +          * Build and return the complete row definition
> > > +          */
> > > +         plpgsql_yylval.row = build_rowtype(classOid);
> > > + 
> > > +         pfree(cp);
> > >   
> > >           return T_ROW;
> > >   }
> > > Index: src/pl/plpgsql/src/plpgsql.h
> > > ===================================================================
> > > RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/plpgsql.h,v
> > > retrieving revision 1.27
> > > diff -c -r1.27 plpgsql.h
> > > *** src/pl/plpgsql/src/plpgsql.h  4 Sep 2002 20:31:47 -0000       1.27
> > > --- src/pl/plpgsql/src/plpgsql.h  9 Sep 2002 04:21:37 -0000
> > > ***************
> > > *** 568,574 ****
> > > --- 568,576 ----
> > >   extern int      plpgsql_parse_tripword(char *word);
> > >   extern int      plpgsql_parse_wordtype(char *word);
> > >   extern int      plpgsql_parse_dblwordtype(char *word);
> > > + extern int      plpgsql_parse_tripwordtype(char *word);
> > >   extern int      plpgsql_parse_wordrowtype(char *word);
> > > + extern int      plpgsql_parse_dblwordrowtype(char *word);
> > >   extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
> > >   extern void plpgsql_adddatum(PLpgSQL_datum * new);
> > >   extern int      plpgsql_add_initdatums(int **varnos);
> > > Index: src/pl/plpgsql/src/scan.l
> > > ===================================================================
> > > RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/scan.l,v
> > > retrieving revision 1.22
> > > diff -c -r1.22 scan.l
> > > *** src/pl/plpgsql/src/scan.l     30 Aug 2002 00:28:41 -0000      1.22
> > > --- src/pl/plpgsql/src/scan.l     9 Sep 2002 04:23:49 -0000
> > > ***************
> > > *** 170,183 ****
> > > --- 170,187 ----
> > >   {identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}       
> { return plpgsql_parse_tripword(yytext); }
> > >   {identifier}{space}*%TYPE               { return 
>plpgsql_parse_wordtype(yytext);        }
> > >   {identifier}{space}*\.{space}*{identifier}{space}*%TYPE { return 
>plpgsql_parse_dblwordtype(yytext); }
> > > + 
>{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE 
>  { return plpgsql_parse_tripwordtype(yytext); }
> > >   {identifier}{space}*%ROWTYPE    { return plpgsql_parse_wordrowtype(yytext);    
> }
> > > + {identifier}{space}*\.{space}*{identifier}{space}*%ROWTYPE      { return 
>plpgsql_parse_dblwordrowtype(yytext);  }
> > >   
> > >   \${digit}+                                              { return 
>plpgsql_parse_word(yytext);    }
> > >   \${digit}+{space}*\.{space}*{identifier}        { return 
>plpgsql_parse_dblword(yytext); }
> > >   \${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}  { 
>return plpgsql_parse_tripword(yytext); }
> > >   \${digit}+{space}*%TYPE                 { return 
>plpgsql_parse_wordtype(yytext);        }
> > >   \${digit}+{space}*\.{space}*{identifier}{space}*%TYPE   { return 
>plpgsql_parse_dblwordtype(yytext); }
> > > + 
>\${digit}+{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE   
>  { return plpgsql_parse_tripwordtype(yytext); }
> > >   \${digit}+{space}*%ROWTYPE              { return 
>plpgsql_parse_wordrowtype(yytext);     }
> > > + \${digit}+{space}*\.{space}*{identifier}{space}*%ROWTYPE        { return 
>plpgsql_parse_dblwordrowtype(yytext);  }
> > >   
> > >   {digit}+                { return T_NUMBER;                      }
> > >   
> > 
> > > -- nspname.relname.attname%TYPE
> > > DROP FUNCTION t();
> > > CREATE OR REPLACE FUNCTION t() RETURNS TEXT AS '
> > > DECLARE
> > >     col_name pg_catalog.pg_attribute.attname%TYPE;
> > > BEGIN
> > >     col_name := ''uga'';
> > >     RETURN col_name;
> > > END;
> > > ' LANGUAGE 'plpgsql';
> > > SELECT t();
> > > 
> > > -- nspname.relname%ROWTYPE
> > > DROP FUNCTION t();
> > > CREATE OR REPLACE FUNCTION t() RETURNS pg_catalog.pg_attribute AS '
> > > DECLARE
> > >     rec pg_catalog.pg_attribute%ROWTYPE;
> > > BEGIN
> > >     SELECT INTO rec * FROM pg_catalog.pg_attribute WHERE attrelid = 1247 AND 
>attname = ''typname'';
> > >     RETURN rec;
> > > END;
> > > ' LANGUAGE 'plpgsql';
> > > SELECT * FROM t();
> > > 
> > > -- nspname.relname.attname%TYPE
> > > DROP FUNCTION t();
> > > CREATE OR REPLACE FUNCTION t() RETURNS pg_catalog.pg_attribute.attname%TYPE AS '
> > > DECLARE
> > >     rec pg_catalog.pg_attribute.attname%TYPE;
> > > BEGIN
> > >     SELECT INTO rec pg_catalog.pg_attribute.attname FROM pg_catalog.pg_attribute 
>WHERE attrelid = 1247 AND attname = ''typname'';
> > >     RETURN rec;
> > > END;
> > > ' LANGUAGE 'plpgsql';
> > > SELECT t();
> > > 
> > > -- nspname.relname%ROWTYPE
> > > DROP FUNCTION t();
> > > CREATE OR REPLACE FUNCTION t() RETURNS pg_catalog.pg_attribute AS '
> > > DECLARE
> > >     rec pg_catalog.pg_attribute%ROWTYPE;
> > > BEGIN
> > >     SELECT INTO rec * FROM pg_catalog.pg_attribute WHERE attrelid = 1247 AND 
>attname = ''typname'';
> > >     RETURN rec;
> > > END;
> > > ' LANGUAGE 'plpgsql';
> > > SELECT * FROM t();
> > 
> > > 
> > > ---------------------------(end of broadcast)---------------------------
> > > TIP 3: if posting/reading through Usenet, please send an appropriate
> > > subscribe-nomail command to [EMAIL PROTECTED] so that your
> > > message can get through to the mailing list cleanly
> > 
> > -- 
> >   Bruce Momjian                        |  http://candle.pha.pa.us
> >   [EMAIL PROTECTED]               |  (610) 359-1001
> >   +  If your life is a hard drive,     |  13 Roberts Road
> >   +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
> > 
> > ---------------------------(end of broadcast)---------------------------
> > TIP 2: you can get off all lists at once with the unregister command
> >     (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])
> 
-- End of PGP section, PGP failed!

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  [EMAIL PROTECTED]               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

http://archives.postgresql.org

Reply via email to