*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.73 1999/11/22 17:56:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.77 2000/01/22 23:50:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_amop.h"
#include "catalog/pg_operator.h"
#include "executor/executor.h"
+#include "mb/pg_wchar.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+
+#define is_indexable_operator(clause,opclass,relam,indexkey_on_left) \
+ (indexable_operator(clause,opclass,relam,indexkey_on_left) != InvalidOid)
+
typedef enum {
Prefix_None, Prefix_Partial, Prefix_Exact
} Prefix_Status;
-static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index, int indexkey,
- int xclass, List *restrictinfo_list);
-static List *match_index_orclause(RelOptInfo *rel, RelOptInfo *index, int indexkey,
- int xclass, List *or_clauses, List *other_matching_indices);
-static bool match_or_subclause_to_indexkey(RelOptInfo *rel, RelOptInfo *index,
- int indexkey, int xclass,
+static void match_index_orclauses(RelOptInfo *rel, IndexOptInfo *index,
+ int indexkey, Oid opclass,
+ List *restrictinfo_list);
+static List *match_index_orclause(RelOptInfo *rel, IndexOptInfo *index,
+ int indexkey, Oid opclass,
+ List *or_clauses,
+ List *other_matching_indices);
+static bool match_or_subclause_to_indexkey(RelOptInfo *rel,
+ IndexOptInfo *index,
+ int indexkey, Oid opclass,
Expr *clause);
-static List *group_clauses_by_indexkey(RelOptInfo *rel, RelOptInfo *index,
- int *indexkeys, Oid *classes, List *restrictinfo_list);
-static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel, RelOptInfo *index,
- int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list);
-static bool match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index,
- int indexkey, int xclass,
+static List *group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index,
+ int *indexkeys, Oid *classes,
+ List *restrictinfo_list);
+static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel,
+ IndexOptInfo *index,
+ int *indexkeys, Oid *classes,
+ List *join_cinfo_list,
+ List *restr_cinfo_list);
+static bool match_clause_to_indexkey(RelOptInfo *rel, IndexOptInfo *index,
+ int indexkey, Oid opclass,
Expr *clause, bool join);
-static bool indexable_operator(Expr *clause, int xclass, Oid relam,
- bool indexkey_on_left);
static bool pred_test(List *predicate_list, List *restrictinfo_list,
- List *joininfo_list);
+ List *joininfo_list);
static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
static bool one_pred_clause_test(Expr *predicate, Node *clause);
static bool clause_pred_clause_test(Expr *predicate, Node *clause);
-static void indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
+static void indexable_joinclauses(RelOptInfo *rel, IndexOptInfo *index,
List *joininfo_list, List *restrictinfo_list,
List **clausegroups, List **outerrelids);
-static List *index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
+static List *index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
List *clausegroup_list, List *outerrelids_list);
-static bool useful_for_mergejoin(RelOptInfo *rel, RelOptInfo *index,
+static bool useful_for_mergejoin(RelOptInfo *rel, IndexOptInfo *index,
List *joininfo_list);
static bool useful_for_ordering(Query *root, RelOptInfo *rel,
- RelOptInfo *index);
+ IndexOptInfo *index);
static bool match_index_to_operand(int indexkey, Var *operand,
- RelOptInfo *rel, RelOptInfo *index);
-static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index);
-static bool match_special_index_operator(Expr *clause, bool indexkey_on_left);
+ RelOptInfo *rel, IndexOptInfo *index);
+static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
+ IndexOptInfo *index);
+static bool match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
+ bool indexkey_on_left);
static Prefix_Status like_fixed_prefix(char *patt, char **prefix);
static Prefix_Status regex_fixed_prefix(char *patt, bool case_insensitive,
char **prefix);
static List *prefix_quals(Var *leftop, Oid expr_op,
char *prefix, Prefix_Status pstatus);
+static char *make_greater_string(const char * str, Oid datatype);
+static Oid find_operator(const char * opname, Oid datatype);
+static Datum string_to_datum(const char * str, Oid datatype);
+static Const *string_to_const(const char * str, Oid datatype);
+static bool string_lessthan(const char * str1, const char * str2,
+ Oid datatype);
/*
foreach(ilist, indices)
{
- RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
+ IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
List *restrictclauses;
List *joinclausegroups;
List *joinouterrelids;
*/
static void
match_index_orclauses(RelOptInfo *rel,
- RelOptInfo *index,
+ IndexOptInfo *index,
int indexkey,
- int xclass,
+ Oid opclass,
List *restrictinfo_list)
{
List *i;
*/
restrictinfo->subclauseindices =
match_index_orclause(rel, index,
- indexkey, xclass,
+ indexkey, opclass,
restrictinfo->clause->args,
restrictinfo->subclauseindices);
}
*/
static List *
match_index_orclause(RelOptInfo *rel,
- RelOptInfo *index,
+ IndexOptInfo *index,
int indexkey,
- int xclass,
+ Oid opclass,
List *or_clauses,
List *other_matching_indices)
{
{
Expr *clause = lfirst(clist);
- if (match_or_subclause_to_indexkey(rel, index, indexkey, xclass,
+ if (match_or_subclause_to_indexkey(rel, index, indexkey, opclass,
clause))
{
/* OK to add this index to sublist for this subclause */
*/
static bool
match_or_subclause_to_indexkey(RelOptInfo *rel,
- RelOptInfo *index,
+ IndexOptInfo *index,
int indexkey,
- int xclass,
+ Oid opclass,
Expr *clause)
{
if (and_clause((Node *) clause))
foreach(item, clause->args)
{
- if (! match_clause_to_indexkey(rel, index, indexkey, xclass,
+ if (! match_clause_to_indexkey(rel, index, indexkey, opclass,
lfirst(item), false))
return false;
}
return true;
}
else
- return match_clause_to_indexkey(rel, index, indexkey, xclass,
+ return match_clause_to_indexkey(rel, index, indexkey, opclass,
clause, false);
}
*/
static List *
group_clauses_by_indexkey(RelOptInfo *rel,
- RelOptInfo *index,
+ IndexOptInfo *index,
int *indexkeys,
Oid *classes,
List *restrictinfo_list)
*/
static List *
group_clauses_by_ikey_for_joins(RelOptInfo *rel,
- RelOptInfo *index,
+ IndexOptInfo *index,
int *indexkeys,
Oid *classes,
List *join_cinfo_list,
* 'rel' is the relation of interest.
* 'index' is an index on 'rel'.
* 'indexkey' is a key of 'index'.
- * 'xclass' is the corresponding operator class.
+ * 'opclass' is the corresponding operator class.
* 'clause' is the clause to be tested.
* 'join' is true if we are considering this clause for joins.
*
*/
static bool
match_clause_to_indexkey(RelOptInfo *rel,
- RelOptInfo *index,
+ IndexOptInfo *index,
int indexkey,
- int xclass,
+ Oid opclass,
Expr *clause,
bool join)
{
if ((IsA(rightop, Const) || IsA(rightop, Param)) &&
match_index_to_operand(indexkey, leftop, rel, index))
{
- if (indexable_operator(clause, xclass, index->relam, true))
+ if (is_indexable_operator(clause, opclass, index->relam, true))
return true;
/*
* If we didn't find a member of the index's opclass,
* see whether it is a "special" indexable operator.
*/
- if (match_special_index_operator(clause, true))
+ if (match_special_index_operator(clause, opclass, index->relam,
+ true))
return true;
return false;
}
if ((IsA(leftop, Const) || IsA(leftop, Param)) &&
match_index_to_operand(indexkey, rightop, rel, index))
{
- if (indexable_operator(clause, xclass, index->relam, false))
+ if (is_indexable_operator(clause, opclass, index->relam, false))
return true;
/*
* If we didn't find a member of the index's opclass,
* see whether it is a "special" indexable operator.
*/
- if (match_special_index_operator(clause, false))
+ if (match_special_index_operator(clause, opclass, index->relam,
+ false))
return true;
return false;
}
isIndexable = ! intMember(lfirsti(rel->relids), othervarnos);
freeList(othervarnos);
if (isIndexable &&
- indexable_operator(clause, xclass, index->relam, true))
+ is_indexable_operator(clause, opclass, index->relam, true))
return true;
}
else if (match_index_to_operand(indexkey, rightop, rel, index))
isIndexable = ! intMember(lfirsti(rel->relids), othervarnos);
freeList(othervarnos);
if (isIndexable &&
- indexable_operator(clause, xclass, index->relam, false))
+ is_indexable_operator(clause, opclass, index->relam, false))
return true;
}
}
* Does a binary opclause contain an operator matching the index's
* access method?
*
- * If the indexkey is on the right, what we actually want to know
- * is whether the operator has a commutator operator that matches
- * the index's access method.
+ * If the indexkey is on the right, what we actually want to know
+ * is whether the operator has a commutator operator that matches
+ * the index's access method.
*
* We try both the straightforward match and matches that rely on
* recognizing binary-compatible datatypes. For example, if we have
* which we need to replace with oideq in order to recognize it as
* matching an oid_ops index on the oid field.
*
- * NOTE: if a binary-compatible match is made, we destructively modify
- * the given clause to use the binary-compatible substitute operator!
- * This should be safe even if we don't end up using the index, but it's
- * a tad ugly...
+ * Returns the OID of the matching operator, or InvalidOid if no match.
+ * Note that the returned OID will be different from the one in the given
+ * expression if we used a binary-compatible substitution. Also note that
+ * if indexkey_on_left is FALSE (meaning we need to commute), the returned
+ * OID is *not* commuted; it can be plugged directly into the given clause.
*/
-static bool
-indexable_operator(Expr *clause, int xclass, Oid relam,
+Oid
+indexable_operator(Expr *clause, Oid opclass, Oid relam,
bool indexkey_on_left)
{
Oid expr_op = ((Oper *) clause->oper)->opno;
else
commuted_op = get_commutator(expr_op);
if (commuted_op == InvalidOid)
- return false;
+ return InvalidOid;
/* Done if the (commuted) operator is a member of the index's AM */
- if (op_class(commuted_op, xclass, relam))
- return true;
+ if (op_class(commuted_op, opclass, relam))
+ return expr_op;
/*
* Maybe the index uses a binary-compatible operator set.
Operator newop;
if (opname == NULL)
- return false; /* probably shouldn't happen */
+ return InvalidOid; /* probably shouldn't happen */
/* Use the datatype of the index key */
if (indexkey_on_left)
else
commuted_op = get_commutator(new_expr_op);
if (commuted_op == InvalidOid)
- return false;
+ return InvalidOid;
- if (op_class(commuted_op, xclass, relam))
- {
- /*
- * Success! Change the opclause to use the
- * binary-compatible operator.
- */
- ((Oper *) clause->oper)->opno = new_expr_op;
- return true;
- }
+ if (op_class(commuted_op, opclass, relam))
+ return new_expr_op;
}
}
}
- return false;
+ return InvalidOid;
}
/*
*/
static bool
useful_for_mergejoin(RelOptInfo *rel,
- RelOptInfo *index,
+ IndexOptInfo *index,
List *joininfo_list)
{
int *indexkeys = index->indexkeys;
static bool
useful_for_ordering(Query *root,
RelOptInfo *rel,
- RelOptInfo *index)
+ IndexOptInfo *index)
{
List *index_pathkeys;
* '*outerrelids' receives a list of relid lists
*/
static void
-indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
+indexable_joinclauses(RelOptInfo *rel, IndexOptInfo *index,
List *joininfo_list, List *restrictinfo_list,
List **clausegroups, List **outerrelids)
{
* Returns a list of index pathnodes.
*/
static List *
-index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
+index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
List *clausegroup_list, List *outerrelids_list)
{
List *path_list = NIL;
List *clausegroup = lfirst(i);
IndexPath *pathnode = makeNode(IndexPath);
List *indexquals;
- float npages;
- float selec;
-
- indexquals = get_actual_clauses(clausegroup);
- /* expand special operators to indexquals the executor can handle */
- indexquals = expand_indexqual_conditions(indexquals);
-
- index_selectivity(root,
- lfirsti(rel->relids),
- lfirsti(index->relids),
- indexquals,
- &npages,
- &selec);
/* XXX this code ought to be merged with create_index_path? */
pathnode->path.parent = rel;
pathnode->path.pathkeys = build_index_pathkeys(root, rel, index);
+ indexquals = get_actual_clauses(clausegroup);
+ /* expand special operators to indexquals the executor can handle */
+ indexquals = expand_indexqual_conditions(indexquals);
+
/* Note that we are making a pathnode for a single-scan indexscan;
* therefore, both indexid and indexqual should be single-element
* lists.
*/
- Assert(length(index->relids) == 1);
- pathnode->indexid = index->relids;
+ pathnode->indexid = lconsi(index->indexoid, NIL);
pathnode->indexqual = lcons(indexquals, NIL);
/* joinrelids saves the rels needed on the outer side of the join */
pathnode->joinrelids = lfirst(outerrelids_list);
- pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
- (int) npages,
- selec,
- rel->pages,
- rel->tuples,
- index->pages,
- index->tuples,
+ pathnode->path.path_cost = cost_index(root, rel, index, indexquals,
true);
path_list = lappend(path_list, pathnode);
match_index_to_operand(int indexkey,
Var *operand,
RelOptInfo *rel,
- RelOptInfo *index)
+ IndexOptInfo *index)
{
if (index->indproc == InvalidOid)
{
}
static bool
-function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
+function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
{
int relvarno = lfirsti(rel->relids);
Func *function;
* Return 'true' if we can do something with it anyway.
*/
static bool
-match_special_index_operator(Expr *clause, bool indexkey_on_left)
+match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
+ bool indexkey_on_left)
{
bool isIndexable = false;
Var *leftop,
break;
}
+ /* done if the expression doesn't look indexable */
+ if (! isIndexable)
+ return false;
+
+ /*
+ * Must also check that index's opclass supports the operators we will
+ * want to apply. (A hash index, for example, will not support ">=".)
+ * We cheat a little by not checking for availability of "=" ... any
+ * index type should support "=", methinks.
+ */
+ switch (expr_op)
+ {
+ case OID_TEXT_LIKE_OP:
+ case OID_TEXT_REGEXEQ_OP:
+ case OID_TEXT_ICREGEXEQ_OP:
+ if (! op_class(find_operator(">=", TEXTOID), opclass, relam) ||
+ ! op_class(find_operator("<", TEXTOID), opclass, relam))
+ isIndexable = false;
+ break;
+
+ case OID_BPCHAR_LIKE_OP:
+ case OID_BPCHAR_REGEXEQ_OP:
+ case OID_BPCHAR_ICREGEXEQ_OP:
+ if (! op_class(find_operator(">=", BPCHAROID), opclass, relam) ||
+ ! op_class(find_operator("<", BPCHAROID), opclass, relam))
+ isIndexable = false;
+ break;
+
+ case OID_VARCHAR_LIKE_OP:
+ case OID_VARCHAR_REGEXEQ_OP:
+ case OID_VARCHAR_ICREGEXEQ_OP:
+ if (! op_class(find_operator(">=", VARCHAROID), opclass, relam) ||
+ ! op_class(find_operator("<", VARCHAROID), opclass, relam))
+ isIndexable = false;
+ break;
+
+ case OID_NAME_LIKE_OP:
+ case OID_NAME_REGEXEQ_OP:
+ case OID_NAME_ICREGEXEQ_OP:
+ if (! op_class(find_operator(">=", NAMEOID), opclass, relam) ||
+ ! op_class(find_operator("<", NAMEOID), opclass, relam))
+ isIndexable = false;
+ break;
+ }
+
return isIndexable;
}
/*
* Extract the fixed prefix, if any, for a LIKE pattern.
- * *prefix is set to a palloc'd prefix string with 1 spare byte,
+ * *prefix is set to a palloc'd prefix string,
* or to NULL if no fixed prefix exists for the pattern.
* The return value distinguishes no fixed prefix, a partial prefix,
* or an exact-match-only pattern.
int pos,
match_pos;
- *prefix = match = palloc(strlen(patt)+2);
+ *prefix = match = palloc(strlen(patt)+1);
match_pos = 0;
for (pos = 0; patt[pos]; pos++)
/*
* Extract the fixed prefix, if any, for a regex pattern.
- * *prefix is set to a palloc'd prefix string with 1 spare byte,
+ * *prefix is set to a palloc'd prefix string,
* or to NULL if no fixed prefix exists for the pattern.
* The return value distinguishes no fixed prefix, a partial prefix,
* or an exact-match-only pattern.
}
/* OK, allocate space for pattern */
- *prefix = match = palloc(strlen(patt)+2);
+ *prefix = match = palloc(strlen(patt)+1);
match_pos = 0;
/* note start at pos 1 to skip leading ^ */
{
List *result;
Oid datatype;
- HeapTuple optup;
- void *conval;
+ Oid oproid;
Const *con;
Oper *op;
Expr *expr;
- int prefixlen;
+ char *greaterstr;
Assert(pstatus != Prefix_None);
*/
if (pstatus == Prefix_Exact)
{
- optup = SearchSysCacheTuple(OPERNAME,
- PointerGetDatum("="),
- ObjectIdGetDatum(datatype),
- ObjectIdGetDatum(datatype),
- CharGetDatum('b'));
- if (!HeapTupleIsValid(optup))
+ oproid = find_operator("=", datatype);
+ if (oproid == InvalidOid)
elog(ERROR, "prefix_quals: no = operator for type %u", datatype);
- /* Note: we cheat a little by assuming that textin() will do for
- * bpchar and varchar constants too...
- */
- conval = (datatype == NAMEOID) ?
- (void*) namein(prefix) : (void*) textin(prefix);
- con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
- PointerGetDatum(conval),
- false, false, false, false);
- op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL);
+ con = string_to_const(prefix, datatype);
+ op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
expr = make_opclause(op, leftop, (Var *) con);
result = lcons(expr, NIL);
return result;
*
* We can always say "x >= prefix".
*/
- optup = SearchSysCacheTuple(OPERNAME,
- PointerGetDatum(">="),
- ObjectIdGetDatum(datatype),
- ObjectIdGetDatum(datatype),
- CharGetDatum('b'));
- if (!HeapTupleIsValid(optup))
+ oproid = find_operator(">=", datatype);
+ if (oproid == InvalidOid)
elog(ERROR, "prefix_quals: no >= operator for type %u", datatype);
- conval = (datatype == NAMEOID) ?
- (void*) namein(prefix) : (void*) textin(prefix);
- con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
- PointerGetDatum(conval),
- false, false, false, false);
- op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL);
+ con = string_to_const(prefix, datatype);
+ op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
expr = make_opclause(op, leftop, (Var *) con);
result = lcons(expr, NIL);
/*
- * In ASCII locale we say "x <= prefix\377". This does not
- * work for non-ASCII collation orders, and it's not really
- * right even for ASCII. FIX ME!
- * Note we assume the passed prefix string is workspace with
- * an extra byte, as created by the xxx_fixed_prefix routines above.
+ * If we can create a string larger than the prefix, say "x < greaterstr".
*/
-#ifndef USE_LOCALE
- prefixlen = strlen(prefix);
- prefix[prefixlen] = '\377';
- prefix[prefixlen+1] = '\0';
+ greaterstr = make_greater_string(prefix, datatype);
+ if (greaterstr)
+ {
+ oproid = find_operator("<", datatype);
+ if (oproid == InvalidOid)
+ elog(ERROR, "prefix_quals: no < operator for type %u", datatype);
+ con = string_to_const(greaterstr, datatype);
+ op = makeOper(oproid, InvalidOid, BOOLOID, 0, NULL);
+ expr = make_opclause(op, leftop, (Var *) con);
+ result = lappend(result, expr);
+ pfree(greaterstr);
+ }
+
+ return result;
+}
+
+/*
+ * Try to generate a string greater than the given string or any string it is
+ * a prefix of. If successful, return a palloc'd string; else return NULL.
+ *
+ * To work correctly in non-ASCII locales with weird collation orders,
+ * we cannot simply increment "foo" to "fop" --- we have to check whether
+ * we actually produced a string greater than the given one. If not,
+ * increment the righthand byte again and repeat. If we max out the righthand
+ * byte, truncate off the last character and start incrementing the next.
+ * For example, if "z" were the last character in the sort order, then we
+ * could produce "foo" as a string greater than "fonz".
+ *
+ * This could be rather slow in the worst case, but in most cases we won't
+ * have to try more than one or two strings before succeeding.
+ *
+ * XXX in a sufficiently weird locale, this might produce incorrect results?
+ * For example, in German I believe "ss" is treated specially --- if we are
+ * given "foos" and return "foot", will this actually be greater than "fooss"?
+ */
+static char *
+make_greater_string(const char * str, Oid datatype)
+{
+ char *workstr;
+ int len;
+
+ /* Make a modifiable copy, which will be our return value if successful */
+ workstr = pstrdup((char *) str);
+
+ while ((len = strlen(workstr)) > 0)
+ {
+ unsigned char *lastchar = (unsigned char *) (workstr + len - 1);
+
+ /*
+ * Try to generate a larger string by incrementing the last byte.
+ */
+ while (*lastchar < (unsigned char) 255)
+ {
+ (*lastchar)++;
+ if (string_lessthan(str, workstr, datatype))
+ return workstr; /* Success! */
+ }
+ /*
+ * Truncate off the last character, which might be more than 1 byte
+ * in MULTIBYTE case.
+ */
+#ifdef MULTIBYTE
+ len = pg_mbcliplen((const unsigned char *) workstr, len, len-1);
+ workstr[len] = '\0';
+#else
+ *lastchar = '\0';
+#endif
+ }
+
+ /* Failed... */
+ pfree(workstr);
+ return NULL;
+}
+
+/*
+ * Handy subroutines for match_special_index_operator() and friends.
+ */
+
+/* See if there is a binary op of the given name for the given datatype */
+static Oid
+find_operator(const char * opname, Oid datatype)
+{
+ HeapTuple optup;
optup = SearchSysCacheTuple(OPERNAME,
- PointerGetDatum("<="),
+ PointerGetDatum(opname),
ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype),
CharGetDatum('b'));
if (!HeapTupleIsValid(optup))
- elog(ERROR, "prefix_quals: no <= operator for type %u", datatype);
- conval = (datatype == NAMEOID) ?
- (void*) namein(prefix) : (void*) textin(prefix);
- con = makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
- PointerGetDatum(conval),
- false, false, false, false);
- op = makeOper(optup->t_data->t_oid, InvalidOid, BOOLOID, 0, NULL);
- expr = make_opclause(op, leftop, (Var *) con);
- result = lappend(result, expr);
-#endif
+ return InvalidOid;
+ return optup->t_data->t_oid;
+}
+
+/*
+ * Generate a Datum of the appropriate type from a C string.
+ * Note that all of the supported types are pass-by-ref, so the
+ * returned value should be pfree'd if no longer needed.
+ */
+static Datum
+string_to_datum(const char * str, Oid datatype)
+{
+ /* We cheat a little by assuming that textin() will do for
+ * bpchar and varchar constants too...
+ */
+ if (datatype == NAMEOID)
+ return PointerGetDatum(namein((char *) str));
+ else
+ return PointerGetDatum(textin((char *) str));
+}
+
+/*
+ * Generate a Const node of the appropriate type from a C string.
+ */
+static Const *
+string_to_const(const char * str, Oid datatype)
+{
+ Datum conval = string_to_datum(str, datatype);
+
+ return makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
+ conval, false, false, false, false);
+}
+
+/*
+ * Test whether two strings are "<" according to the rules of the given
+ * datatype. We do this the hard way, ie, actually calling the type's
+ * "<" operator function, to ensure we get the right result...
+ */
+static bool
+string_lessthan(const char * str1, const char * str2, Oid datatype)
+{
+ Datum datum1 = string_to_datum(str1, datatype);
+ Datum datum2 = string_to_datum(str2, datatype);
+ bool result;
+
+ switch (datatype)
+ {
+ case TEXTOID:
+ result = text_lt((text *) datum1, (text *) datum2);
+ break;
+
+ case BPCHAROID:
+ result = bpcharlt((char *) datum1, (char *) datum2);
+ break;
+
+ case VARCHAROID:
+ result = varcharlt((char *) datum1, (char *) datum2);
+ break;
+
+ case NAMEOID:
+ result = namelt((NameData *) datum1, (NameData *) datum2);
+ break;
+
+ default:
+ elog(ERROR, "string_lessthan: unexpected datatype %u", datatype);
+ result = false;
+ break;
+ }
+
+ pfree(DatumGetPointer(datum1));
+ pfree(DatumGetPointer(datum2));
return result;
}