Пример #1
0
// This is not inlined in TestDates to force the cleanup after we're done with
// each server (this prevents races from two TestServers running at the same time).
func testDatesInternal(t *testing.T, loc *time.Location) {
	server, db := setup(t, loc)
	defer cleanup(server, db)

	var date *driver.Date
	for _, year := range []int{
		1200, // distant past
		2020, // present day, for DST rules
		4000, // distant future
	} {
		for _, month := range []time.Month{
			time.December, // winter
			time.August,   // summer
		} {
			for hour := 0; hour < 24; hour++ {
				timestamp := time.Date(year, month, 20, hour, 34, 45, 123, loc)

				if err := db.QueryRow("SELECT $1::DATE", timestamp).Scan(&date); err != nil {
					t.Fatal(err)
				}

				if expected := driver.MakeDate(timestamp); *date != expected {
					t.Fatalf("expected date to be truncated to:\n%s\nbut got:\n%s", expected, date)
				}
			}
		}
	}
}
Пример #2
0
func TestDates(t *testing.T) {
	defer leaktest.AfterTest(t)

	// From https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
	locationNames := []string{
		"Canada/Newfoundland", // half-hour zone
		"Europe/London",       // same as UTC, except for DST
		"Pacific/Kiritimati",  // maximum positive offset
		"Pacific/Midway",      // maximum negative offset
		"US/Pacific",          // negative offset
		"UTC",
	}

	for _, locationName := range locationNames {
		loc, err := time.LoadLocation(locationName)
		if err != nil {
			t.Error(err)
			continue
		}

		s, db := setup(t, loc)
		defer cleanup(s, db)

		var date *driver.Date
		for _, year := range []int{
			1200, // distant past
			2020, // present day, for DST rules
			4000, // distant future
		} {
			for _, month := range []time.Month{
				time.December, // winter
				time.August,   // summer
			} {
				for hour := 0; hour < 24; hour++ {
					timestamp := time.Date(year, month, 20, hour, 34, 45, 123, loc)

					if err := db.QueryRow("SELECT $1::DATE", timestamp).Scan(&date); err != nil {
						t.Fatal(err)
					}

					if expected := driver.MakeDate(timestamp); *date != expected {
						t.Fatalf("expected date to be truncated to:\n%s\nbut got:\n%s", expected, date)
					}
				}
			}
		}
	}
}
Пример #3
0
func TestPlaceholders(t *testing.T) {
	defer leaktest.AfterTest(t)

	// loc is selected so that timeVal below maps to a different date in
	// loc and UTC.
	loc, err := time.LoadLocation("Pacific/Midway")
	if err != nil {
		t.Fatal(err)
	}

	s, db := setup(t, loc)
	defer cleanup(s, db)

	year, month, day := 3015, time.August, 30
	timeVal := time.Date(year, month, day, 3, 34, 45, 345670000, loc)
	dateVal := driver.MakeDate(time.Date(year, month, day, 0, 0, 0, 0, time.UTC))
	intervalVal, err := time.ParseDuration("34h2s")
	if err != nil {
		t.Fatal(err)
	}

	if result, err := db.Exec(`CREATE DATABASE t`); err != nil {
		t.Fatal(err)
	} else if _, err := result.LastInsertId(); !testutils.IsError(err, "no LastInsertId available after DDL statement") {
		t.Error(err)
	} else if _, err := result.RowsAffected(); !testutils.IsError(err, "no RowsAffected available after DDL statement") {
		t.Error(err)
	}

	schema := `
CREATE TABLE t.alltypes (
  a BIGINT PRIMARY KEY,
  b FLOAT,
  c TEXT,
  d BYTES,
  e BOOLEAN,
  f TIMESTAMP,
  g DATE,
  h INTERVAL
)
`
	if result, err := db.Exec(schema); err != nil {
		t.Fatal(err)
	} else if _, err := result.LastInsertId(); !testutils.IsError(err, "no LastInsertId available after DDL statement") {
		t.Error(err)
	} else if _, err := result.RowsAffected(); !testutils.IsError(err, "no RowsAffected available after DDL statement") {
		t.Error(err)
	}

	var (
		a int64
		b sql.NullFloat64
		c sql.NullString
		d sql.NullString
		e sql.NullBool
		f *time.Time
		g *driver.Date
		h *time.Duration
	)

	if rows, err := db.Query("SELECT * FROM t.alltypes"); err != nil {
		t.Fatal(err)
	} else {
		defer rows.Close()

		cols, err := rows.Columns()
		if err != nil {
			t.Fatal(err)
		}

		if expected := []string{"a", "b", "c", "d", "e", "f", "g", "h"}; !reflect.DeepEqual(cols, expected) {
			t.Errorf("got unexpected columns:\n%s\nexpected:\n%s", cols, expected)
		}
	}

	// Insert values for all the different types.
	if result, err := db.Exec(`INSERT INTO t.alltypes VALUES ($1, $2, $3, $4, $5, $6, $6::DATE, $7::INTERVAL)`,
		123, 3.4, "blah", []byte("foo"), true, timeVal, intervalVal); err != nil {
		t.Fatal(err)
	} else if got, err := result.RowsAffected(); err != nil {
		t.Fatal(err)
	} else if e := int64(1); got != e {
		t.Fatalf("expected %d rows affected, got %d", e, a)
	}
	// Insert a row with NULL values
	if result, err := db.Exec(`INSERT INTO t.alltypes VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
		456, nil, nil, nil, nil, nil, nil, nil); err != nil {
		t.Fatal(err)
	} else if got, err := result.RowsAffected(); err != nil {
		t.Fatal(err)
	} else if e := int64(1); got != e {
		t.Fatalf("expected %d rows affected, got %d", e, a)
	}
	if _, err := db.Query("SELECT a, b FROM t.alltypes WHERE a IN ($1)", 123); err != nil {
		t.Fatal(err)
	}
	if _, err := db.Query("SELECT a, b FROM t.alltypes WHERE b IN ($1)", 3.4); err != nil {
		t.Fatal(err)
	}
	if _, err := db.Query("SELECT a, b FROM t.alltypes WHERE c IN ($1)", "blah"); err != nil {
		t.Fatal(err)
	}
	if _, err := db.Query("SELECT a, b FROM t.alltypes WHERE d IN ($1)", []byte("foo")); err != nil {
		t.Fatal(err)
	}
	if _, err := db.Query("SELECT a, b FROM t.alltypes WHERE e IN ($1)", true); err != nil {
		t.Fatal(err)
	}
	if _, err := db.Query("SELECT a, b FROM t.alltypes WHERE f IN ($1)", timeVal); err != nil {
		t.Fatal(err)
	}
	if _, err := db.Query("SELECT a, b FROM t.alltypes WHERE g IN ($1::DATE)", timeVal); err != nil {
		t.Fatal(err)
	}
	if _, err := db.Query("SELECT a, b FROM t.alltypes WHERE h IN ($1::INTERVAL)", intervalVal); err != nil {
		t.Fatal(err)
	}
	if rows, err := db.Query("SELECT * FROM t.alltypes"); err != nil {
		t.Fatal(err)
	} else {
		defer rows.Close()

		rows.Next()
		if err := rows.Scan(&a, &b, &c, &d, &e, &f, &g, &h); err != nil {
			t.Fatal(err)
		}

		if err := rows.Err(); err != nil {
			t.Fatal(err)
		}

		if !(a == 123 && b.Float64 == 3.4 && c.String == "blah" && d.String == "foo" &&
			e.Bool && f.Equal(timeVal) && *g == dateVal && *h == intervalVal) {
			t.Errorf(
				"expected:\n%+v\ngot:\n%+v",
				[]interface{}{123, 3.4, "blah", "foo", true, timeVal, dateVal, intervalVal},
				[]interface{}{a, b, c, d, e, f, g, h},
			)
		}

		rows.Next()
		if err := rows.Scan(&a, &b, &c, &d, &e, &f, &g, &h); err != nil {
			t.Fatal(err)
		}

		if err := rows.Err(); err != nil {
			t.Fatal(err)
		}

		if !(a == 456 && !b.Valid && !c.Valid && !d.Valid && !e.Valid && f == nil && g == nil && h == nil) {
			t.Errorf(
				"expected:\n%+v\ngot:\n%+v",
				[]interface{}{123, "<NOT NULL>", "<NOT NULL>", "<NOT NULL>", "<NOT NULL>", "<NULL>", "<NULL>", "<NULL>"},
				[]interface{}{a, b, c, d, e, f, g, h},
			)
		}

		if rows.Next() {
			t.Error("expected rows to be complete")
		}
	}
	// Delete a row using a placeholder param.
	if result, err := db.Exec(`DELETE FROM t.alltypes WHERE a IN ($1)`, 123); err != nil {
		t.Fatal(err)
	} else if got, err := result.RowsAffected(); err != nil {
		t.Fatal(err)
	} else if e := int64(1); got != e {
		t.Fatalf("expected %d rows affected, got %d", e, a)
	}
	if rows, err := db.Query("SELECT * FROM t.alltypes"); err != nil {
		t.Fatal(err)
	} else {
		defer rows.Close()

		rows.Next()
		if err := rows.Scan(&a, &b, &c, &d, &e, &f, &g, &h); err != nil {
			t.Fatal(err)
		}

		if err := rows.Err(); err != nil {
			t.Fatal(err)
		}

		if !(a == 456 && !b.Valid && !c.Valid && !d.Valid && !e.Valid && f == nil && g == nil && h == nil) {
			t.Errorf(
				"expected:\n%+v\ngot:\n%+v",
				[]interface{}{123, "<NOT NULL>", "<NOT NULL>", "<NOT NULL>", "<NOT NULL>", "<NULL>", "<NULL>", "<NULL>"},
				[]interface{}{a, b, c, d, e, f, g, h},
			)
		}

		if rows.Next() {
			t.Error("expected rows to be complete")
		}
	}
}