/* * Converts a VARCHAR2 type to the specified size. * * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. * isExplicit is true if this is for an explicit cast to varchar2(N). * * Truncation rules: for an explicit cast, silently truncate to the given * length; for an implicit cast, raise error if length limit is exceeded */ PGDLLEXPORT Datum varchar2(PG_FUNCTION_ARGS) { VarChar *source = PG_GETARG_VARCHAR_PP(0); int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); int32 len, maxlen; char *s_data; len = VARSIZE_ANY_EXHDR(source); s_data = VARDATA_ANY(source); maxlen = typmod - VARHDRSZ; /* No work if typmod is invalid or supplied data fits it already */ if (maxlen < 0 || len <= maxlen) PG_RETURN_VARCHAR_P(source); /* error out if value too long unless it's an explicit cast */ if (!isExplicit) { if (len > maxlen) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input value length is %d; too long for type varchar2(%d)",len ,maxlen))); } PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,maxlen)); }
Datum email_in(PG_FUNCTION_ARGS) { char *str=PG_GETARG_CSTRING(0); VarChar *rt; int len,ret; ret=email_grammar_checker(str); if(ret==IS_FALSE) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for email: \"%s\"",str))); len=strlen(str); if(len>256) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid length of input for email: len(%d) \"%s\"", len,str))); rt=(VarChar*) palloc(len+VARHDRSZ); SET_VARSIZE(rt,len+VARHDRSZ); strcpy_to_lowercase_len(VARDATA(rt),str,len);//copy string and convert string into lowercase PG_RETURN_VARCHAR_P(rt); }
/* * Converts a VARCHAR type to the specified size. * * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. * isExplicit is true if this is for an explicit cast to varchar(N). * * Truncation rules: for an explicit cast, silently truncate to the given * length; for an implicit cast, raise error unless extra characters are * all spaces. (This is sort-of per SQL: the spec would actually have us * raise a "completion condition" for the explicit cast case, but Postgres * hasn't got such a concept.) */ Datum varchar(PG_FUNCTION_ARGS) { VarChar *source = PG_GETARG_VARCHAR_P(0); int32 maxlen = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); VarChar *result; int32 len; size_t maxmblen; int i; len = VARSIZE(source); /* No work if typmod is invalid or supplied data fits it already */ if (maxlen < (int32) VARHDRSZ || len <= maxlen) PG_RETURN_VARCHAR_P(source); /* only reach here if string is too long... */ /* truncate multibyte string preserving multibyte boundary */ maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ, maxlen - VARHDRSZ); if (!isExplicit) { for (i = maxmblen; i < len - VARHDRSZ; i++) if (*(VARDATA(source) + i) != ' ') ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("value too long for type character varying(%d)", maxlen - VARHDRSZ))); } len = maxmblen + VARHDRSZ; result = palloc(len); VARATT_SIZEP(result) = len; memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ); PG_RETURN_VARCHAR_P(result); }
/* * Converts a C string to NVARCHAR2 internal representation. atttypmod * is the declared length of the type plus VARHDRSZ. */ Datum nvarchar2in(PG_FUNCTION_ARGS) { char *s = PG_GETARG_CSTRING(0); #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); VarChar *result; result = nvarchar2_input(s, strlen(s), atttypmod); PG_RETURN_VARCHAR_P(result); }
/* * Converts a NVARCHAR2 type to the specified size. * * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. * isExplicit is true if this is for an explicit cast to nvarchar2(N). * * Truncation rules: for an explicit cast, silently truncate to the given * length; for an implicit cast, raise error if length limit is exceeded */ Datum nvarchar2(PG_FUNCTION_ARGS) { VarChar *source = PG_GETARG_VARCHAR_PP(0); int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); int32 len, maxlen; size_t maxmblen; char *s_data; len = VARSIZE_ANY_EXHDR(source); s_data = VARDATA_ANY(source); maxlen = typmod - VARHDRSZ; /* No work if typmod is invalid or supplied data fits it already */ if (maxlen < 0 || len <= maxlen) PG_RETURN_VARCHAR_P(source); /* only reach here if string is too long... */ /* truncate multibyte string preserving multibyte boundary */ maxmblen = pg_mbcharcliplen(s_data, len, maxlen); /* error out if value too long unless it's an explicit cast */ if (!isExplicit) { /* if there is still data beyond maxmblen, error out * * Remember - no blankspace truncation on implicit cast */ if (len > maxmblen) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input value too long for type nvarchar2(%d)", maxlen))); } PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data, maxmblen)); }
Datum email_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); VarChar *result; char *str; int nbytes; str=pq_getmsgtext(buf,buf->len-buf->cursor,&nbytes); result=(VarChar*) palloc((nbytes)+VARHDRSZ); SET_VARSIZE(result,nbytes+VARHDRSZ); memcpy(VARDATA(result),str,nbytes); pfree(str); PG_RETURN_VARCHAR_P(result); }
/* * varcharrecv - converts external binary format to varchar */ Datum varcharrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); VarChar *result; char *str; int nbytes; str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); result = varchar_input(str, nbytes, atttypmod); pfree(str); PG_RETURN_VARCHAR_P(result); }
/* * converts external binary format to nvarchar */ Datum nvarchar2recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); #ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); #endif int32 atttypmod = PG_GETARG_INT32(2); /* typmod of the receiving column */ VarChar *result; char *str; /* received data */ int nbytes; /* length in bytes of recived data */ str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); result = nvarchar2_input(str, nbytes, atttypmod); pfree(str); PG_RETURN_VARCHAR_P(result); }
/* table_log_restore_table() restore a complete table based on the logging table parameter: - original table name - name of primary key in original table - logging table - name of primary key in logging table - restore table name - timestamp for restoring data - primary key to restore (only this key will be restored) (optional) - restore mode 0: restore from blank table (default) needs a complete logging table 1: restore from actual table backwards - dont create table temporarly 0: create restore table temporarly (default) 1: create restore table not temporarly return: not yet defined */ Datum table_log_restore_table(PG_FUNCTION_ARGS) { /* the original table name */ char *table_orig; /* the primary key in the original table */ char *table_orig_pkey; /* number columns in original table */ int table_orig_columns; /* the log table name */ char *table_log; /* the primary key in the log table (usually trigger_id) */ /* cannot be the same then then the pkey in the original table */ char *table_log_pkey; /* number columns in log table */ int table_log_columns; /* the restore table name */ char *table_restore; /* the timestamp in past */ Datum timestamp = PG_GETARG_DATUM(5); /* the single pkey, can be null (then all keys will be restored) */ char *search_pkey = ""; /* the restore method - 0: restore from blank table (default) needs a complete log table! - 1: restore from actual table backwards */ int method = 0; /* dont create restore table temporarly - 0: create restore table temporarly (default) - 1: dont create restore table temporarly */ int not_temporarly = 0; int ret, results, i, number_columns; char query[250 + NAMEDATALEN]; /* for getting table infos (250 chars (+ one times the length of all names) should be enough) */ int need_search_pkey = 0; /* does we have a single key to restore? */ char *tmp, *timestamp_string, *old_pkey_string = ""; char *trigger_mode, *trigger_tuple, *trigger_changed; SPITupleTable *spi_tuptable = NULL; /* for saving query results */ VarChar *return_name; /* memory for dynamic query */ int d_query_size = 250; /* start with 250 bytes */ char *d_query; char *d_query_start; /* memory for column names */ int col_query_size = 0; char *col_query; char *col_query_start; int col_pkey = 0; /* * Some checks first... */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "start table_log_restore_table()"); #endif /* TABLE_LOG_DEBUG */ /* does we have all arguments? */ if (PG_ARGISNULL(0)) { elog(ERROR, "table_log_restore_table: missing original table name"); } if (PG_ARGISNULL(1)) { elog(ERROR, "table_log_restore_table: missing primary key name for original table"); } if (PG_ARGISNULL(2)) { elog(ERROR, "table_log_restore_table: missing log table name"); } if (PG_ARGISNULL(3)) { elog(ERROR, "table_log_restore_table: missing primary key name for log table"); } if (PG_ARGISNULL(4)) { elog(ERROR, "table_log_restore_table: missing copy table name"); } if (PG_ARGISNULL(5)) { elog(ERROR, "table_log_restore_table: missing timestamp"); } /* first check number arguments to avoid an segfault */ if (PG_NARGS() >= 7) { /* if argument is given, check if not null */ if (!PG_ARGISNULL(6)) { /* yes, fetch it */ search_pkey = __table_log_varcharout((VarChar *)PG_GETARG_VARCHAR_P(6)); /* and check, if we have an argument */ if (strlen(search_pkey) > 0) { need_search_pkey = 1; #ifdef TABLE_LOG_DEBUG elog(NOTICE, "table_log_restore_table: will restore a single key"); #endif /* TABLE_LOG_DEBUG */ } } } /* same procedere here */ if (PG_NARGS() >= 8) { if (!PG_ARGISNULL(7)) { method = PG_GETARG_INT32(7); if (method > 0) { method = 1; } else { method = 0; } } } #ifdef TABLE_LOG_DEBUG if (method == 1) { elog(NOTICE, "table_log_restore_table: will restore from actual state backwards"); } else { elog(NOTICE, "table_log_restore_table: will restore from begin forward"); } #endif /* TABLE_LOG_DEBUG */ if (PG_NARGS() >= 9) { if (!PG_ARGISNULL(8)) { not_temporarly = PG_GETARG_INT32(8); if (not_temporarly > 0) { not_temporarly = 1; } else { not_temporarly = 0; } } } #ifdef TABLE_LOG_DEBUG if (not_temporarly == 1) { elog(NOTICE, "table_log_restore_table: dont create restore table temporarly"); } #endif /* TABLE_LOG_DEBUG */ /* get parameter */ table_orig = __table_log_varcharout((VarChar *)PG_GETARG_VARCHAR_P(0)); table_orig_pkey = __table_log_varcharout((VarChar *)PG_GETARG_VARCHAR_P(1)); table_log = __table_log_varcharout((VarChar *)PG_GETARG_VARCHAR_P(2)); table_log_pkey = __table_log_varcharout((VarChar *)PG_GETARG_VARCHAR_P(3)); table_restore = __table_log_varcharout((VarChar *)PG_GETARG_VARCHAR_P(4)); /* pkey of original table cannot be the same as of log table */ if (strcmp((const char *)table_orig_pkey, (const char *)table_log_pkey) == 0) { elog(ERROR, "pkey of logging table cannot be the pkey of the original table: %s <-> %s", table_orig_pkey, table_log_pkey); } /* Connect to SPI manager */ ret = SPI_connect(); if (ret != SPI_OK_CONNECT) { elog(ERROR, "table_log_restore_table: SPI_connect returned %d", ret); } /* check original table */ snprintf(query, 249, "SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname = %s AND a.attnum > 0 AND a.attrelid = c.oid ORDER BY a.attnum", do_quote_literal(table_orig)); #ifdef TABLE_LOG_DEBUG_QUERY elog(NOTICE, "query: %s", query); #endif /* TABLE_LOG_DEBUG_QUERY */ ret = SPI_exec(query, 0); if (ret != SPI_OK_SELECT) { elog(ERROR, "could not check relation: %s", table_orig); } if (SPI_processed > 0) { table_orig_columns = SPI_processed; } else { elog(ERROR, "could not check relation: %s", table_orig); } /* check pkey in original table */ snprintf(query, 249, "SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname=%s AND c.relkind='r' AND a.attname=%s AND a.attnum > 0 AND a.attrelid = c.oid", do_quote_literal(table_orig), do_quote_literal(table_orig_pkey)); #ifdef TABLE_LOG_DEBUG_QUERY elog(NOTICE, "query: %s", query); #endif /* TABLE_LOG_DEBUG_QUERY */ ret = SPI_exec(query, 0); if (ret != SPI_OK_SELECT) { elog(ERROR, "could not check relation: %s", table_orig); } if (SPI_processed == 0) { elog(ERROR, "could not check relation: %s", table_orig); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "original table: OK (%i columns)", table_orig_columns); #endif /* TABLE_LOG_DEBUG */ /* check log table */ snprintf(query, 249, "SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname = %s AND a.attnum > 0 AND a.attrelid = c.oid ORDER BY a.attnum", do_quote_literal(table_log)); #ifdef TABLE_LOG_DEBUG_QUERY elog(NOTICE, "query: %s", query); #endif /* TABLE_LOG_DEBUG_QUERY */ ret = SPI_exec(query, 0); if (ret != SPI_OK_SELECT) { elog(ERROR, "could not check relation [1]: %s", table_log); } if (SPI_processed > 0) { table_log_columns = SPI_processed; } else { elog(ERROR, "could not check relation [2]: %s", table_log); } /* check pkey in log table */ snprintf(query, 249, "SELECT a.attname FROM pg_class c, pg_attribute a WHERE c.relname=%s AND c.relkind='r' AND a.attname=%s AND a.attnum > 0 AND a.attrelid = c.oid", do_quote_literal(table_log), do_quote_literal(table_log_pkey)); #ifdef TABLE_LOG_DEBUG_QUERY elog(NOTICE, "query: %s", query); #endif /* TABLE_LOG_DEBUG_QUERY */ ret = SPI_exec(query, 0); if (ret != SPI_OK_SELECT) { elog(ERROR, "could not check relation [3]: %s", table_log); } if (SPI_processed == 0) { elog(ERROR, "could not check relation [4]: %s", table_log); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "log table: OK (%i columns)", table_log_columns); #endif /* TABLE_LOG_DEBUG */ /* check restore table */ snprintf(query, 249, "SELECT pg_attribute.attname AS a FROM pg_class, pg_attribute WHERE pg_class.relname=%s AND pg_attribute.attnum > 0 AND pg_attribute.attrelid=pg_class.oid", do_quote_literal(table_restore)); #ifdef TABLE_LOG_DEBUG_QUERY elog(NOTICE, "query: %s", query); #endif /* TABLE_LOG_DEBUG_QUERY */ ret = SPI_exec(query, 0); if (ret != SPI_OK_SELECT) { elog(ERROR, "could not check relation: %s", table_restore); } if (SPI_processed > 0) { elog(ERROR, "restore table already exists: %s", table_restore); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "restore table: OK (doesnt exists)"); #endif /* TABLE_LOG_DEBUG */ /* now get all columns from original table */ snprintf(query, 249, "SELECT a.attname, format_type(a.atttypid, a.atttypmod), a.attnum FROM pg_class c, pg_attribute a WHERE c.relname = %s AND a.attnum > 0 AND a.attrelid = c.oid ORDER BY a.attnum", do_quote_literal(table_orig)); #ifdef TABLE_LOG_DEBUG_QUERY elog(NOTICE, "query: %s", query); #endif /* TABLE_LOG_DEBUG_QUERY */ ret = SPI_exec(query, 0); if (ret != SPI_OK_SELECT) { elog(ERROR, "could not get columns from relation: %s", table_orig); } if (SPI_processed == 0) { elog(ERROR, "could not check relation: %s", table_orig); } results = SPI_processed; /* store number columns for later */ number_columns = SPI_processed; #ifdef TABLE_LOG_DEBUG elog(NOTICE, "number columns: %i", results); #endif /* TABLE_LOG_DEBUG */ for (i = 0; i < results; i++) { /* the column name */ tmp = SPI_getvalue(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1); col_query_size += strlen(do_quote_ident(tmp)) + 2; /* now check, if this is the pkey */ if (strcmp((const char *)tmp, (const char *)table_orig_pkey) == 0) { /* remember the (real) number */ col_pkey = i + 1; } } /* check if we have found the pkey */ if (col_pkey == 0) { elog(ERROR, "cannot find pkey (%s) in table %s", table_orig_pkey, table_orig); } /* allocate memory for string */ col_query_size += 10; col_query_start = (char *) palloc((col_query_size + 1) * sizeof(char)); col_query = col_query_start; for (i = 0; i < results; i++) { if (i > 0) { sprintf(col_query, ", "); col_query = col_query_start + strlen(col_query_start); } sprintf(col_query, "%s", do_quote_ident(SPI_getvalue(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1))); col_query = col_query_start + strlen(col_query_start); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "string for columns: %s", col_query_start); #endif /* TABLE_LOG_DEBUG */ /* create restore table */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "create restore table: %s", table_restore); #endif /* TABLE_LOG_DEBUG */ snprintf(query, 249, "SELECT * INTO "); /* per default create a temporary table */ if (not_temporarly == 0) { strcat(query, "TEMPORARY "); } strcat(query, "TABLE "); strncat(query, table_restore, 249); /* from which table? */ strncat(query, " FROM ", 249); strncat(query, table_orig, 249); if (need_search_pkey == 1) { /* only extract a specific key */ strncat(query, " WHERE ", 249); strncat(query, do_quote_ident(table_orig_pkey), 249); strncat(query, "=", 249); strncat(query, do_quote_literal(search_pkey), 249); } if (method == 0) { /* restore from begin (blank table) */ strncat(query, " LIMIT 0", 249); } #ifdef TABLE_LOG_DEBUG_QUERY elog(NOTICE, "query: %s", query); #endif /* TABLE_LOG_DEBUG_QUERY */ ret = SPI_exec(query, 0); if (ret != SPI_OK_SELINTO) { elog(ERROR, "could not check relation: %s", table_restore); } if (method == 1) { #ifdef TABLE_LOG_DEBUG elog(NOTICE, "%i rows copied", SPI_processed); #endif /* TABLE_LOG_DEBUG */ } /* get timestamp as string */ timestamp_string = DatumGetCString(DirectFunctionCall1(timestamptz_out, timestamp)); #ifdef TABLE_LOG_DEBUG if (method == 0) { elog(NOTICE, "need logs from start to timestamp: %s", timestamp_string); } else { elog(NOTICE, "need logs from end to timestamp: %s", timestamp_string); } #endif /* TABLE_LOG_DEBUG */ /* now build query for getting logs */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "build query for getting logs"); #endif /* TABLE_LOG_DEBUG */ d_query_size += d_query_size + strlen(col_query_start); if (need_search_pkey == 1) { /* add size of pkey and size of value */ d_query_size += strlen(do_quote_ident(table_orig_pkey)) * 2 + strlen(do_quote_literal(search_pkey)) + 3; } /* allocate memory for string */ d_query_size += 10; d_query_start = (char *) palloc((d_query_size + 1) * sizeof(char)); d_query = d_query_start; snprintf(d_query, d_query_size, "SELECT %s, trigger_mode, trigger_tuple, trigger_changed FROM %s WHERE ", col_query_start, do_quote_ident(table_log)); d_query = d_query_start + strlen(d_query_start); if (method == 0) { /* from start to timestamp */ snprintf(d_query, d_query_size, "trigger_changed <= %s ", do_quote_literal(timestamp_string)); } else { /* from now() backwards to timestamp */ snprintf(d_query, d_query_size, "trigger_changed >= %s ", do_quote_literal(timestamp_string)); } d_query = d_query_start + strlen(d_query_start); if (need_search_pkey == 1) { snprintf(d_query, d_query_size, "AND %s = %s ", do_quote_ident(table_orig_pkey), do_quote_literal(search_pkey)); d_query = d_query_start + strlen(d_query_start); } if (method == 0) { snprintf(d_query, d_query_size, "ORDER BY %s ASC", do_quote_ident(table_log_pkey)); } else { snprintf(d_query, d_query_size, "ORDER BY %s DESC", do_quote_ident(table_log_pkey)); } d_query = d_query_start + strlen(d_query_start); #ifdef TABLE_LOG_DEBUG_QUERY elog(NOTICE, "query: %s", d_query_start); #endif /* TABLE_LOG_DEBUG_QUERY */ ret = SPI_exec(d_query_start, 0); if (ret != SPI_OK_SELECT) { elog(ERROR, "could not get log data from table: %s", table_log); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "number log entries to restore: %i", SPI_processed); #endif /* TABLE_LOG_DEBUG */ results = SPI_processed; /* save results */ spi_tuptable = SPI_tuptable; /* go through all results */ for (i = 0; i < results; i++) { /* get tuple data */ trigger_mode = SPI_getvalue(spi_tuptable->vals[i], spi_tuptable->tupdesc, number_columns + 1); trigger_tuple = SPI_getvalue(spi_tuptable->vals[i], spi_tuptable->tupdesc, number_columns + 2); trigger_changed = SPI_getvalue(spi_tuptable->vals[i], spi_tuptable->tupdesc, number_columns + 3); /* check for update tuples we doesnt need */ if (strcmp((const char *)trigger_mode, (const char *)"UPDATE") == 0) { if (method == 0 && strcmp((const char *)trigger_tuple, (const char *)"old") == 0) { /* we need the old value of the pkey for the update */ old_pkey_string = SPI_getvalue(spi_tuptable->vals[i], spi_tuptable->tupdesc, col_pkey); #ifdef TABLE_LOG_DEBUG elog(NOTICE, "tuple old pkey: %s", old_pkey_string); #endif /* TABLE_LOG_DEBUG */ /* then skip this tuple */ continue; } if (method == 1 && strcmp((const char *)trigger_tuple, (const char *)"new") == 0) { /* we need the old value of the pkey for the update */ old_pkey_string = SPI_getvalue(spi_tuptable->vals[i], spi_tuptable->tupdesc, col_pkey); #ifdef TABLE_LOG_DEBUG elog(NOTICE, "tuple: old pkey: %s", old_pkey_string); #endif /* TABLE_LOG_DEBUG */ /* then skip this tuple */ continue; } } if (method == 0) { /* roll forward */ #ifdef TABLE_LOG_DEBUG elog(NOTICE, "tuple: %s %s %s", trigger_mode, trigger_tuple, trigger_changed); #endif /* TABLE_LOG_DEBUG */ if (strcmp((const char *)trigger_mode, (const char *)"INSERT") == 0) { __table_log_restore_table_insert(spi_tuptable, table_restore, table_orig_pkey, col_query_start, col_pkey, number_columns, i); } else if (strcmp((const char *)trigger_mode, (const char *)"UPDATE") == 0) { __table_log_restore_table_update(spi_tuptable, table_restore, table_orig_pkey, col_query_start, col_pkey, number_columns, i, old_pkey_string); } else if (strcmp((const char *)trigger_mode, (const char *)"DELETE") == 0) { __table_log_restore_table_delete(spi_tuptable, table_restore, table_orig_pkey, col_query_start, col_pkey, number_columns, i); } else { elog(ERROR, "unknown trigger_mode: %s", trigger_mode); } } else { /* roll back */ char rb_mode[10]; /* reverse the method */ if (strcmp((const char *)trigger_mode, (const char *)"INSERT") == 0) { sprintf(rb_mode, "DELETE"); } else if (strcmp((const char *)trigger_mode, (const char *)"UPDATE") == 0) { sprintf(rb_mode, "UPDATE"); } else if (strcmp((const char *)trigger_mode, (const char *)"DELETE") == 0) { sprintf(rb_mode, "INSERT"); } else { elog(ERROR, "unknown trigger_mode: %s", trigger_mode); } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "tuple: %s %s %s", rb_mode, trigger_tuple, trigger_changed); #endif /* TABLE_LOG_DEBUG */ if (strcmp((const char *)trigger_mode, (const char *)"INSERT") == 0) { __table_log_restore_table_delete(spi_tuptable, table_restore, table_orig_pkey, col_query_start, col_pkey, number_columns, i); } else if (strcmp((const char *)trigger_mode, (const char *)"UPDATE") == 0) { __table_log_restore_table_update(spi_tuptable, table_restore, table_orig_pkey, col_query_start, col_pkey, number_columns, i, old_pkey_string); } else if (strcmp((const char *)trigger_mode, (const char *)"DELETE") == 0) { __table_log_restore_table_insert(spi_tuptable, table_restore, table_orig_pkey, col_query_start, col_pkey, number_columns, i); } } } #ifdef TABLE_LOG_DEBUG elog(NOTICE, "table_log_restore_table() done, results in: %s", table_restore); #endif /* TABLE_LOG_DEBUG */ /* convert string to VarChar for result */ return_name = DatumGetVarCharP(DirectFunctionCall2(varcharin, CStringGetDatum(table_restore), Int32GetDatum(strlen(table_restore) + VARHDRSZ))); /* close SPI connection */ SPI_finish(); /* and return the name of the restore table */ PG_RETURN_VARCHAR_P(return_name); }
Datum *tidyurl(PG_FUNCTION_ARGS) { VarChar *arg; VarChar *ret; int ret_size; char *str; char *res; char *src, *dst; int in, out; translation *t; int size; arg = PG_GETARG_VARCHAR_P(0); // Extract string size = VARSIZE(arg) - VARHDRSZ; str = (char *) palloc(size + 1); if (str == NULL) { ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); PG_RETURN_NULL(); } memcpy(str, VARDATA(arg), size); str[size] = 0; // Allocate result string res = (char *) palloc(size + 1); if (res == NULL) { ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); PG_RETURN_NULL(); } memset(res, 0, size + 1); for (in = out = 0, src = str, dst = res; *src; src = str + in, dst = res + out) { // FIXME: Bubble search. fix for performance for (t = (translation *) translator; t->tr_from; ++t) { if (strncmp(src, t->tr_from, strlen(t->tr_from)) == 0) { src = t->tr_to; break; } } // Skip unknown/untranslated utf-8 chars and non printables if (*src <= 32 || *src >= 127) { ++in; continue; } // Skip double white spaces: _ if (out && *(dst - 1) == SPACE_CHAR && *src == SPACE_CHAR) { ++in; continue; } if (t->tr_from) { in += strlen(t->tr_from); out += strlen(t->tr_to); } else { ++in; ++out; } // Make sure theres enough room in result if (out >= size) { res = repalloc(res, size * 2 + 1); if (res == NULL) { ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); PG_RETURN_NULL(); } memset(res + size, 0, size + 1); // Make sure dst points right dst = res + strlen(res); size *= 2; } if (t->tr_from) { strcpy(dst, src); } else { *dst = *src; } } // Remove trailing underscores (spaces) for (;*dst == SPACE_CHAR; --dst) { *dst = 0; } // Lowercase /* for (dst = res; *dst; ++dst) { if (isupper(*dst)) { *dst = tolower(*dst); } } */ // Return result ret_size = out + VARHDRSZ; ret = (VarChar *) palloc(ret_size); if (ret == NULL) { ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); PG_RETURN_NULL(); } SET_VARSIZE(ret, ret_size); memcpy(VARDATA(ret), res, out); pfree(str); pfree(res); PG_RETURN_VARCHAR_P(ret); }